Spec Sheet — Flappy Bird (Python Pygame Edition)
Project File: flappy_bird.py
Platform: Pygame Window
Must Have: Gravity, Flap, Pipes, Collisions, Score, Restart
Goal
Build a Flappy Bird–style game where the player controls a bird that “flaps” upward and must fly through gaps between moving pipes.
Requirements
Window / Display
- Window size: 400 x 600 (or similar)
- Title: “Flappy Bird”
- Background color: simple solid color is fine
Bird
- Bird is a rectangle or circle (no images required)
- Gravity pulls bird down each frame
- Press SPACE to flap upward (set upward velocity)
Pipes
- Pipes spawn on the right and move left
- Each pipe set has a top and bottom pipe with a gap
- Gap size is constant (example: 170 px)
- Pipes recycle after leaving the screen
Collision
- Bird hits a pipe → Game Over
- Bird hits the ground or top of screen → Game Over
Scoring
- Score increases by 1 when the bird passes a pipe set
- Score is displayed on screen
Game Over / Restart
- Show “GAME OVER” message
- Press R to restart (reset bird, pipes, and score)
Controls
- SPACE = flap
- R = restart (after game over)
- ESC or window close = quit
Install pygame: run
pip install pygame before running this project.
Pseudocode
START
SET up pygame
CREATE game window and clock
DEFINE constants (gravity, flap strength, pipe speed, gap size)
FUNCTION reset_game():
set score = 0
set game_over = false
create bird rectangle at starting position
set bird velocity = 0
create list of pipes (several pipe sets spaced out)
FUNCTION create_pipe(x_position):
randomize top pipe height
create top pipe rect
create bottom pipe rect (top height + gap)
mark pipe as not yet scored
return pipe set
CALL reset_game()
WHILE program running:
handle events:
if quit -> exit
if SPACE and not game_over -> flap (set velocity upward)
if R and game_over -> reset_game()
if ESC -> exit
IF not game_over:
apply gravity to bird velocity
move bird vertically
move pipes left
if pipe leaves screen -> recycle it to right with new random gap
check collisions:
if bird hits pipe OR bird hits ground/top -> game_over
update score:
if bird passes pipe center and not scored -> score++
draw background
draw pipes
draw bird
draw score
if game_over -> draw "GAME OVER" and restart instructions
update display and tick clock (FPS)
END
Rubric (100 Points)
| Category | Excellent (Full Credit) | Points |
|---|---|---|
| Program Runs / Setup | Runs with pygame, clean window loop | 10 |
| Bird Physics (Gravity + Flap) | Gravity works; flap gives upward velocity | 15 |
| Pipes Spawn & Move | Pipes move left; gap exists; multiple pipe sets | 15 |
| Pipe Recycling | Pipes reset after leaving screen | 10 |
| Collision Detection | Pipe + ground/top collisions end game | 15 |
| Scoring | Score increments when passing pipes; shown on screen | 15 |
| Game Over Screen | Shows message clearly | 5 |
| Restart Feature | Press R resets game correctly | 10 |
| Code Quality | Good organization, names, comments | 5 |
| Total | 100 |
Actual Python Code — flappy_bird.py
"""
File: flappy_bird.py
Flappy Bird (Simple Pygame Version)
Controls:
- SPACE: flap
- R: restart after game over
- ESC: quit
"""
import pygame
import random
import sys
# ----------------------------
# CONFIG
# ----------------------------
WIDTH, HEIGHT = 400, 600
FPS = 60
GRAVITY = 0.45
FLAP_STRENGTH = -8.5
PIPE_WIDTH = 70
PIPE_GAP = 170
PIPE_SPEED = 3.2
PIPE_SPACING = 220 # distance between pipe sets
GROUND_HEIGHT = 60
class PipeSet:
"""
Stores a top pipe rect, bottom pipe rect, and whether it has been scored.
"""
def __init__(self, x):
self.x = x
self.scored = False
self.randomize()
def randomize(self):
# top pipe height min/max (leave room for gap and ground)
min_top = 60
max_top = HEIGHT - GROUND_HEIGHT - PIPE_GAP - 60
top_h = random.randint(min_top, max_top)
self.top = pygame.Rect(self.x, 0, PIPE_WIDTH, top_h)
self.bottom = pygame.Rect(self.x, top_h + PIPE_GAP, PIPE_WIDTH,
HEIGHT - GROUND_HEIGHT - (top_h + PIPE_GAP))
def move(self):
self.top.x -= PIPE_SPEED
self.bottom.x -= PIPE_SPEED
def recycle_if_needed(self, new_x):
# If pipe is completely off-screen to the left, move it to new_x and randomize
if self.top.right < 0:
self.x = new_x
self.scored = False
self.randomize()
self.top.x = self.x
self.bottom.x = self.x
def draw_text(screen, text, size, x, y, center=True):
font = pygame.font.SysFont("Arial", size, bold=True)
surf = font.render(text, True, (255, 255, 255))
rect = surf.get_rect()
if center:
rect.center = (x, y)
else:
rect.topleft = (x, y)
screen.blit(surf, rect)
def reset_game():
# Bird as a rectangle
bird = pygame.Rect(90, HEIGHT // 2 - 20, 34, 24)
bird_vel = 0.0
# Create pipes
pipes = []
start_x = WIDTH + 120
for i in range(3):
pipes.append(PipeSet(start_x + i * PIPE_SPACING))
score = 0
game_over = False
return bird, bird_vel, pipes, score, game_over
def main():
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Flappy Bird")
clock = pygame.time.Clock()
bird, bird_vel, pipes, score, game_over = reset_game()
running = True
while running:
clock.tick(FPS)
# ----------------------------
# EVENTS
# ----------------------------
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
if not game_over and event.key == pygame.K_SPACE:
bird_vel = FLAP_STRENGTH
if game_over and event.key == pygame.K_r:
bird, bird_vel, pipes, score, game_over = reset_game()
# ----------------------------
# UPDATE
# ----------------------------
if not game_over:
# Apply gravity and move bird
bird_vel += GRAVITY
bird.y += int(bird_vel)
# Bird collisions with top/bottom (ground)
if bird.top <= 0:
game_over = True
if bird.bottom >= HEIGHT - GROUND_HEIGHT:
game_over = True
# Move pipes
for p in pipes:
p.move()
# Recycle pipes
rightmost_x = max(p.top.x for p in pipes)
for p in pipes:
p.recycle_if_needed(rightmost_x + PIPE_SPACING)
# Collision detection + scoring
for p in pipes:
if bird.colliderect(p.top) or bird.colliderect(p.bottom):
game_over = True
# Score when bird passes pipe set (once per set)
if not p.scored and bird.left > p.top.right:
p.scored = True
score += 1
# ----------------------------
# DRAW
# ----------------------------
screen.fill((15, 25, 45)) # background
# Draw ground
pygame.draw.rect(screen, (30, 80, 30), (0, HEIGHT - GROUND_HEIGHT, WIDTH, GROUND_HEIGHT))
# Draw pipes
for p in pipes:
pygame.draw.rect(screen, (0, 200, 0), p.top)
pygame.draw.rect(screen, (0, 200, 0), p.bottom)
# Draw bird
pygame.draw.rect(screen, (255, 210, 0), bird)
# Draw score
draw_text(screen, f"Score: {score}", 26, WIDTH // 2, 40)
# Game over overlay
if game_over:
draw_text(screen, "GAME OVER", 48, WIDTH // 2, HEIGHT // 2 - 40)
draw_text(screen, "Press R to Restart", 24, WIDTH // 2, HEIGHT // 2 + 20)
draw_text(screen, "ESC to Quit", 20, WIDTH // 2, HEIGHT // 2 + 55)
pygame.display.flip()
pygame.quit()
sys.exit()
if __name__ == "__main__":
main()
Run it: Save as
flappy_bird.py, install pygame with
pip install pygame, then run python flappy_bird.py.