pygame-core
Structure a pygame (pygame-ce) game in Python: the init/event/update/draw loop, delta-time movement, Surface/Rect blitting, keyboard/mouse input, and Sprite/Group management with collision. Use when building or debugging a pygame game — when the user mentions pygame, pygame-ce, the game loop, blit, Surface, Rect, sprite groups, or clock.tick. Targets pygame-ce.
Resumen
pygame Core
Build the foundation of a pygame game in Python: the main loop, delta-time movement, drawing with Surface/Rect, input, and Sprite/Group management. Targets pygame-ce 2.5.8 (the actively maintained community fork; same import pygame).
When to use
- Use when starting a pygame game, fixing the loop, frame-rate-dependent speed, input handling, blitting, or sprite/group collision.
- Use when code does
import pygameand the project depends onpygame-ce(orpygame).
When not to use: Python language questions unrelated to pygame. 3D rendering (pygame is 2D). For cross-engine save/load use save-systems; for rebindable input architecture see input-systems.
Core workflow
- Install pygame-ce, not legacy pygame.
pip install pygame-ce— it's the maintained fork and imports aspygame. Don't install both in one environment. - Init and open a window.
pygame.init(),screen = pygame.display.set_mode((w, h)),clock = pygame.time.Clock(). - Run one loop: events → update → draw → flip. Pump the event queue every frame (
for event in pygame.event.get()), update state, redraw, thenpygame.display.flip(). - Make it frame-rate independent. Get
dt = clock.tick(60) / 1000(seconds) and scale all motion bydt. Keep positions as floats; blit at integer rects. - Handle input two ways: event-based (
KEYDOWN/MOUSEBUTTONDOWN, for discrete actions) and polled (pygame.key.get_pressed(), for held movement). - Organise objects with
Sprite+Group. Subclasspygame.sprite.Spritewithimage/rect;group.update(dt)andgroup.draw(screen)handle the batch. Run it and watch the window before assuming it works.
Patterns
1. Minimal game loop (the skeleton)
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("My Game")
clock = pygame.time.Clock()
running = True
while running:
dt = clock.tick(60) / 1000 # cap at 60 FPS; dt = seconds since last frame
for event in pygame.event.get(): # MUST drain the queue or the OS thinks it hung
if event.type == pygame.QUIT:
running = False
# update game state here, scaled by dt ...
screen.fill((18, 18, 28)) # clear each frame
# draw everything here ...
pygame.display.flip() # present the frame
pygame.quit()2. Delta-time movement (frame-rate independent)
from pygame.math import Vector2
pos = Vector2(100, 100) # keep position as floats
speed = 220 # PIXELS PER SECOND, not per frame
# inside the loop, after computing dt:
keys = pygame.key.get_pressed()
direction = Vector2(
keys[pygame.K_RIGHT] - keys[pygame.K_LEFT],
keys[pygame.K_DOWN] - keys[pygame.K_UP],
)
if direction.length_squared() > 0:
direction = direction.normalize() # equal speed on diagonals
pos += direction * speed * dt # RIGHT: dt-scaled
screen.blit(player_img, (round(pos.x), round(pos.y))) # blit at integer pixels3. Input: events vs polling
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN: # discrete press: jump, menu, pause
if event.key == pygame.K_SPACE:
jump()
elif event.key == pygame.K_ESCAPE:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
shoot_at(event.pos) # event.pos = (x, y)
# Polled state (read once per frame) for continuous/held input:
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
move_left(dt)4. A Sprite subclass + a Group
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
# convert() once at load makes blits much faster; _alpha keeps transparency.
self.image = pygame.image.load("player.png").convert_alpha()
self.rect = self.image.get_rect(center=(x, y))
self.pos = pygame.math.Vector2(self.rect.center)
self.speed = 240
def update(self, dt): # Group.update(dt) calls this per sprite
keys = pygame.key.get_pressed()
self.pos.x += (keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]) * self.speed * dt
self.rect.center = (round(self.pos.x), round(self.pos.y))
all_sprites = pygame.sprite.Group()
all_sprites.add(Player(400, 300))
# in the loop:
all_sprites.update(dt) # calls each sprite's update(dt)
all_sprites.draw(screen) # blits each sprite at its rect5. Collision detection
# Sprite vs group: e.g. player picking up coins (True = remove collided coins).
collected = pygame.sprite.spritecollide(player, coins, dokill=True)
score += len(collected)
# Group vs group: bullets vs enemies (kill both on hit).
hits = pygame.sprite.groupcollide(bullets, enemies, True, True)
# Plain rect overlap (no sprites needed):
if player.rect.colliderect(door_rect):
open_door()Pitfalls
- Window freezes / "not responding" → you didn't pump the event queue. Call
pygame.event.get()(orpygame.event.pump()) every frame. - Speed differs on faster machines → you moved by a fixed amount per frame. Scale by
dt = clock.tick(fps) / 1000and use pixels-per-second values. - Sub-pixel movement snaps/jitters →
rectcoordinates are integers; store the true position as aVector2of floats and assignrect.center = round(...)each frame. - Blits are slow / framerate drops → call
.convert()(opaque) or.convert_alpha()(transparent) on loaded images once; un-converted surfaces blit far slower. - Nothing appears → you forgot
pygame.display.flip()(orupdate()), or you drew beforescreen.fill(...)so it was cleared away. - Wrong draw order → pygame uses painter's order; later blits cover earlier ones. Draw background first, sprites last.
pip install pygamegot the old one → for the maintained fork usepip install pygame-ce; having both installed causes import conflicts.- Diagonal movement is faster → normalise the direction vector before scaling by speed.
References
- For
Groupvariants (GroupSingle,LayeredUpdatesfor z-order), pixel-perfect collision withmask, slicing a spritesheet, simple animation, sound/music, and text rendering, readreferences/sprites-and-collision.md.
Related skills
love2d-core— the same loop concepts in LÖVE/Lua.bevy-ecs— a heavier ECS engine when a project outgrows pygame.input-systems/save-systems— engine-agnostic input and persistence.platformer/roguelike— genre templates that pair with pygame.
Archivos 2 archivos
Instálala a mano
Deska ejecuta esto por ti, para cada agente que elijas. Para ejecutarlo tú en una terminal:
npx skills add gamedev-skills/awesome-gamedev-agent-skills --skill pygame-coreMás de gamedev-skills
- game-feelgamedev-skillsAdd "juice" and game feel that makes actions satisfying — screen shake, hit-stop/freeze frames, tweened/eased motion, squash & stretch, knockback, and layered audio-visual feedback — as engine-neutral techniques that pair with the detected engine's tween, particle, and camera APIs. Use when the user mentions game feel, juice, "make it feel good/punchy", screen shake, hit stop, screen freeze, easing, squash and stretch, impact frames, or feedback/polish on hits, jumps, pickups, and deaths.5,900 instalaciones en skills.sh0
- game-ui-uxgamedev-skillsDesign and build game UI/UX — HUDs, menus, and overlays — that survive every screen: anchor- based responsive layout, resolution/aspect scaling and safe areas, keyboard/gamepad focus navigation, a screen/menu state stack, and event-driven (not polled) HUD updates. Engine- neutral patterns that pair with the detected engine's UI skill. Use when the user mentions HUD, health bar, main menu, pause menu, settings screen, UI layout, anchors, UI scaling, aspect ratio, safe area, controller/keyboard menu navigation, or wiring UI to game state.5,900 instalaciones en skills.sh0
- level-designgamedev-skillsDesign and build playable levels — the blockout/whitebox-to-playable workflow, player metrics and grid layout, pacing and flow (tension/rest curve), gating and the critical path, and encounter design. Engine-neutral practice. Use when the user mentions level design, blockout/whitebox/greybox, level layout, level pacing, encounter design, or the critical path through a level.4,700 instalaciones en skills.sh0
- game-aigamedev-skillsDesign NPC and enemy decision-making with finite state machines, behavior trees, steering behaviors, and A* pathfinding — engine-neutral algorithms that pair with the detected engine's navigation API. Use when building enemy AI, an FSM or behavior tree, steering/flocking, or pathfinding, or when the user mentions state machine, behavior tree, blackboard, A*, navmesh, seek, or patrol/chase.4,500 instalaciones en skills.sh0
- audio-designgamedev-skillsImplement game audio practice — bus/mixer architecture and gain in decibels, ducking (sidechain), adaptive/dynamic music via layering and re-sequencing, SFX variation, and beat synchronization. Engine-neutral. Use when the user mentions audio mixing, audio buses, adaptive/dynamic music, ducking, SFX variation, music layers, or syncing gameplay to the beat.4,400 instalaciones en skills.sh0