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
Every pygame and Python word in the game, with a tiny example each. Big ideas, in small words.
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
Wakes up all of pygame's parts (fonts, sound, the keyboard). Call it once, right after import pygame.
import pygame pygame.init()
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))
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))
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()
Sets the title shown along the top of the window.
pygame.display.set_caption("Pixel Garden")
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))
Shuts pygame down and closes the window. It goes at the very end, after the game loop has finished.
while running: ... pygame.quit()
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")
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
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)
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)
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)])
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)
Draws an oval that fits inside a rectangle (x, y, width, height).
pygame.draw.ellipse(screen, "plum", (100, 80, 120, 60))
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
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()
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 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
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)
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)
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
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
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")
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)
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()
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)
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)
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="-")
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
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
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
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)
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!")
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!")
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())
Makes a font. None means pygame's built-in font, and the number is its size.
font = pygame.font.Font(None, 32)
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))
Put an f before the quotes and you can drop values straight into the text with { }.
score = 5 text = f"Score: {score}" # "Score: 5"
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
x += 4 is short for x = x + 4. There's also -=, *= and /=.
score += 1 x -= 4
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
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
The two booleans. Variables holding them remember whether something is so: running, eaten, jumping.
running = True eaten = False
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"
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
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))
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)
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))
Repeats a block as long as a condition stays True. The game loop is a while loop.
running = True while running: ...
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)
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)
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])
.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)
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
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)
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)
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 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
Anything after # is a note for humans. Python skips it.
vy += 0.5 # gravity