Platformer

Python pygame Physics Tilemaps Camera Logic Coyote Time
← Back to Games
pygame

This game runs as a desktop app

This platformer relies on pygame for real-time collision detection, gravity physics, dynamic camera scrolling, and array-based level loading. Run it locally to experience the smooth jumping mechanics and multiple levels.

How to run it locally

01Install pygame: pip install pygame
02Download platformer.py from the GitHub repo below
03Run it: python platformer.py
04Arrow keys or A/D to move, Space to jump, R to restart
platformer.py — logic highlights GitHub ↗
""" PROJECT 9: Platformer ====================== Concepts: physics (gravity, jumping), tilemaps, camera/scrolling, enemy AI, collectibles, multiple levels, organized code structure """ import pygame # ── Player Physics & Coyote Time ────────────────────────────────────────────── class Player(pygame.sprite.Sprite): def jump(self): # Allow jumping if grounded OR if within the coyote time grace period if self.on_ground or self.coyote > 0: self.vel_y = JUMP_FORCE self.on_ground = False self.coyote = 0 def update(self, keys, tiles): # Gravity self.vel_y += GRAVITY if self.vel_y > 20: self.vel_y = 20 # terminal velocity # Move & collide vertically was_on_ground = self.on_ground self.on_ground = False self.rect.y += int(self.vel_y) for tile in pygame.sprite.spritecollide(self, tiles, False): if self.vel_y > 0: self.rect.bottom = tile.rect.top self.on_ground = True self.vel_y = 0 elif self.vel_y < 0: self.rect.top = tile.rect.bottom self.vel_y = 0 # Coyote time: keep a grace window after walking off an edge if was_on_ground and not self.on_ground: self.coyote = COYOTE_FRAMES elif self.coyote > 0: self.coyote -= 1 # ── Dynamic Camera Scrolling ────────────────────────────────────────────────── class Camera: def __init__(self, level_width, level_height): self.offset_x = 0 self.offset_y = 0 self.lw = level_width self.lh = level_height def update(self, target): # Center on player self.offset_x = target.rect.centerx - WIDTH // 2 self.offset_y = target.rect.centery - HEIGHT // 2 # Clamp so we don't show outside the level boundaries self.offset_x = max(0, min(self.offset_x, self.lw - WIDTH)) self.offset_y = max(0, min(self.offset_y, self.lh - HEIGHT)) def apply(self, rect): return rect.move(-self.offset_x, -self.offset_y)
TilemapsString array parsing
PhysicsGravity & Velocity
CameraViewport offset
Game FeelCoyote time
State MgmtLevel transitions
CollectiblesSprite collisions