Create a Platformer Game with Python and Pygame
Platformer games are one of the most beloved video game genres, going back to classics like Super Mario Bros. and Sonic the Hedgehog. These 2D action games challenge players to run, jump, and battle enemies across side-scrolling levels. While modern platformers boast realistic physics and dazzling 3D graphics, at their core these games are quite simple—which makes them a great project for beginner game developers!
In this guide, we‘ll create a complete platformer game from scratch using Python and Pygame. We‘ll build our game step-by-step, beginning with basic player movement before progressing to animations, collectibles, hazards, and multiple levels. By the end, you‘ll have a fully-playable game you can share with others! Let‘s jump in.
Setting Up the Development Environment
To code our platformer, we‘ll be using Python 3 and the Pygame library. Pygame is a popular Python package for making 2D games, providing helpful modules for graphics, sound, input handling, and more.
First, make sure you have Python 3.x installed. Open a terminal and run:
python3 --version
If you don‘t have Python 3 installed, download it from python.org. Next, install Pygame using pip:
python3 -m pip install -U pygame
With that, we‘re ready to start coding!
Creating the Game Window
Let‘s begin by displaying a basic 800×600 game window:
import pygame
# Initialize pygame
pygame.init()
# Set up the game window
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption(‘Pixel Platformer‘)
running = True
while running:
# Handle events
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Fill the screen with a background color
screen.fill((147, 210, 220))
# Update the display
pygame.display.update()
pygame.quit()
This code initializes Pygame, creates an 800×600 pixel window, sets a background color, and starts the game loop. The for event in pygame.event.get()
loop handles window events like closing the game.
When you run this script, you should see a blank window with a light blue background. We have our foundation—now we need a character to control!
Making a Player Sprite
In a platformer, the player character is represented by a sprite—a 2D graphic we can move around the screen. For our player sprite, we‘ll use a simple 32×32 pixel art character:
(Feel free to use this sprite or create/find your own.)
Let‘s create a Player
class to encapsulate our character‘s data and behavior:
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
# Load the sprite sheet image
self.sprite_sheet = pygame.image.load(‘player.png‘).convert()
# Create a surface for the player image and set its rect attribute
self.image = self.get_image(0, 0)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def get_image(self, x, y):
"""Extracts image from sprite sheet"""
image = pygame.Surface([32, 32])
image.blit(self.sprite_sheet, (0, 0), (x, y, 32, 32))
image.set_colorkey((0, 0, 0)) # Transparent black background
return image
def update(self):
"""Update the player"""
pass
The Player
class extends pygame.sprite.Sprite
, giving it special sprite properties. The constructor loads the sprite sheet image, extracts the first frame into its own 32×32 surface, and positions that image at the specified x,y coordinates.
The get_image
method pulls a sprite from the sheet at the given x,y pixel positions. This will come in handy for animations later.
To show the player on screen, create an instance of Player
and add it to a sprite group in the main game code:
player = Player(100, 300)
all_sprites = pygame.sprite.Group(player)
running = True
while running:
# Handle events
# ...
# Update sprites
all_sprites.update()
# Draw
screen.fill((147, 210, 220))
all_sprites.draw(screen)
pygame.display.update()
Run it and you should see the player sprite show up!
Player Movement and Physics
Now for the fun part—making the player move and jump around the level! We‘ll add basic platform physics so the sprite has weight and momentum.
First, set up variables for the player‘s movement speed and acceleration due to gravity:
GRAVITY = 1
PLAYER_SPEED = 5
Modify the Player
class to track its velocity and accept keyboard input:
class Player(pygame.sprite.Sprite):
# ...
def __init__(self, x, y):
# ...
self.vel_x = 0
self.vel_y = 0
self.on_ground = False
def update(self):
"""Updates the player‘s position"""
# Apply gravity
self.vel_y += GRAVITY
# Move left/right
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.vel_x = -PLAYER_SPEED
elif keys[pygame.K_RIGHT]:
self.vel_x = PLAYER_SPEED
else:
self.vel_x = 0
# Jump if on the ground
if keys[pygame.K_UP] and self.on_ground:
self.vel_y = -20
# Update position
self.rect.x += self.vel_x
self.rect.y += self.vel_y
# Check if fallen off bottom of screen
if self.rect.top > WINDOW_HEIGHT:
self.kill()
When the player holds the left or right arrow keys, it applies the PLAYER_SPEED
velocity in that direction. Pressing the up arrow key while on the ground triggers a jump by setting a large negative Y velocity. Meanwhile, GRAVITY
constantly pulls the player downward.
The on_ground
flag will track when the player is touching a platform so we know when to allow jumps. We‘ll implement platforms and collision next.
For now, test out the player physics! It should run left and right, fall with gravity, and jump on command. It‘s starting to feel like a real platformer!
Platforms and Collision Detection
A platformer isn‘t much fun without platforms to jump between. Pygame makes it easy to create platforms using sprites.
First define a Platform
class:
class Platform(pygame.sprite.Sprite):
def __init__(self, x, y, width, height):
super().__init__()
self.image = pygame.Surface([width, height])
self.image.fill((255, 0, 0))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
Each platform has a position and size, with a red colored surface for its image.
Now let‘s place some platforms in the level:
all_sprites = pygame.sprite.Group()
platforms = pygame.sprite.Group()
# Create platforms
p1 = Platform(300, 550, 200, 60)
p2 = Platform(80, 400, 100, 30)
p3 = Platform(500, 300, 150, 30)
all_sprites.add(p1, p2, p3)
platforms.add(p1, p2, p3)
If you run the game now, you‘ll see the red platforms—but the player falls right through them. We need to implement collision detection between the player and the platforms.
Pygame provides handy collision detection functions out-of-the-box. Modify the Player.update
method to check for platform collisions:
def update(self):
# ...
# Check for collisions with platforms
hits = pygame.sprite.spritecollide(self, platforms, False)
if hits:
self.on_ground = True
self.vel_y = 0
self.rect.bottom = hits[0].rect.top
else:
self.on_ground = False
# Wrap player around the screen
if self.rect.left < 0:
self.rect.left = 0
elif self.rect.right > WINDOW_WIDTH:
self.rect.right = WINDOW_WIDTH
The pygame.sprite.spritecollide
function checks if the player is overlapping with any platforms. If so, we set on_ground
to True
, zero out the Y velocity, and snap the player‘s bottom to the top of the platform.
If there are no collisions, we set on_ground
to False
to prevent the player from jumping in mid-air.
Finally, the code at the end wraps the player around the edges of the screen to prevent it from running off the sides.
Test it out—we have a playable mini platformer! The player sprite can now run and jump between platforms with reliable physics.
Adding Enemies and Hazards
To give our platformer some challenge, let‘s add hazards the player must avoid. We‘ll create deadly spikes that defeat the player on contact.
Define a Spike
sprite class:
class Spike(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.image.load(‘spike.png‘).convert_alpha()
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
Here I‘m using a simple 16×16 spike sprite:
Place some spikes around the level near platforms:
spikes = pygame.sprite.Group()
s1 = Spike(350, 530)
s2 = Spike(100, 380)
all_sprites.add(s1, s2)
spikes.add(s1, s2)
To handle the player hitting a spike, check for collisions in the update loop:
spike_hits = pygame.sprite.spritecollide(player, spikes, False)
if spike_hits:
player.kill()
running = False
If the player overlaps with any spikes, it instantly ends the game. You could implement lives or a health system—but for now instant death will suffice!
Watch your step around those spikes. They‘re merciless!
Winning, Losing, and Reset
Let‘s add some a goal for the player and win/lose conditions.
We‘ll create a Goal
sprite that loads the level when touched:
class Goal(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.image.load(‘goal.png‘)
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
Place a goal at the right edge of the level:
goal = Goal(700, 510)
all_sprites.add(goal)
Test for the player reaching the goal in the update loop:
goal_hit = pygame.sprite.collide_rect(player, goal)
if goal_hit:
level_complete = True
running = False
When the player touches the goal, we set level_complete
to True
and end the game loop.
Lastly, let‘s display winning and losing messages to the player. Create font objects for the text:
font = pygame.font.SysFont(None, 48)
win_text = font.render("Level Complete!", True, (255, 255, 255))
lose_text = font.render("Game Over!", True, (255, 255, 255))
Draw the appropriate message after the game loop ends:
if level_complete:
screen.blit(win_text, (WINDOW_WIDTH//2 - win_text.get_width()//2,
WINDOW_HEIGHT//2 - win_text.get_height()//2))
else:
screen.blit(lose_text, (WINDOW_WIDTH//2 - lose_text.get_width()//2,
WINDOW_HEIGHT//2 - lose_text.get_height()//2))
pygame.display.update()
pygame.time.wait(3000)
The winning or losing text appears centered on the screen for 3 seconds before the game closes. Voila! Our platformer is complete with objectives, hazards, and feedback.
Next Steps
Congrats, you‘ve built a basic platformer in Python using Pygame! Feel proud of your accomplishment. This is no small feat!
Where you go from here is up to you. You can expand this simple demo into a full-fledged game! Some ideas:
- Add more levels, challenges, and enemies
- Implement a main menu, pause screen, and level end screen
- Create collectibles like coins or power-ups
- Give the player a health bar and lives
- Replace the placeholder art with your own sprites and backgrounds
- Compose a soundtrack and sound effects
I encourage you to use this platformer as a foundation to build upon. Make it your own! With more time and polish, you could develop it into something special.
I hope this guide has sparked your excitement for game development. Python and Pygame provide a surprisingly powerful and beginner-friendly way to make 2D action games. The techniques you‘ve learned here—sprites, physics, collision, animation—apply to all sorts of game projects.
Remember, every pro developer starts as a beginner. Keep practicing your skills, learning new concepts, and most importantly—have fun! Game development is an amazing blend of art and code. Unleash your creativity and see what you can build!