Code of the Day
BeginnerGame Concepts

Moving things

Implement the full game loop and use it to animate a rectangle across the screen by updating its position each frame.

Game DevBeginner10 min read
By the end of this lesson you will be able to:
  • Implement a complete game loop with input, update, and render phases
  • Draw a rectangle on screen using pygame.draw.rect
  • Update a position variable each frame to produce smooth motion
  • Enforce a frame rate with pygame.time.Clock

The game loop is not a concept you understand by reading — you understand it by writing one. This lesson adds the missing pieces: the while loop, the clock, position state, and drawing. By the end, a rectangle will move steadily across the screen because you update its position every frame.

Position is state. The rectangle has an x and a y. Each pass through the loop you change x by a small amount. The render step draws the rectangle at the new position. At 60 frames per second, that sequence of tiny nudges looks like smooth motion.

The complete loop

Pyodide (the in-browser Python runner) does not support pygame's display system. Read through this code carefully, then run it locally: pip install pygame followed by python moving.py.

import pygame
import sys

pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Moving rectangle")

clock = pygame.time.Clock()   # used to cap the frame rate

# --- State ---
x = 0          # horizontal position of the rectangle
y = 200        # fixed vertical position
speed = 3      # pixels moved per frame
WIDTH, HEIGHT = 50, 50

running = True
while running:
    # Phase 1 — process input
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    # Phase 2 — update state
    x += speed
    if x > 640:          # wrap around when the rectangle leaves the screen
        x = -WIDTH

    # Phase 3 — render
    screen.fill((20, 20, 30))                        # erase last frame
    pygame.draw.rect(screen, (80, 180, 255), (x, y, WIDTH, HEIGHT))
    pygame.display.flip()                            # push frame to screen

    clock.tick(60)   # cap at 60 FPS; pause if we're running too fast

pygame.quit()
sys.exit()

What each part does

pygame.time.Clock() creates a timer object. Its tick(60) call at the end of each loop iteration enforces a 60-FPS ceiling. Without it, the loop runs as fast as the CPU allows — hundreds of iterations per second — and the rectangle flies off screen instantly. tick(60) returns the milliseconds since the last call, which you can store for delta-time calculations later.

x += speed is the entire update for this example. Position is just a number. Movement is just arithmetic on that number. Everything fancier in a real game — gravity, friction, bouncing — is still arithmetic on position and velocity variables.

if x > 640: x = -WIDTH wraps the rectangle. When the left edge of the rectangle passes the right edge of the screen, it resets to just off the left edge. The -WIDTH offset makes it slide in smoothly rather than popping.

screen.fill((20, 20, 30)) paints the entire background each frame. This is the erase step. Skip it and you get a smear — every previous position of the rectangle drawn on top of each other.

pygame.draw.rect(screen, colour, (x, y, width, height)) draws a filled rectangle. The four-element tuple is the rectangle's position and dimensions. Colour is again an (R, G, B) tuple.

Notice that the render phase reads state but never changes it. The update phase changes state but never draws. Keeping these two responsibilities separate makes it easy to add new behaviour without creating subtle bugs.

Where to go next

Next: state in games — a broader look at what game state is, why it all lives in variables, and how the screen is just a rendering of that state.

Finished reading? Mark it complete to track your progress.

On this page