Animace a sekvence
Tyto tři moduly ti ušetří ruční správu frame čítačů. picogame_anim pohání snímky sprite na základě času, picogame_seq ti umožní psát časové osy jako generátory a picogame_cutscene vykreslí obrázek přes celou obrazovku s minimálními nároky na RAM. Jsou to pure-Python helpery nad enginem - signatury najdeš v /cs/reference/.
picogame_anim
Sekce “picogame_anim”Co to je: malý driver pro snímkovou animaci. Předáš mu seznam indexů snímků a fps, každý frame zavoláš tick(dt) se skutečně uplynulými sekundami a on sám nastaví sprite.frame. Sáhni po něm vždy, když bys jinak psal sprite.frame = (f // 4) % n - animace bude nezávislá na snímkové frekvenci (řízená skutečným dt, ne počtem volání smyčky) a matematiku dostaneš z update smyčky pryč.
Máš dvě třídy:
FrameAnim(sprite, frames, *, fps=8, loop=True)- přehraje jednu sekvenci.framesje list/tuple indexů snímků (předán odkazem, nikoli kopií - považuj ho za read-only).fpsje rychlost animace;loopje keyword-only. Při vytvoření nastaví sprite naframes[0]..tick(dt)- posune odtskutečných sekund. Akumuluje čas a přepne snímek, když uplynulo dost. Pokud neloopující animace skončila nebo jeframesprázdný, nedělá nic. Nic nevrací..configure(frames, fps=8, loop=True)- přesměruje tuto instanci na novou sekvenci a resetuje ji. Vracíself. Umožní ti znovu použít jednuFrameAnimmísto alokace nové při každém přepnutí..reset()- vrátí na snímek 0, smaže příznakdonea akumulátor času.- Atributy ke čtení:
.done(True, když neloopující animace dosáhla posledního snímku),.i(aktuální index doframes),.frames,.fps,.loop.
AnimatedSprite(sprite, anims)- sprite s pojmenovanými stavy.animsje dict{name: (frames, fps, loop)}. Interně drží jednu znovu použitelnouFrameAnim(bez alokace při přepnutí)..play(name)- přepne na danou pojmenovanou animaci. Vyhledáanims[name]a překonfiguruje. Voláníplayse jménem, které už hraje, je no-op, takže je bezpečné volat každý frame..tick(dt)- posune aktuální animaci.
import picogame_anim
hero = picogame_anim.AnimatedSprite(self.spr, { "run": (DINO_RUN, 12, True), "jump": ((DINO_JUMP,), 1, False),})hero.play("run")# each frame, with dt = real seconds since last frame:hero.play("jump" if self.jumping else "run") # cheap to call every framehero.tick(dt)Pro jednu sekvenci (rotující mince, animace chůze) přeskoč dict a použij FrameAnim přímo: spin = picogame_anim.FrameAnim(sprite, list(range(COIN_FRAMES)), fps=15).
Pozor na: musíš předat skutečné dt (sekundy za snímek, např. z picogame_clock), ne počet snímků - pokud předáš 1, poběží animace rychlostí fps snímků za volání. List frames je držen odkazem, takže ho neměň, dokud je používán. .done se stane True pouze pro loop=False.
picogame_seq
Sekce “picogame_seq”Co to je: způsob, jak psát časovanou a postupnou logiku jako generátory (coroutine vzor). Každý yield znamená “probuď mě příští frame”; Seq posune jeden generátor o jeden krok per tick(). Sáhni po něm pro cutscény, intra, postupnou AI a jakoukoliv časovou osu “dělej X po N snímcích”, která by se jinak proměnila v spleti frame čítačů a if-podmínek. Podsekvence skládej pomocí yield from.
Pomocníci pro generátory (volej přes yield from):
wait(frames)- pauza naframessnímků (tolikrát yields a nic nedělá).over(frames, fn)- obecný tween: voláfn(t)každý frame strostoucím od0do1(konkrétněi/framesproiv1..frames) po dobuframessnímků.move_over(sprite, x, y, frames)- lineárně posune sprite z jeho aktuální pozice na(x, y)zaframessnímků přessprite.move(...).
Driver:
Seq(gen=None)- obalí jeden generátor. Pokud jegenNone, začíná jako.done..start(gen)- nasměruje ho na (nový) generátor a smažedone. Vracíself, takže je znovu použitelný..tick()- posune na dalšíyield. ZachytíStopIterationa nastaví.done. Vrací příznakdone(True po skončení), takže se na něj můžeš větvit..done- True, když sekvence skončila.
import picogame_seq as seq
def intro(hero, label): yield from seq.wait(30) label.set("GO!") yield from seq.move_over(hero, 120, hero.y, 20) # glide over 20 frames
s = seq.Seq(intro(player, hud))# each frame:if not s.tick(): # advances one step; True once the intro is over ... # still runningPozor na: tick() posune přesně o jeden krok (na další yield) za volání, takže ho spouštěj jednou za herní frame. Vše mezi yieldy se provede v jednom snímku - těžkou práci dávej za yield. Seq spouští jeden generátor; chceš-li souběžně více časových os, dej každé vlastní Seq, nebo je slučuj pomocí yield from uvnitř jednoho generátoru.
picogame_cutscene
Sekce “picogame_cutscene”Co to je: přehrávač obrázků přes celou obrazovku s minimální spotřebou RAM. Snímek 320x240 má 150 KB v RGB565 (75 KB v PAL8), což se nevejde do ~138 KB heapu - viz /cs/memory/. Místo toho obrázek žije na flashi jako raw, row-major soubor a modul ho streamuje po jednom ~24řádkovém bandu skrz malý znovu použitý buffer, přičemž každý band blituje přímo na LCD. V RAM je vždy jen jeden band; po vykreslení si obrázek drží LCD, takže statická cutscéna pak nestojí nic. Sáhni po něm pro úvodní obrazovky, příběhové panely, mapy a mezichapterové karty.
Raw soubor si nejprve upečeš pomocí tools/bake_image.py (PNG na wire-order RGB565 řádky, nebo PAL8 plus paletu). Formáty bitmap enginu najdeš v /cs/scene-format/ a informace o displeji a tlačítkách v /cs/hardware/.
show(pg, display, buffer, path, w=320, h=240, band=24, palette=None)- vykreslí obrázek zpathnadisplay, streamuje band po bandu.bufferje tvůj strip buffer. Předejpalettepro čtení 1-bajt-na-pixel PAL8 souboru; pro 2-bajtový RGB565 ho vynech. Nic nevrací.play(pg, display, buffer, btn, path, w=320, h=240, band=24, palette=None)- zavoláshow(), pak blokuje (pollingbtn) dokud není stisknutoAneboB, pak se vrátí. Použij pro obrazovky “stiskni pro pokračování”;show()použij, když chceš pokračovat ve vlastní smyčce.
import picogame_cutscene as cutimport board
cut.play(pg, board.DISPLAY, bufA, btn, "intro.dat") # RGB565cut.play(pg, board.DISPLAY, bufA, btn, "map.dat", palette=PAL) # PAL8 + palettePozor na: band MUSÍ dělit h beze zbytku (240 % 24 == 0), jinak ti budou chybět řádky. buffer musí mít alespoň w * band * 2 bajtů (RGB565) - nebo w * band pro PAL8. Soubor musí být raw, row-major, v wire order z bake_image.py; normální PNG nebude fungovat. play() zcela zablokuje tvou herní smyčku po dobu čekání na tlačítko.