# 🍬 Cosmic Candy Pinball A cute, 8-bit, pixel-art **pinball** game, written from scratch in Python with [pygame-ce](https://pygame.org). 100% procedural β€” there are **no image or audio asset files**: every sprite, texture, particle, chiptune and sound effect is generated by code at runtime. Not web-based: it opens its own native window and renders on a low-res `480Γ—360` virtual canvas, upscaled with crisp nearest-neighbour scaling for an authentic retro look. ![demo](shots/3_play.png) ## Running it Fastest (uv, already used in this project): ```bash uv venv .venv --python 3.12 # once uv pip install --python .venv/bin/python -r requirements.txt # once .venv/bin/python main.py ``` Or with plain venv + pip (Python 3.10+): ```bash python3 -m venv .venv .venv/bin/pip install -r requirements.txt .venv/bin/python main.py ``` > Note: the dependency is **`pygame-ce`**, not `pygame` (the community edition > supports newer Python versions and is what this was built against). ## Controls | Key | Action | | --- | --- | | `←` `β†’` (or `Z` / `/`) | Flippers | | hold `Space` / `↑` | Charge the **Candy Cannon** β€” release to fire | | `M` | Mute | | `P` | Pause | | `R` | Restart game | | `Esc` | Quit | | `Enter` | Start / play again | ## How to play - Light the **3 star lanes** up top β†’ **CANDY FEVER!** (double points for 20s β€” keep hitting stars to extend it). - Bounce off the three kawaii candy bumpers and the two slingshots. Every hit inside 2.5s builds your **combo multiplier** (up to Γ—9). - Watch the bottom-centre drain and the two outlanes… or lose the ball. - Every **50,000 points** earns an extra ball. - Squirrel says encouraging things. Blush at the cat in the corner. ## Project layout | file | purpose | | --- | --- | | `main.py` | entry point / main loop | | `game.py` | game states, scoring, juice, all rendering (pixel art) | | `physics.py` | pure pinball physics (flippers, bumpers, slingshots, drains) β€” no rendering | | `font.py` | hand-made 5Γ—5 pixel bitmap font | | `sfx.py` | procedural chiptune + music synthesis (pure code, no samples) | | `highscore.json` | best score (written at game over) | Dev / test tools (run headless, no window needed): ```bash .venv/bin/python autotest.py 40000 # auto-playing bot, prints game-health stats .venv/bin/python runtest.py 900 # simulated session incl. rendering .venv/bin/python shots.py shots # dumps screenshots of every state .venv/bin/python probe.py # pixel-probes the rendered layout ``` ## Design notes - **Physics**: fixed 60 Hz logic with up to 6 collision substeps so the ball never tunnels; kinematic flippers whose angular velocity is transferred to the ball (real "scoop" feel); inward-tilting floor funnels; centre drain + guarded outlanes; a softlock rescue nudge if a ball ever parks too long. - **Fun tuning was data-driven**: an `autotest.py` bot plays thousands of frames and reports hit/drain rates per table element, so bumper, slingshot and flipper geometry was tuned against measured behaviour, not guesswork. - **Audio**: square/triangle/noise oscillators -> PCM at startup; distinct pitched bump sounds that climb with your combo, plus two generative music loops (menu + play). Licence: MIT β€” go wild.