31. From Python to pygame — Homework solutions

To run any of these, open a terminal in the solutions folder and run python with the file name. The window opens; close it with the X button.

Problem 1 — Different window size

Problem. Open a 1024x768 window with the caption "Big Window".

How to think about it. Only two lines change from the minimal program: the tuple in set_mode and the string in set_caption.

Worked solution.

import pygame

pygame.init()
screen = pygame.display.set_mode((1024, 768))
pygame.display.set_caption("Big Window")
clock = pygame.time.Clock()

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    screen.fill((0, 0, 0))
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Common mistakes.

  • Writing set_mode(1024, 768) without the inner tuple. set_mode takes one argument — a (width, height) tuple — not two separate numbers.

Problem 2 — Background colour

Problem. Fill the background with a colour that is not black.

How to think about it. screen.fill takes an (R, G, B) tuple. Each component ranges from 0 to 255. Experiment until you find a colour you like.

Worked solution (dark navy background):

import pygame

pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Coloured Background")
clock = pygame.time.Clock()

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    screen.fill((30, 30, 80))   # dark navy
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Some colours to try: (200, 100, 50) burnt orange, (0, 128, 0) green, (128, 0, 128) purple.

Common mistakes.

  • Passing three separate arguments: screen.fill(30, 30, 80). The argument must be one tuple.

Problem 3 — Two fills

Problem. Call screen.fill twice (red, then blue) before flip(). Observe the result and explain it in a comment.

How to think about it. screen.fill overwrites the entire canvas. The second call overwrites what the first call painted. Only the second colour is visible when flip() shows the frame.

Worked solution.

import pygame

pygame.init()
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("Two Fills")
clock = pygame.time.Clock()

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    screen.fill((255, 0, 0))   # paint red...
    screen.fill((0, 0, 255))   # ...then overwrite with blue
    # Result: the window is blue.
    # The red fill is never shown because flip() has not been called yet.
    # The second fill replaces every pixel the first fill set.
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Key idea. Drawing functions write to an off-screen buffer. Nothing the player sees changes until flip() is called. Because both fills happen before flip(), only the final state of the buffer — blue — is shown.

Challenge — Shrinking window

Problem. Start 500x500. Each spacebar press shrinks the window by 50 in each dimension, minimum 100x100.

How to think about it. Store the current size in variables. On K_SPACE, subtract 50 from both, clamp to 100, then call pygame.display.set_mode again with the new size.

Worked solution.

import pygame

pygame.init()
width = 500
height = 500
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Shrinking Window")
clock = pygame.time.Clock()

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                width = max(100, width - 50)
                height = max(100, height - 50)
                screen = pygame.display.set_mode((width, height))

    screen.fill((50, 50, 50))
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

max(100, width - 50) prevents the size from going below 100. The return value of set_mode is a new Surface for the new size, so reassigning screen keeps the variable pointing to the right canvas.

Common mistakes.

  • Not reassigning screen. After set_mode, the old screen Surface is no longer valid. Always use the return value.
  • Using pygame.KEYUP instead of pygame.KEYDOWN. KEYDOWN fires once when the key is pressed; KEYUP fires once when released. Either works here, but KEYDOWN is the natural choice for a one-shot action.

Done?

Chapter 32 covers drawing shapes and colours on the screen inside the game loop.