Boot a herní smyčka
Tyto tři moduly jsou páteří každé hry na PicoPadu: picogame_game převezme displej a předá ti Scene, picogame_clock hlídá timing snímků a dává ti dt, a picogame_input převede fyzická tlačítka na bitmasku s detekcí hran. Typický code.py jednou zavolá picogame_game.setup(), vytvoří Buttons() a Clock(), a pak se točí ve smyčce: poll, update, refresh, tick. Čisté signatury najdeš na /cs/reference/.
picogame_game
Sekce “picogame_game”Inicializační kostra. Zavolej to jednou na začátku hry - zakáže to displayio auto-refresh, vyčistí root group, alokuje dva strip buffery a sestaví ti Scene, takže přeskočíš veškerý renderovací boilerplate. Sáhni po tom, kdykoli chceš herní převzetí obrazovky místo normálního displayio UI.
setup(display=None, strip_h=24, background=0, fast=True, top=0, bottom=0, left=0, right=0, rgb444=False)- převezme displej a vrátí tuple(scene, buffer_a, buffer_b). Nastavídisplay.auto_refresh = False, vyčistíroot_group, alokuje dva full-width xstrip_hstrip buffery (každýwidth * strip_h * 2bajtů) a sestavíScene. Drž všechny tři vrácené hodnoty živé po celou dobu hry - buffery nesmí být garbage-collected.display- displayio displej; výchozí jeboard.DISPLAY.strip_h- výška každého render stripu v pixelech. Menší hodnota šetří RAM, větší může znamenat méně SPI transakcí. Kompromis popisuje /cs/memory/.background- barva pozadí za scénou jako RGB565 int. Sestav ji pomocípg.rgb565(r, g, b).top/bottom/left/right- rezervuje okraj (px), do kterého scéna nebude kreslit, takže maluje jen vnitřní herní obdélník. Ten okraj nakreslíš sám (HUD bar, boční panely) jednou a pak se už nepřepočítává na každý snímek.fast-Truepoužije platformový rychlýpg.Display(async DMA kde je k dispozici);Falseřídí obyčejný busdisplay přes přenosný renderer (funguje všude, pomalejší). Na portu bez DMA backendusetupautomaticky přepne.rgb444-Trueposílá 12-bit RGB444 místo 16-bit RGB565 (~25% méně SPI provozu, 4096 barev), jen pro rychlýDisplaya vyžaduje 12-bit kontroler (ST7789/ST7735, ne ILI9341).rgb444="auto"to zapne jen tam, kde board hlásípg.RGB444_SUPPORTED, takže jeden kód běží optimálně na ST7789 a bezpečně na ILI9341.
import picogame as pgimport picogame_game
BG = pg.rgb565(20, 24, 30)scene, bufA, bufB = picogame_game.setup(background=BG, strip_h=16, top=12)# scene is a pg.Scene; add sprites and refresh it each framescene.add(sprite)scene.refresh()Pozor na: drž scene, bufA a bufB po celou dobu hry - pokud se buffery uvolní, rendering se rozbije. Okraj, který rezervuješ přes top/bottom/left/right, je tvůj na malování; setup jen zastaví scénu, aby tam kreslila. Co Scene očekává popisuje /cs/scene-format/ a poznámky k displejům pro konkrétní boardy najdeš na /cs/hardware/.
picogame_clock
Sekce “picogame_clock”Timing snímků. Clock omezí tvoji smyčku na cílové FPS a vrátí reálné dt (uběhlé sekundy), takže pohyb může být nezávislý na snímkové frekvenci a rychlé poklepání na D-pad nevymrští sprite přes celou obrazovku při vysokém FPS. FixedStep je alternativa, když chceš deterministickou logiku: spouští update v stejně velkých krocích bez ohledu na dobu renderování. Používej Clock pro většinu her; sáhni po FixedStep, když fyzika nebo kolize musí být reprodukovatelné.
Clock:
Clock(fps=30, max_dt=0.1)- omezí smyčku nafps(použij0pro bez omezení) a ořízne vrácenédtna maximálněmax_dtsekund, takže pauza nebo zaseknutí nemůže vyrobit obřídt, které teleportuje vše.tick()- čeká do hranice snímku a pak vrátí reálnédtv sekundách od posledníhotick(). Kotví se na ideální rozvrh, takže malé překročení se nesmí akumulovat do driftu; pokud jsi přetáhl rozpočet, ukotvuje se na reálný čas adtzůstane přesné. Volej jednou za snímek.tick_async()- awaitable varianta, která při čekání nečinnosti předá řízení jinýmasynciotaskům místo blokování. Vyžaduje dostupnou knihovnuasyncio(jinak vyhodíRuntimeError). Pozor - samotné renderování blokuje, takže async pomůže jen v mezeře cap-sleep.set_fps(fps)- změn cílové FPS za běhu (např. menu na 30, akce na 60).0odstraní omezení.
FixedStep:
FixedStep(step_fps=60, max_steps=5)- pevný timestep1/step_fpssekund, spustí nejvýšemax_stepslogických kroků za snímek (limit zabrání “spirále smrti”, když rendering nestíhá - backlog se zahodí).step_count()- vrátí počet pevných kroků pro tento snímek (0..max_steps). Iterujfor _ in range(step_count())a používej konstantníself.dt; tato forma nic nealokuje, vhodné pro horké smyčky.dt- konstantní délka kroku v sekundách. Předej ji svému updatu.steps()- generátorová forma, která pro každý krok yieldujeself.dt. Pohodlné, ale při každém volání alokuje generátor; v hlavní smyčce raději použijstep_count().
import picogame_clock
clock = picogame_clock.Clock(30) # cap to 30 FPSwhile True: dt = clock.tick() # sleeps to the frame boundary, returns real dt player.x += player.vx * dt # frame-rate independent movement scene.refresh()Pozor na: volej tick() přesně jednou za snímek, na konci smyčky. Pokud vrácenou hodnotu ignoruješ, FPS cap stále funguje, ale přijdeš o nezávislost na snímkové frekvenci - to je v pořádku pro mřížkovou hru s pevným pohybem, ne pro plynulý motion. tick_async() ti něco přinese jen tehdy, když rendering může překrývat jiné tasky; samotné volání renderu stále blokuje.
picogame_input
Sekce “picogame_input”Tlačítka. Buttons čte fyzická tlačítka boardu do logické bitmasky s detekcí hran (právě stisknuto / právě uvolněno) a auto-repeatem, přičemž backend vybírá automaticky podle boardu: modul keypad z CircuitPythonu (hardwarový debounce, skenování na pozadí, fronta událostí, takže rychlé stisky se nikdy neztratí) kde je k dispozici, jinak digitalio polling - stejné API v obou případech. Timer je malý ubývající čítač snímků pro triky se vstupní benevolencí (coyote time, jump buffering). Používej Buttons v každé hře; přidej Timer, když akční hra musí být odpouštějící.
Logická tlačítka jsou přístupná jak jako konstanty modulu, tak jako atributy instance: UP, DOWN, LEFT, RIGHT, A, B, X, Y, L1, L2, R1, R2, START, SELECT, plus ALL. PicoPad mapuje osm face buttonů; chybějící tlačítka (žádná ramena) prostě nikdy nespustí. Jsou to bitové příznaky, takže je můžeš ORovat: btn.A | btn.B.
Buttons:
Buttons(profile=None, pull=None, prefer_keypad=True, debounce_s=0.02)- sestaví čtečku. Sprofile=Nonese pin mapa určuje podle priority od nejvyšší: explicitníprofile, paksettings.tomlPICOGAME_BUTTONS = "UP=GP2 A=GP12 ..."(přemapuj vlastní Pico bez reflashování), pak vestavěný profil podleboard.board_id, pak fallbackPICOPAD.pullvýchozí jePull.UP(neboPICOGAME_PULLvsettings.toml).debounce_sje okno skenování keypad;prefer_keypad=Falsevynutí polling.poll()- jednou vzorkuje všechna tlačítka a vrátí aktuální bitmasku stisknutých. Volej jednou za snímek, před jakýmkoliv dotazem. Vyprázdní frontu událostí keypad (zachytí sub-frame stisky) nebo přečte piny přímo a aktualizuje počty held-frame prorepeat().is_pressed(mask=ALL)-Truepokud je aktuálně stisknuto jakékoli tlačítko vmask(úroveň).just_pressed(mask=ALL)-Truena vzestupné hraně (snímek, kdy tlačítko šlo dolů). Na keypad backendu pochází z fronty událostí, takže stisk kratší než jeden snímek se stále zaregistruje.just_released(mask=ALL)-Truena sestupné hraně (snímek, kdy tlačítko šlo nahoru).has(mask=ALL)-Truepokud tento board fyzicky zapojuje daná tlačítka. Použij to k přizpůsobení ovládání/UI pro boardy bez ramen nebo bez START/SELECT.repeat(button, delay=15, interval=4)- auto-repeat pro JEDNO tlačítko:Trueve snímku, kdy je stisknuto, pak každýchintervalsnímků po přidrženídelaysnímků. Ideální pro pohyb v menu a mřížce.clear()- resetuje stav a vyprázdní čekající vstup. Volej při přechodech mezi scénami nebo menu, aby přidržené tlačítko neprosáklo dál.
Timer:
Timer(frames)- čítač, který ubývá jeden snímek po druhém po dobuframessnímků.feed(condition)- dobije na plnou hodnotu pokud jeconditionpravdivá, jinak odečte jeden snímek; vrátí, zda je stále aktivní. Použij pro coyote time (feed(on_ground)).charge()- vynutí čítač na plnou hodnotu.is_active(property) -Truedokud je čítač nad nulou.consume()- jednou vrátíTruepokud je aktivní, pak se vynuluje, takže bufferovaný stisk se spustí přesně jednou (jump buffering).
import picogame_input
btn = picogame_input.Buttons() # auto profile by boardwhile True: btn.poll() dx = btn.is_pressed(btn.RIGHT) - btn.is_pressed(btn.LEFT) # -1, 0 or +1 if btn.just_pressed(btn.A): # rising edge: fire once per tap jump() scene.refresh()Coyote time a jump buffering, přímo z příkladu platformovky:
coyote = picogame_input.Timer(5) # still jump a few frames after a ledgejbuf = picogame_input.Timer(6) # honour a jump pressed just before landing# each frame:coyote.feed(on_ground)jbuf.feed(btn.just_pressed(btn.A))if coyote.is_active and jbuf.consume(): jump()Pozor na: vždy volej poll() jednou za snímek před dotazováním, jinak is_pressed / just_pressed čtou zastaralý stav. repeat() bere jedno tlačítko, ne OR-masku. Backend digitalio polling nemá debounce (vzorkování po snímcích už filtruje sub-frame zákmity); pro hlučný přepínač na sestavě bez keypad debounce řeš upstream. Profily boardů a klíče pro přemapování v settings.toml popisuje /cs/hardware/.