Lists of things: spawning, timers and randomness
Pygame fundamentals · Lesson 6 of 7
Most games have many of something: keep them in a list, add new ones on a timer and drop the ones you no longer need.
A list, a timer and random
Each falling block is a Rect in the list blocks. Every frame moves and draws all of them with one for loop.
spawn_timer counts frames. When it reaches spawn_every, a new block appears at a random place along the top (random.randint) and the timer starts again. Lowering spawn_every as the score grows makes the blocks come faster.
Removing things safely
Blocks that have fallen off the screen must go, or the list grows forever and the game slows down. Removing items from a list while a for loop walks through it skips items, so build a new list of the ones to keep instead:
blocks = [b for b in blocks if b.top < 320]
import random import pygame pygame.init() screen = pygame.display.set_mode((480, 320)) clock = pygame.time.Clock() font = pygame.font.Font(None, 30) player = pygame.Rect(220, 280, 36, 24) blocks = [] spawn_timer = 0 score = 0 alive = True running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE and not alive: blocks, score, alive = [], 0, True if alive: keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: player.x -= 6 if keys[pygame.K_RIGHT]: player.x += 6 player.clamp_ip(screen.get_rect()) spawn_every = max(8, 30 - score // 100) # faster as you survive spawn_timer += 1 if spawn_timer >= spawn_every: spawn_timer = 0 size = random.randint(16, 40) blocks.append(pygame.Rect(random.randint(0, 480 - size), -size, size, size)) for block in blocks: block.y += 4 if block.colliderect(player): alive = False blocks = [b for b in blocks if b.top < 320] # keep the ones still on screen score += 1 screen.fill((16, 18, 22)) for block in blocks: pygame.draw.rect(screen, (235, 95, 85), block, border_radius=4) pygame.draw.rect(screen, (255, 212, 59), player, border_radius=6) screen.blit(font.render(f"Score {score} Blocks {len(blocks)}", True, (230, 232, 235)), (12, 10)) if not alive: text = font.render("Hit! Press Space to try again", True, (255, 212, 59)) screen.blit(text, text.get_rect(center=(240, 160))) pygame.display.flip() clock.tick(60) pygame.quit()
Things with more than a position
When each thing needs more than a Rect, such as its own speed or colour, store a dictionary per thing: {"rect": rect, "speed": 5}. When things also need their own behaviour, it is time for classes, which the next lesson covers.
Your turn
Change the programs above in the game panel, then press Run.
- Give each block its own speed: store dictionaries with a
"speed"from 2 to 6. - Add coins (yellow circles) that also fall: catching one adds 100 points.
- Show the best score of the session next to the score.
Space Shooter keeps invaders, bullets, bombs and sparks in lists. Open Space Shooter.