Stay Alive!
Dodge & Collect
Gems rain down, so do bombs. Grab the good, dodge the bad, chase a high score. You will master lists of moving objects, spawn timers, and difficulty curves.
Gems rain down, so do bombs. Grab the good, dodge the bad, chase a high score. You will master lists of moving objects, spawn timers, and difficulty curves.
import pygameimport pygame, pygame.init()pygame.init(), the window and the while runningwhile running game loop. If you're starting here or need that template, grab it in one click: Episode 1 full template โ ยท Python Cheatsheet โStandard setup with a player that runs along the bottom of the screen.
player = pygame.Rect(380, 430, 40, 40)
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.x -= 8
if keys[pygame.K_RIGHT]:
player.x += 8
player.x = max(0, min(800 - player.width, player.x))player = pygame.Rect(380, 430, 40, 40)
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.x -= 8
if keys[pygame.K_RIGHT]:
player.x += 8
player.x = max(0, min(800 - player.width, player.x))
Build a frame-counting timer that spawns falling gems into a list.
import random
things = []
spawn_timer = 0
# inside the loop:
spawn_timer += 1
if spawn_timer >= 40:
spawn_timer = 0
things.append({
"rect": pygame.Rect(random.randint(10, 766), -24, 24, 24),
"kind": "gem"
})
for t in things[:]:
t["rect"].y += 5
if t["rect"].y > 480:
things.remove(t)import random
things = []
spawn_timer = 0
# inside the loop:
spawn_timer += 1
if spawn_timer >= 40:
spawn_timer = 0
things.append({
"rect": pygame.Rect(random.randint(10, 766), -24, 24, 24),
"kind": "gem"
})
for t in things[:]:
t["rect"].y += 5
if t["rect"].y > 480:
things.remove(t)
spawn_timer += 1
if spawn_timer >= spawn_timer += 1
if spawn_timer >= :
spawn_timer = :
spawn_timer =
things.
things.({"rect": pygame.Rect(random.randint(10, 766), -24, 24, 24), "kind": "gem"})({"rect": pygame.Rect(random.randint(10, 766), -24, 24, 24), "kind": "gem"})
Mix hazards into the spawn using weighted randomness.
kind = "bomb" if random.random() < 0.25 else "gem"
things.append({
"rect": pygame.Rect(random.randint(10, 766), -24, 24, 24),
"kind": kind
})
# drawing:
for t in things:
colour = (248, 113, 113) if t["kind"] == "bomb" else (77, 217, 224)
pygame.draw.ellipse(screen, colour, t["rect"])kind = "bomb" if random.random() < 0.25 else "gem"
things.append({
"rect": pygame.Rect(random.randint(10, 766), -24, 24, 24),
"kind": kind
})
# drawing:
for t in things:
colour = (248, 113, 113) if t["kind"] == "bomb" else (77, 217, 224)
pygame.draw.ellipse(screen, colour, t["rect"])
Handle both collision outcomes and show score + lives.
score, lives = 0, 3
for t in things[:]:
if player.colliderect(t["rect"]):
if t["kind"] == "gem":
score += 1
else:
lives -= 1
things.remove(t)score, lives = 0, 3
for t in things[:]:
if player.colliderect(t["rect"]):
if t["kind"] == "gem":
score += 1
else:
lives -= 1
things.remove(t)
if player.colliderect(t["rect"]):
if t["kind"] == if player.colliderect(t["rect"]):
if t["kind"] == :
score += 1
else:
lives -= :
score += 1
else:
lives -=
things.
things.(t)(t)
Scale three difficulty knobs with score so the game always ends.
fall_speed = 5 + score // 10
spawn_at = max(12, 40 - score // 2)
bomb_chance = min(0.5, 0.25 + score * 0.005)
if spawn_timer >= spawn_at:
...
kind = "bomb" if random.random() < bomb_chance else "gem"fall_speed = 5 + score // 10
spawn_at = max(12, 40 - score // 2)
bomb_chance = min(0.5, 0.25 + score * 0.005)
if spawn_timer >= spawn_at:
...
kind = "bomb" if random.random() < bomb_chance else "gem"
End the game cleanly and save the high score to disk so it survives restarts.
def load_highscore():
try:
with open("highscore.txt") as f:
return int(f.read())
except:
return 0
def save_highscore(value):
with open("highscore.txt", "w") as f:
f.write(str(value))
high = load_highscore()
# when the game ends:
if score > high:
high = score
save_highscore(high)def load_highscore():
try:
with open("highscore.txt") as f:
return int(f.read())
except:
return 0
def save_highscore(value):
with open("highscore.txt", "w") as f:
f.write(str(value))
high = load_highscore()
# when the game ends:
if score > high:
high = score
save_highscore(high)
if score > if score > :
high = score
:
high = score
(high)(high)
A runner, a spawn timer, falling gems and bombs, gem-scores-bomb-costs-a-life collisions, a difficulty curve that scales with score, and a high score saved to highscore.txthighscore.txt , one file. Save it as game.pygame.py, run python game.pypython game.py, and play. Stuck on a step? Compare your file against this.
import pygame, random
pygame.init()
screen = pygame.display.set_mode((800, 480))
pygame.display.set_caption("Gem Dash")
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 32)
big_font = pygame.font.SysFont(None, 72)
def load_highscore():
try:
with open("highscore.txt") as f:
return int(f.read())
except:
return 0
def save_highscore(value):
with open("highscore.txt", "w") as f:
f.write(str(value))
player = pygame.Rect(380, 430, 40, 40)
things = []
spawn_timer = 0
score = 0
lives = 3
game_over = False
high = load_highscore()
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_r and game_over:
things = []
spawn_timer = 0
score = 0
lives = 3
game_over = False
if not game_over:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.x -= 8
if keys[pygame.K_RIGHT]:
player.x += 8
player.x = max(0, min(800 - player.width, player.x))
# difficulty scales with score
fall_speed = 5 + score // 10
spawn_at = max(12, 40 - score // 2)
bomb_chance = min(0.5, 0.25 + score * 0.005)
spawn_timer += 1
if spawn_timer >= spawn_at:
spawn_timer = 0
kind = "bomb" if random.random() < bomb_chance else "gem"
things.append({"rect": pygame.Rect(random.randint(10, 766), -24, 24, 24), "kind": kind})
for t in things[:]:
t["rect"].y += fall_speed
if player.colliderect(t["rect"]):
if t["kind"] == "gem":
score += 1
else:
lives -= 1
things.remove(t)
elif t["rect"].y > 480:
things.remove(t)
if lives <= 0:
game_over = True
if score > high:
high = score
save_highscore(high)
# draw
screen.fill((25, 30, 60))
pygame.draw.rect(screen, (45, 212, 191), player)
for t in things:
colour = (248, 113, 113) if t["kind"] == "bomb" else (77, 217, 224)
pygame.draw.ellipse(screen, colour, t["rect"])
screen.blit(font.render("Score: " + str(score), True, (255, 255, 255)), (12, 12))
screen.blit(font.render("Best: " + str(high), True, (255, 255, 255)), (12, 44))
screen.blit(font.render("Lives: " + str(max(0, lives)), True, (248, 113, 113)), (680, 12))
if game_over:
msg = big_font.render("GAME OVER", True, (255, 209, 102))
screen.blit(msg, (210, 190))
screen.blit(font.render("Press R to restart", True, (255, 255, 255)), (300, 270))
pygame.display.flip()
clock.tick(60)
pygame.quit()import pygame, random
pygame.init()
screen = pygame.display.set_mode((800, 480))
pygame.display.set_caption("Gem Dash")
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 32)
big_font = pygame.font.SysFont(None, 72)
def load_highscore():
try:
with open("highscore.txt") as f:
return int(f.read())
except:
return 0
def save_highscore(value):
with open("highscore.txt", "w") as f:
f.write(str(value))
player = pygame.Rect(380, 430, 40, 40)
things = []
spawn_timer = 0
score = 0
lives = 3
game_over = False
high = load_highscore()
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_r and game_over:
things = []
spawn_timer = 0
score = 0
lives = 3
game_over = False
if not game_over:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.x -= 8
if keys[pygame.K_RIGHT]:
player.x += 8
player.x = max(0, min(800 - player.width, player.x))
# difficulty scales with score
fall_speed = 5 + score // 10
spawn_at = max(12, 40 - score // 2)
bomb_chance = min(0.5, 0.25 + score * 0.005)
spawn_timer += 1
if spawn_timer >= spawn_at:
spawn_timer = 0
kind = "bomb" if random.random() < bomb_chance else "gem"
things.append({"rect": pygame.Rect(random.randint(10, 766), -24, 24, 24), "kind": kind})
for t in things[:]:
t["rect"].y += fall_speed
if player.colliderect(t["rect"]):
if t["kind"] == "gem":
score += 1
else:
lives -= 1
things.remove(t)
elif t["rect"].y > 480:
things.remove(t)
if lives <= 0:
game_over = True
if score > high:
high = score
save_highscore(high)
# draw
screen.fill((25, 30, 60))
pygame.draw.rect(screen, (45, 212, 191), player)
for t in things:
colour = (248, 113, 113) if t["kind"] == "bomb" else (77, 217, 224)
pygame.draw.ellipse(screen, colour, t["rect"])
screen.blit(font.render("Score: " + str(score), True, (255, 255, 255)), (12, 12))
screen.blit(font.render("Best: " + str(high), True, (255, 255, 255)), (12, 44))
screen.blit(font.render("Lives: " + str(max(0, lives)), True, (248, 113, 113)), (680, 12))
if game_over:
msg = big_font.render("GAME OVER", True, (255, 209, 102))
screen.blit(msg, (210, 190))
screen.blit(font.render("Press R to restart", True, (255, 255, 255)), (300, 270))
pygame.display.flip()
clock.tick(60)
pygame.quit()