Cosmic Candy Pinball: procedural 8-bit pinball game

Native pygame-ce game with fully procedural pixel art and chiptune
audio (no asset files). Pure-logic physics module with flipper angular
momentum, plus headless autoplay/screenshot/probe dev tools.
This commit is contained in:
georgios
2026-09-09 16:18:39 +02:00
commit db49b466c2
25 changed files with 2330 additions and 0 deletions
+90
View File
@@ -0,0 +1,90 @@
# 🍬 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.