95 lines
3.6 KiB
Markdown
95 lines
3.6 KiB
Markdown
# 🍬 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.
|
||
|
||

|
||
|
||
## 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.
|