Game Dev Lab — Day 1

Pygame Basics: Moving Ship

# INSTRUCTOR — Game Dev Lab Day 1: Pygame Foundations
# -------------------------------------------------------
# TEACH: This student already knows Python well. Skip syntax review.
# The goal today is to get them into pygame fast and have something moving.
#
# KEY DIFFERENCES from turtle:
#   - pygame uses a pixel coordinate system: (0,0) is TOP-LEFT, y increases downward
#   - No global event loop — YOU write the while loop and call pygame.event.get() yourself
#   - Drawing is done each frame: clear screen, draw everything, flip (show)
#   - Keyboard uses pygame.key.get_pressed() for smooth held-key movement
#
# MILESTONE (show me when done):
#   Ship moves left/right with arrow keys — smooth, no jitter
#   Space fires a bullet that flies upward off screen
#
# EXTENSION challenges (when milestone is done):
#   - Wrap ship so going off right edge appears on left
#   - Limit max 3 bullets on screen at once
#   - Add a speed variable and let Up/Down arrow change it

import pygame
import sys

# ── Setup ───────────────────────────────────────────────────────────────────
pygame.init()

WIDTH, HEIGHT = 600, 700
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Space Shooter — Day 1")

clock = pygame.time.Clock()  # TEACH: clock.tick(FPS) keeps the game at a fixed speed

BLACK  = (0,   0,   0)
WHITE  = (255, 255, 255)
CYAN   = (0,   220, 220)
YELLOW = (255, 255, 0)

# ── Ship ────────────────────────────────────────────────────────────────────
# TEACH: We store game objects as dicts for now. Day 3 converts these to classes.
ship = {
    'x': WIDTH // 2,
    'y': HEIGHT - 60,
    'width': 40,
    'height': 30,
    'speed': 5,
}

# ── Bullets ─────────────────────────────────────────────────────────────────
bullets = []   # each bullet: {'x': ..., 'y': ..., 'speed': ...}

def fire_bullet():
    bullets.append({'x': ship['x'], 'y': ship['y'] - ship['height'], 'speed': 8})

# ── Draw helpers ─────────────────────────────────────────────────────────────
def draw_ship(s):
    # Triangle pointing up: three points
    cx = s['x']
    top    = (cx,             s['y'] - s['height'])
    left   = (cx - s['width'] // 2, s['y'])
    right  = (cx + s['width'] // 2, s['y'])
    pygame.draw.polygon(screen, CYAN, [top, left, right])

def draw_bullet(b):
    pygame.draw.ellipse(screen, YELLOW,
                        (b['x'] - 4, b['y'] - 10, 8, 18))

# ── Game loop ────────────────────────────────────────────────────────────────
# TEACH: every frame does exactly four things in order:
#   1. Handle events (quit, key presses)
#   2. Update state (move ship, move bullets)
#   3. Draw everything
#   4. Flip (show the new frame)

while True:
    # 1. Events
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                fire_bullet()

    # 2. Update
    keys = pygame.key.get_pressed()   # TEACH: held keys — much smoother than KEYDOWN
    if keys[pygame.K_LEFT] and ship['x'] > ship['width'] // 2:
        ship['x'] -= ship['speed']
    if keys[pygame.K_RIGHT] and ship['x'] < WIDTH - ship['width'] // 2:
        ship['x'] += ship['speed']

    # Move bullets upward; remove when off screen
    for b in bullets[:]:              # TEACH: iterate a copy when removing during loop
        b['y'] -= b['speed']
        if b['y'] < 0:
            bullets.remove(b)

    # 3. Draw
    screen.fill(BLACK)
    draw_ship(ship)
    for b in bullets:
        draw_bullet(b)

    # 4. Flip
    pygame.display.flip()
    clock.tick(60)   # TEACH: 60 frames per second cap