Files

95 lines
3.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🍬 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
**portrait** `360×480` virtual canvas — like a proper pinball machine —
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.
- The kawaii cat helper reacts to your shots from 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
- **Portrait table**: a `360×480` playfield like a real pinball machine,
with regular-sized flippers (about a quarter of the playfield width each)
at the bottom and a wide centre drain between them.
- **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**: soft triangle/sine voices -> PCM at startup; pitched bumper pops
that climb with your combo, plus two real melodies (a slow *Twinkle Twinkle*
lullaby on the title, a bouncier version during play — no square-wave or
noise percussion in the music).
Licence: MIT — go wild.