georgios cf2c0e4558 Portrait 360x480 table with regular-sized flippers
Rotate the playfield to portrait like a real pinball machine:
- canvas 480x360 landscape -> 360x480 portrait; playfield 308px wide,
  ~390px tall, with HUD, title/game-over screens and HUD re-laid out
  for the narrow format (score/best top row, balls/stars/fever below)
- flippers reduced to a regular ~quarter-width size (82px) pivoting at
  the lower corners, tips meeting over a wide centre drain
- table elements re-placed for the taller field: 3 star lanes up top,
  candy bumpers mid-field, slingshots and floor-level outlane guard
  posts at the bottom; data-checked with the autoplay bot (~350 bumper
  hits / 30k frames, centre+side drains, no stuck balls)
- probes & autoplay policy updated for the portrait geometry; all 13
  pixel-probes pass
2026-09-09 19:02:11 +02:00

🍬 Cosmic Candy Pinball

A cute, 8-bit, pixel-art pinball game, written from scratch in Python with pygame-ce. 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

Running it

Fastest (uv, already used in this project):

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+):

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):

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

S
Description
No description provided
Readme
157 KiB
Languages
Python 100%