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!

Similar Posts