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
92 lines
2.1 KiB
Python
92 lines
2.1 KiB
Python
"""Render screenshots of key game states (headless) so we can inspect art.
|
|
|
|
Usage: python shots.py [outdir]
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
|
|
os.environ.setdefault("SDL_VIDEODRIVER", "dummy")
|
|
os.environ.setdefault("SDL_AUDIODRIVER", "dummy")
|
|
|
|
import pygame # noqa: E402
|
|
from game import Game # noqa: E402
|
|
|
|
|
|
def save(g, name, out):
|
|
g.render()
|
|
path = os.path.join(out, name + ".png")
|
|
pygame.image.save(g.canvas, path)
|
|
# also save an upscaled preview
|
|
big = pygame.transform.scale(g.canvas, (CV_W * 2, CV_H * 2))
|
|
pygame.image.save(big, os.path.join(out, name + "_2x.png"))
|
|
print("saved", path)
|
|
|
|
|
|
from physics import CV_W, CV_H # noqa: E402
|
|
|
|
|
|
def main():
|
|
out = sys.argv[1] if len(sys.argv) > 1 else "shots"
|
|
os.makedirs(out, exist_ok=True)
|
|
g = Game()
|
|
|
|
# ---- title ----
|
|
for _ in range(50):
|
|
g.update()
|
|
save(g, "1_title", out)
|
|
|
|
# ---- serve hint ----
|
|
g.state = "play"
|
|
g.new_game()
|
|
for _ in range(140): # past the ball banner
|
|
g.update()
|
|
save(g, "2_serve", out)
|
|
|
|
# ---- mid play, staged action ----
|
|
t = g.table
|
|
# force a live ball drifting toward the bumpers
|
|
t.reset_ball_in_cannon()
|
|
g.pending = "live"
|
|
t.ball_live = True
|
|
t.ball.x, t.ball.y = 295, 75
|
|
t.ball.vx, t.ball.vy = -2.2, 3.1
|
|
for _ in range(80):
|
|
g.keys["fire"] = False
|
|
g.update()
|
|
save(g, "3_play", out)
|
|
|
|
# manually trigger some juice: bumper hit + combo + fever
|
|
g.combo = 4
|
|
g.combo_t = 150
|
|
g.fever = 60 * 12
|
|
g.add_msg("+500", 180, 150, (255, 214, 92))
|
|
for st in t.stars:
|
|
st["lit"] = True
|
|
b = t.bumpers[0]
|
|
b["squash"] = 4
|
|
b["face_t"] = 0.0
|
|
g.particles.append(dict(x=180, y=150, life=14, kind="ring", color=(255, 255, 255)))
|
|
g.bubble = ["CANDY FEVER!", 90, "star"]
|
|
save(g, "4_fever", out)
|
|
|
|
# ---- drain overlay ----
|
|
g.pending = "drain_pause"
|
|
g.pending_t = 40
|
|
save(g, "5_drain", out)
|
|
|
|
# ---- game over ----
|
|
g.pending = "over_banner"
|
|
g.pending_t = 1
|
|
g.lives = 0
|
|
g.update()
|
|
for _ in range(80):
|
|
g.update()
|
|
save(g, "6_gameover", out)
|
|
|
|
pygame.quit()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|