Animace a sekvence
Tyto tři moduly řeší animaci spritů, časované sekvence a statické obrázky přes celou obrazovku. picogame_anim posouvá animaci podle uplynulého času, picogame_seq zapisuje sekvence jako generátory a picogame_cutscene načítá obrázek po částech, takže nemusí držet celý snímek v Python heapu. Signatury najdeš v /cs/reference/.
picogame_anim
Sekce “picogame_anim”Třídě FrameAnim předej sekvenci a hodnotu fps. V každém herním snímku pak zavolej tick(dt) s uplynulým časem v sekundách. Položkou sekvence může být index snímku ve spritesheetu nebo samostatný objekt Bitmap. Animace se tak řídí časem, ne počtem průchodů smyčkou.
Modul obsahuje dvě třídy:
FrameAnim(sprite, frames, *, fps=8, loop=True)- přehraje jednu sekvenci.framesje seznam nebo n-tice indexů snímků, případně objektůBitmap. Sekvence se nekopíruje, proto ji za běhu neměň.fpsurčuje rychlost alooplze zadat pouze jménem. Pokud sekvence není prázdná, konstruktor zobrazíframes[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 slovník{name: (frames, fps, loop)}. Třída používá jednu instanciFrameAnim, takže při změně animace nealokuje další..play(name)- přepne na pojmenovanou animaci. Vyhledáanims[name]a přenastaví interníFrameAnim. Pokud už daná animace běží, nic neudělá, takže metodu můžeš volat v každém snímku..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")# každý snímek; dt je skutečný počet sekund od minulého snímku:hero.play("jump" if self.jumping else "run") # lze levně volat každý snímekhero.tick(dt)Pro jedinou sekvenci, například rotující minci, použij FrameAnim přímo: spin = picogame_anim.FrameAnim(sprite, list(range(COIN_FRAMES)), fps=15).
picogame_seq
Sekce “picogame_seq”picogame_seq zapisuje časovanou logiku jako generátory. Každý yield pozastaví běh do dalšího herního snímku a každé volání tick() posune jeden generátor k následujícímu yield. Hodí se pro úvody, postupnou logiku protivníků a další děje s pevným pořadím. Menší sekvence skládej pomocí yield from.
Pomocníci pro generátory (volej přes yield from):
wait(frames)- počkáframessnímků.over(frames, fn)- v každém snímku zavoláfn(t), přičemžtroste od0do1(přesnějii/framesproiv1..frames).move_over(sprite, x, y, frames)- lineárně posune sprite z jeho aktuální pozice na(x, y)zaframessnímků přessprite.move(...).
Spouštění sekvence:
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) # přesun během 20 snímků
s = seq.Seq(intro(player, hud))# každý snímek:if not s.tick(): # posune o krok; po skončení úvodu vrátí True ... # sekvence ještě běžípicogame_cutscene
Sekce “picogame_cutscene”picogame_cutscene zobrazí statický obrázek přes celou obrazovku, aniž by celý zdroj načetl do Python heapu. Zdroj o rozměrech 320x240 zabere 153 600 bajtů v RGB565 nebo 76 800 bajtů v PAL8. Modul proto čte surový soubor z flash paměti po pásech řádků a každý pás vykreslí přes zobrazovací backend.
Dočasný zdrojový pás zabere w * band bajtů v PAL8 nebo w * band * 2 bajtů v RGB565. Pro výchozí w=320 a band=24 je to 7 680, respektive 15 360 bajtů nad rámec vykreslovacího bufferu předaného do show(). Pokud se alokace nevejde, zmenši band. Po vykreslení už není potřeba žádný další Python objekt s celým snímkem. Ostatní náklady popisuje stránka /cs/memory/.
Zdrojový soubor nejprve vytvoř pomocí tools/bake_cutscene.py. Nástroj převádí PNG na PAL8 s modulem palety nebo na řádky RGB565 v pořadí pro přenos. Formáty bitmap enginu najdeš v /cs/scene-format/ a informace o displeji a tlačítkách v /cs/hardware/.
palette(pg, rgb)- vytvoří paletu pro zařízení (array('H')barev v pořadí pro přenos) z modulu palety odbake_cutscene.py, seznamu trojic(r, g, b)nebo hotových číselných hodnot. Vytvoř ji jednou při inicializaci a dále ji používej; jinak jishow()sestaví při každém volání.show(pg, display, buffer, path, pal=None, w=320, h=240, scale=None, band=24, bg=0)- načítá obrázek zpathpo pásech a každý pás vykreslí pomocí vykreslovacího bufferubuffer.palvybírá vstup PAL8 (1 B/px);Nonevybírá RGB565 (2 B/px).scale=Noneodvodí celočíselné zvětšení z displeje (width // w) a odmítne zdroj, který nevyplní obě osy. Krátký poslední pás dočistí barvoubg. Vrací použité zvětšení.play(pg, display, buffer, btn, path, pal=None, w=320, h=240, scale=None, band=24, caption=None, caption_lines=None, auto_hold=0, clock=None, bg=0)- zobrazí obrázek, doplní volitelné řádky popisku v tmavém pruhu a počká na stisk A nebo B. Sauto_hold > 0pokračuje po daném počtu průchodů čekací smyčkou abtnmůže býtNone. Smyčku můžeš časovat instancípicogame_clockpředanou jakoclock.
import picogame_cutscene as cutimport board
PAL = cut.palette(pg, intro_pal) # jednou při inicializacicut.play(pg, board.DISPLAY, bufA, btn, "intro.raw", pal=PAL, caption="Chapter 1", clock=clock)scene.invalidate() # obrázek přepsal obsah displeje