A LITTLE CLARITY

Your pygame handbook.

Every pygame and Python word in the game, with a tiny example each. Big ideas, in small words.

import pygame

Loads the pygame library so you can use it. Everything pygame has is reached with a dot: pygame.display, pygame.draw, pygame.Rect...

import pygame
The window

pygame.init()

Wakes up all of pygame's parts (fonts, sound, the keyboard). Call it once, right after import pygame.

import pygame

pygame.init()
The window

pygame.display.set_mode()

Opens the window. Give it a tuple (width, height) in pixels. It gives back the screen: a Surface you draw on.

screen = pygame.display.set_mode((320, 240))
The window

screen.fill()

Paints the whole surface one color. In a game loop, fill first, every frame: it wipes away last frame's picture.

screen.fill("skyblue")
screen.fill((40, 120, 80))
The window

pygame.display.flip()

Shows everything you drew. pygame draws on a hidden copy of the screen, and flip() swaps it into view in one go, so you never see half-drawn pictures. pygame.display.update() does the same.

screen.fill("black")
pygame.draw.circle(screen, "gold", (160, 120), 30)
pygame.display.flip()
The window

pygame.display.set_caption()

Sets the title shown along the top of the window.

pygame.display.set_caption("Pixel Garden")
The window

Surfaces

A Surface is a picture you can draw on. The screen is one, every loaded image is one, and rendered text is one. You can draw shapes on any of them and blit them onto each other.

badge = pygame.Surface((40, 40))
badge.fill("gold")
screen.blit(badge, (10, 10))
The window

pygame.quit()

Shuts pygame down and closes the window. It goes at the very end, after the game loop has finished.

while running:
    ...
pygame.quit()
The window

Colors: (r, g, b) and names

A color is a tuple of three numbers from 0 to 255: how much red, green and blue light to mix. pygame also knows hundreds of names, like "coral", "skyblue" and "forestgreen".

white = (255, 255, 255)
black = (0, 0, 0)
garden = (40, 120, 80)
screen.fill("coral")
Colors and coordinates

Coordinates: (x, y)

Positions are (x, y) in pixels from the top-left corner, which is (0, 0). x grows to the right and y grows down. In a 320×240 window the bottom-right pixel is (319, 239).

pygame.draw.circle(screen, "white", (0, 0), 10)     # top-left
pygame.draw.circle(screen, "white", (320, 240), 10) # bottom-right
Colors and coordinates

pygame.draw.rect()

Draws a rectangle: (x, y, width, height), where (x, y) is the top-left corner. Add a number at the end to draw only the outline, that thick.

pygame.draw.rect(screen, "forestgreen", (0, 180, 320, 60))
pygame.draw.rect(screen, "white", (10, 10, 50, 30), 2)
Drawing

pygame.draw.circle()

Draws a circle around a center point with a radius. Add a number at the end for just the outline.

pygame.draw.circle(screen, "gold", (270, 50), 30)
pygame.draw.circle(screen, "gold", (250, 60), 14, 2)
Drawing

pygame.draw.polygon()

Joins a list of points into a filled shape. Three points make a triangle.

pygame.draw.polygon(screen, "firebrick", [(100, 120), (160, 70), (220, 120)])
Drawing

pygame.draw.line()

Draws a straight line from one point to another. The last number is how thick it is.

pygame.draw.line(screen, "white", (0, 0), (320, 240), 3)
Drawing

pygame.draw.ellipse()

Draws an oval that fits inside a rectangle (x, y, width, height).

pygame.draw.ellipse(screen, "plum", (100, 80, 120, 60))
Drawing

Drawing order

Later drawings go on top of earlier ones, like paint. Draw the sky first, then the ground, then the things standing on it.

screen.fill("skyblue")                            # back
pygame.draw.rect(screen, "green", (0, 180, 320, 60))
pygame.draw.circle(screen, "coral", (160, 170), 15)  # front
Drawing

The game loop

Every game is a while loop that runs again and again: handle events, update the world, draw it, flip. Each time round is one frame.

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    x += 2                      # update
    screen.fill("black")        # draw
    pygame.draw.circle(screen, "gold", (x, 120), 10)
    pygame.display.flip()       # show
    clock.tick(30)
pygame.quit()
The game loop

pygame.event.get()

Gives you a list of everything that happened since last time: keys pressed, mouse clicks, the window closing. Loop over it every frame. Each event has a .type.

for event in pygame.event.get():
    if event.type == pygame.QUIT:
        running = False
The game loop

pygame.QUIT

The event you get when the player closes the window. Your loop should stop when it arrives, or the game keeps running with no window.

if event.type == pygame.QUIT:
    running = False
The game loop

pygame.time.Clock() and tick()

clock.tick(30) waits just long enough that your loop runs 30 frames per second, so the game runs at the same speed on every computer. Make one clock before the loop and tick it once per frame.

clock = pygame.time.Clock()
while running:
    ...
    clock.tick(30)
The game loop

Moving things

To move something, keep its position in a variable and change it a little every frame. The amount it changes per frame is its speed.

x = 20
speed = 4
while running:
    x += speed
    ...
    pygame.draw.circle(screen, "coral", (x, 120), 15)
Movement

Bouncing

To bounce, flip the speed when the thing reaches an edge: speed = -speed turns 5 into -5 and back again.

if x > 305 or x < 15:
    speed = -speed
Movement

Gravity

Gravity changes the speed, and the speed changes the position. Add a little to the downward speed vy every frame. A jump is just a negative vy.

vy += 0.5   # gravity
y += vy
if y > 200:
    y = 200
    vy = -vy * 0.8   # bounce, losing a little energy
Movement

pygame.image.load()

Loads a picture from a file and gives back a Surface. In Pixel Garden you can load "noodle.png" and "snack.png".

noodle = pygame.image.load("noodle.png")
Images and Rects

screen.blit()

Copies one Surface onto another. (x, y) is where its top-left corner goes. You can also give it a Rect.

screen.blit(noodle, (140, 104))
screen.blit(noodle, noodle_rect)
Images and Rects

.convert_alpha()

Makes a loaded picture faster to draw, and keeps its see-through parts. Real games do this right after loading.

noodle = pygame.image.load("noodle.png").convert_alpha()
Images and Rects

Rect

A Rect is a position and a size: pygame.Rect(x, y, width, height). It has handy attributes you can read and change: x, y, width, height, center, centerx, topleft, right, bottom... Move it by changing them.

box = pygame.Rect(10, 20, 40, 30)
box.x += 5
box.center = (160, 120)
print(box.right)
Images and Rects

.get_rect()

Gives you a Rect the size of a Surface. Place it while you're at it: get_rect(center=(160, 120)) or get_rect(topleft=(20, 110)).

rect = noodle.get_rect(center=(160, 120))
screen.blit(noodle, rect)
Images and Rects

Keyword arguments

Some arguments are given by name: name=value. It makes the call easy to read and lets you skip the ones you don't need.

noodle.get_rect(center=(160, 120))
print("a", "b", sep="-")
Images and Rects

pygame.key.get_pressed()

Tells you which keys are held down right now. Use it for things that keep happening while a key is down, like walking.

keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT]:
    x += 4
Keyboard and mouse

pygame.KEYDOWN and event.key

A KEYDOWN event arrives once when a key goes down. event.key says which key. Use it for things that happen once per press, like jumping or shooting.

for event in pygame.event.get():
    if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
        vy = -9
Keyboard and mouse

Key names: pygame.K_...

Every key has a name: pygame.K_LEFT, pygame.K_RIGHT, pygame.K_UP, pygame.K_DOWN, pygame.K_SPACE, pygame.K_RETURN, and letters like pygame.K_a.

if keys[pygame.K_LEFT]:
    x -= 4
if keys[pygame.K_a]:
    x -= 4
Keyboard and mouse

pygame.MOUSEBUTTONDOWN and event.pos

A MOUSEBUTTONDOWN event arrives when the player clicks. event.pos is where, as (x, y). pygame.mouse.get_pos() gives the mouse's position at any time.

if event.type == pygame.MOUSEBUTTONDOWN:
    print("click at", event.pos)
Keyboard and mouse

.colliderect()

a.colliderect(b) is True when two Rects overlap. It's the heart of almost every 2D game: eating, getting hit, landing on platforms.

if noodle_rect.colliderect(snack_rect):
    print("Yum!")
Collisions

.collidepoint()

rect.collidepoint(point) is True when a point is inside the Rect. Perfect for mouse clicks and buttons.

if button.collidepoint(event.pos):
    print("clicked!")
Collisions

.clamp_ip()

Pushes a Rect back inside another one. _ip means in place: it changes the Rect itself. screen.get_rect() is a Rect the size of the window.

noodle_rect.clamp_ip(screen.get_rect())
Collisions

pygame.font.Font()

Makes a font. None means pygame's built-in font, and the number is its size.

font = pygame.font.Font(None, 32)
Text

font.render()

Turns words into a Surface: font.render(text, True, color). True smooths the edges. Then blit it like any picture.

text = font.render("Score: 5", True, "white")
screen.blit(text, (10, 10))
Text

f-strings

Put an f before the quotes and you can drop values straight into the text with { }.

score = 5
text = f"Score: {score}"   # "Score: 5"
Text

Variables

A variable is a name for a value. = stores the value on the right under the name on the left. Change it any time.

x = 20
speed = 4
x = x + speed
Python basics

+= and -=

x += 4 is short for x = x + 4. There's also -=, *= and /=.

score += 1
x -= 4
Python basics

+, -, *, /, //, %

Maths: + - * /. // divides and rounds down, % is the remainder: 7 % 2 is 1. % 2 is great for every-other patterns.

x = 14 + i * 40
if frame % 10 == 0:
    score += 1
Python basics

==, !=, <, >, <=, >=

Comparisons give back True or False. == means "is equal to" (one = stores a value, two compare).

if x > 305:
    speed = -speed
if event.type == pygame.QUIT:
    running = False
Python basics

True and False

The two booleans. Variables holding them remember whether something is so: running, eaten, jumping.

running = True
eaten = False
Python basics

if, elif and else

if runs its block only when the condition is True. elif checks another condition, and else catches everything left.

if (row + col) % 2 == 0:
    color = "seagreen"
else:
    color = "honeydew"
Python basics

and, or, not

and needs both sides True, or needs at least one, and not flips True and False.

if x > 305 or x < 15:
    speed = -speed
if touching and not eaten:
    eaten = True
Python basics

for loops

Repeats a block once for every item in a sequence. The loop variable takes each value in turn.

for i in range(8):
    pygame.draw.rect(screen, "brown", (14 + i * 40, 140, 12, 60))
Python basics

range()

range(8) counts 0, 1, 2 ... 7. range(30, 320, 50) counts from 30 up to 320 in steps of 50.

for x in range(30, 320, 50):
    tree(x)
Python basics

Nested loops

A loop inside a loop: the inner one runs completely for each round of the outer one. Perfect for grids.

for row in range(6):
    for col in range(8):
        pygame.draw.rect(screen, "white", (col * 40, row * 40, 38, 38))
Python basics

while loops

Repeats a block as long as a condition stays True. The game loop is a while loop.

running = True
while running:
    ...
Python basics

def

def makes your own function: a named recipe. Parameters are the blanks you fill in each time you call it.

def tree(x):
    pygame.draw.rect(screen, "saddlebrown", (x - 5, 150, 10, 45))
    pygame.draw.circle(screen, "seagreen", (x, 140), 25)

tree(60)
tree(160)
Python basics

Lists

A list keeps many values in order: ["red", "orange", "yellow"]. Games keep their snacks, enemies and stars in lists.

colors = ["red", "orange", "yellow"]
for color in colors:
    print(color)
Python basics

Indexing: list[i]

colors[0] is the first item, colors[1] the second. The position can be a variable, like a loop's i.

colors = ["red", "orange", "yellow"]
print(colors[0])   # red
print(colors[i])
Python basics

.append() and .remove()

.append(item) adds an item to the end of a list, and .remove(item) takes it out.

snacks.append(new_snack)
snacks.remove(eaten_snack)
Python basics

Tuples

A tuple is a fixed little group of values in round brackets. pygame uses them everywhere: (x, y) positions, (r, g, b) colors, (width, height) sizes.

size = (320, 240)
position = (160, 120)
x, y = position
Python basics

None

None means "nothing here". In pygame.font.Font(None, 32) it says: no font file, use the built-in one.

font = pygame.font.Font(None, 32)
Python basics

print()

Writes a line under the game, so you can see what your code is doing. Great for finding bugs.

print("Yum!")
print("score is", score)
Python basics

int()

Turns a value into a whole number (dropping anything after the point). Handy for pixel positions: int(12.7) is 12.

y = 12.7
pygame.draw.circle(screen, "coral", (160, int(y)), 15)
Python basics

Indentation

Python uses indentation (4 spaces) to group lines into blocks: everything indented under while, if, for or def belongs to it.

while running:
    x += 1          # inside the loop
    if x > 300:
        x = 0       # inside the if
pygame.quit()       # after the loop
Python basics

Comments

Anything after # is a note for humans. Python skips it.

vy += 0.5   # gravity
Python basics