picogame — 2D herní engine pro PicoPad (CircuitPython)
picogame je 2D herní engine s uchovávanou scénou, napsaný jako C modul pro CircuitPython.
Referenčním cílem je Pajenicko PicoPad (RP2040, 320×240 ST7789), podporované jsou i další
desky. Oproti _stage nabízí sprity různých velikostí, Scene s dirty regiony, tilemapy,
částice, kreslicí plochy a volitelný backend s asynchronním DMA.
- Referenční cíl: firmware PicoPadu a SPI backend jsou testované na zařízení. Stav dalších cílů uvádí stránka Podporovaný hardware.
- Výkon: na SPI displeji přenáší
Scenesamostatně až šest dirty regionů. Pohyb soustředěný na malé ploše proto může být levnější než celý snímek; změny rozeseté po obrazovce a pohyb kamery se mohou blížit překreslení celé obrazovky.
Obsah
Sekce “Obsah”- Kam tahle stránka patří
- Rychlý start
- Přehled API
- Příprava grafiky a map
- Náklady a omezení enginu
- Pod kapotou
- Build firmwaru
- Příklady
Kam tahle stránka patří
Sekce “Kam tahle stránka patří”Tohle je hloubkový průvodce nativním C modulem picogame: přesné chování, kontrakty
a náklady typů enginu. Předpokládá, že víš, co hledáš.
- Jsi tu poprvé? Tvoje první hra, pak Jak picogame funguje.
- „Kterou vrstvu/plochu použít?“ → Kreslicí cesty; rejstřík podle úkolů ve FEATURES.md.
- Holé signatury všeho → REFERENCE.md.
- Čistě-Python helpery
picogame_*(vstup, časování, audio, UI, pooly, ukládání…) mají vlastní průvodce v sekci Helpery — tahle stránka pokrývá jen C modul. (Helpery si drží prefix souborůpicogame_*, nikoli balíčekpicogame/: to jméno patří C modulu a nelze ho zastínit.)
Dva kontrakty, na kterých stojí všechno: barvy jsou vždy ve wire order —
skládej je přes pg.rgb565(r, g, b); naivní 0xRRGGBB nebo host-endian RGB565 vykreslí špatné
barvy. Souřadnice mají počátek vlevo nahoře; obdélníky render volání jsou půlotevřené
(x0,y0 včetně až x1,y1 vyjma), zatímco hitboxy collide() jsou inkluzivní
(jiné domény: pixely vs hitboxy).
Rychlý start
Sekce “Rychlý start”import time, arrayimport boardimport picogame as pgimport picogame_game
BG = pg.rgb565(20, 24, 40)scene, _, _ = picogame_game.setup(background=BG)W, H = board.DISPLAY.width, board.DISPLAY.height # rozměry obrazovky z desky
# Simple 16×16 paletted sprite (index 0 is transparent)pal = array.array("H", [pg.rgb565(0, 0, 0), pg.rgb565(230, 80, 80)])data = bytearray(16 * 16)for y in range(16): for x in range(16): if 3 <= x < 13 and 3 <= y < 13: data[y * 16 + x] = 1hero_bmp = pg.Bitmap(data, 16, 16, format=pg.PAL8, palette=pal, transparent=0)
hero = pg.Sprite(hero_bmp, 150, 110)scene.add(hero)
while True: hero.x = (hero.x + 1) % (W - 16) scene.refresh() time.sleep(1 / 60)Přehled API
Sekce “Přehled API”Modul picogame
Sekce “Modul picogame”| Název | Popis |
|---|---|
RGB565 |
konstanta formátu (16bitová barva ve wire order) |
PAL8 |
konstanta formátu (8bitový index do palette) |
rgb565(r, g, b) -> int |
vytvoří z 8bitových složek barvu RGB565 ve wire order |
collide(x1, y1, x2, y2, ax1, ay1, ax2, ay2) -> bool |
překryv AABB box↔box; inkluzivní hranice, takže boxy kolidují při doteku (boxy spritu předávej jako (x, y, x+w, y+h); spustí se při kontaktu). collide je inkluzivní, na rozdíl od půlotevřených pixelových rozsahů u render (jiné domény: hitboxy vs pixely) |
collide(x1, y1, x2, y2, px, py) -> bool |
box↔bod (6 argumentů) |
render(display, sprites, buffer, x0, y0, x1, y1, *, background=0) |
okamžité vykreslení seznamu spritů do kompatibilního zobrazovacího cíle |
value2d(x, y, *, seed=0) -> float |
hladký 2-D value noise, 0..1 (rychlé C) |
value1d(x, *, seed=0) -> float |
hladký 1-D value noise, 0..1 |
fbm2d(x, y, *, octaves=4, seed=0, lacunarity=2.0, gain=0.5) -> float |
fraktální (fBm) 2-D noise, 0..1 — terén/mraky/jeskyně |
fbm1d(x, *, octaves=4, seed=0, lacunarity=2.0, gain=0.5) -> float |
fraktální (fBm) 1-D noise, 0..1 |
Šum se interně počítá s pevnou řádovou čárkou (Q16.16), což je rychlé na RP2040 bez FPU.
Je určený pro jednorázové generování terénu nebo mraků, ne pro každý snímek. Samostatné exporty _fx
neexistují; value2d/value1d/fbm2d/fbm1d jsou kanonické funkce, volané přímo na modulu
picogame (pg.value2d, pg.fbm2d, …); simulátor poskytuje odpovídající implementaci v Pythonu.
API závislé na buildu
Sekce “API závislé na buildu”Přítomnost závisí na buildu firmwaru — ověř ji přes hasattr nebo getattr:
| Název | Přítomné když | Účel |
|---|---|---|
Display |
CIRCUITPY_PICOGAME_FAST_DISPLAY (porty RP2/ESP) |
backend s asynchronním DMA; na přenositelných portech chybí (místo ní předej Scene běžný busdisplay) |
Framebuffer |
CIRCUITPY_PICOGAME_FRAMEBUFFER (platformy s výstupním framebufferem, např. WASM playground) |
cíl vykreslování v RAM místo panelu |
RGB444_SUPPORTED |
vždy (bool) | zda panel této desky umí 12bitové RGB444 |
STRIP_H |
vždy (int) | výchozí výška stripu desky (používá ji picogame_game.setup) |
API_LEVEL |
novější firmware (použij getattr(pg, "API_LEVEL", 0)) |
generace API enginu, pro verzní kontroly předem |
Bitmap(data, width, height, *, format=RGB565, palette=None, frames=1, stride=0, transparent=None)
Sekce “Bitmap(data, width, height, *, format=RGB565, palette=None, frames=1, stride=0, transparent=None)”Obrazový atlas jednoho či více stejně velkých snímků, libovolné šířky a výšky.
data— čitelný buffer:PAL8= 1 bajt na index pixelu;RGB565= 2 bajty na pixel ve wire order.palette— proPAL8buffer barev RGB565 ve wire order (např.array("H", [...])).frames— snímky animace uspořádané vodorovně; snímekfzačíná ve sloupcif*width.stride— šířka atlasu v pixelech (výchozíwidth*frames).transparent— index palety (PAL8) nebo barva (RGB565) ve wire order, která se přeskočí;None= neprůhledné.- Vlastnosti jen pro čtení:
width,height,frames,format,stride,palette(buffer palety PAL8 neboNone) atransparent(průhledná hodnota neboNone).
Sprite(bitmap, x=0, y=0, *, frame=0, visible=True, flip_x=False, flip_y=False)
Sekce “Sprite(bitmap, x=0, y=0, *, frame=0, visible=True, flip_x=False, flip_y=False)”Umístěná, animovatelná instance Bitmap.
- Vlastnosti:
x,y(celočíselný pixel; setter přijímá i float),fx,fy(sub-pixelová float pozice),frame,visible,flip_x,flip_y,transpose,data,bitmap,scale,angle,shadow,flash,tint,dither. move(x, y)— nastaví pozici (přijímá int nebo float).overlaps(other, inset=0) -> bool/near(other, r) -> bool— nativní testy kolizí (zohledňují anchor/scale/rotaci, bez alokací).overlapsje inkluzivní test AABB boxu (other=Sprite, bod(x, y), nebo rect(x1, y1, x2, y2));insetzmenší box tohoto spritu o N px pro férovější hitbox.nearje kruhový test (středy dor, bez sqrt;other=Spritenebo bod).scale— rovnoměrné měřítko vykreslení (float, nearest-neighbour).1.0= nativní (rychlá cesta 1:1);2.0= dvojnásobná velikost; zlomky povoleny (např. mince pulzující1.0..1.3, rostoucí powerup). Škáluje kolemanchor.angle— rotace ve stupních kolem anchoru (float).0= žádná (rychlá cesta); jakákoli jiná hodnota použije afinní (inverzně mapovaný) blit. Celočíselná měřítka zůstávají ostrá; rotace lehce „šumí“ (kompromis pixel-art grafiky).scale+anglese skládají.shadow— když jeTrue, neprůhledné pixely sprite cíl ztmaví místo vykreslení své barvy (vržené stíny: posunutá silueta pod sprite; nebo ztmavující/vignette overlay). Lze libovolně kombinovat sescale/angle.- Blit efekty
flash,tint,dither— levné per-pixel přebarvení/průhlednost, vždy jeden naráz (nastavení jednoho ostatní zruší;0= vyp), žádná grafika ani RAM navíc.flash = WHITEobarví neprůhledné pixely plochou barvou (1–3framové bliknutí při zásahu);tint = REDbarvu násobí a zachovává stínování (osvětlení/zranění/zmrazení; umí jen ztmavit);dither = 0..16je Bayer stipple (duch/mlha/rozplynutí, žádná alpha; animuj úroveň pro rozplynutí dovnitř/ven). transpose— když jeTrue, prohodí osy X/Y (diagonální zrcadlení); ve spojení sflip_x/flip_ydává všech 8 orientací jako ostrý blit po rychlé cestě (scale 1, angle 0). Prohodí se šířka/výška obrysu.bitmap— čtení/zápis zdrojovéhoBitmap. Přiřazení nového vymění grafiku za běhu a může změnit velikost (powerupy, měnitelné HUD pruhy, textové popisky); scéna při dalšímrefreshpřekreslí jak staré, tak nové hranice.touch()— označí sprite jako dirty po in-place úpravěbitmap/palety (např. přebarvení přespicogame_palette), aby se změna při dalšímrefreshpřekreslila.anchor— pivot jako(fx, fy)zlomky velikosti bitmapy:(0, 0)vlevo nahoře (výchozí),(0.5, 0.5)střed,(0.5, 1.0)dole uprostřed.x/ypak odkazují na tento bod, takže růst/zmenšování přes výměnubitmapzůstává zarovnáno kolem pivotu. Dirty-rect sleduje výsledný levý horní roh.- Pro hladkou fyziku použij
fx/fy(ball.fx += 2.4) místo paralelního Python floatu +int(round());x/yvracejí zaokrouhlený pixel dolů pro výpočty s tile/kolizemi. Dirty-rect se spustí jen tehdy, když se změní pixel (sub-pixelové chvění pod 1 px je zdarma). data— libovolný objekt s herním stavem daného spritu. Není proto potřeba souběžná obalová třída:hero.data = {"vy": 0, "dead": False}.
Display(busdisplay, *, rgb444=False)
Sekce “Display(busdisplay, *, rgb444=False)”Rychlý backend s asynchronním DMA, který obaluje existující busdisplay.BusDisplay (např.
board.DISPLAY). Znovu využívá jeho SPI sběrnici, piny, příkazy okna a rozměry.
rgb444=Trueřídí panel ve 12bitovém RGB444 místo 16bitového RGB565: ~25 % méně provozu na SPI (3 bajty na 2 pixely) za cenu barevné hloubky.render(sprites, buffer_a, buffer_b, x0, y0, x1, y1, *, background=0)— vykreslí seznam sprite do oblasti pomocí DMA s dvojitým bufferem.picogame.invert(display, on)— přepne hardwarovou inverzi barev panelu. Mění stav inverze panelu bez posílání pixelových dat, takže krátká inverze vytvoří celoobrazovkový negativ (efekt „zásahu“) bez bufferu a bez překreslení. Obaleno vpicogame_fx.InvertFlash.
Scene(display, buffer_a, buffer_b, *, background=0, top=0, bottom=0, left=0, right=0)
Sekce “Scene(display, buffer_a, buffer_b, *, background=0, top=0, bottom=0, left=0, right=0)”Scéna v retained mode s vykreslováním pomocí dirty regionů. display je
picogame.Display (rychlý backend) nebo běžný busdisplay.BusDisplay
(přenositelný backend).
add(item, *, fixed=False) -> item— přidáSprite/Tilemap/Particles/Canvas/StripDrawa vrátí přidanou položku, takžespr = scene.add(Sprite(...))funguje. Pořadí vkládání je zdola nahoru.fixed=True(lze zadat jen jménem) připne položku k obrazovce (ignoruje view offset); použij pro HUD / skóre / dialog, které musí zůstat na místě, zatímco se svět posouvá přesset_view. (nejprve přidej pozadí tilemap, pak sprite, popředí tilemap nakonec).add_all(items)— přidá několik položek najednou (stejné pořadí zdola nahoru).refresh() -> [x1, y1, x2, y2] | None— porovná stav s předchozím snímkem a překreslí jen dirty region; vrací ohraničující dirty rect jako ZNOVUPOUŽÍVANÝ list (přečti ho hned — další volání ho přepíše), neboNone, pokud se nic nezměnilo. První refresh překreslí celou obrazovku (pokryje zbylé pixely z konzole).invalidate()— vynutí překreslení celé obrazovky při dalším refresh (např. při změně levelu).set_view(ox, oy)— view offset = pozice počátku scény na obrazovce. Nastav konstantní offset pro vycentrování malé hry (např. hra 128×128 na 320×240); aktualizuj ho každý snímek pro posouvání většího světa (posouvání překresluje celou obrazovku). Sprite/tilemapy pak žijí v běžných souřadnicích scény bez ohledu na umístění.view— dvojice(ox, oy)s aktuálním posunem kamery, jen pro čtení.display— backend, přes který scéna kreslí, jen pro čtení (obalpg.Display, kde je zapnutý, jinak prostý busdisplay).pg.render()/pg.invert()přijímají obě formy, takžepg.render(scene.display, ...)funguje vždy.
Tilemap(tileset, cols, rows)
Sekce “Tilemap(tileset, cols, rows)”Mřížka indexů tilů do tileset, tedy bitmapy, jejíž snímky představují jednotlivé tily.
tile(tx, ty) -> int/tile(tx, ty, value, *, flip_x=False, flip_y=False, transpose=False)— přečte nebo nastaví tile. Zápis ho označí jako změněný; příznaky orientace lze zadat jen jménem.move(x, y)— posune celou mapu; určí pixelovou pozici tilu 0,0.fill(value)— nastaví všechny tily.- Čtení
tile()mimo rozsah vrací0a zápisy ignoruje (bez výjimky). - Vlastnosti jen pro čtení:
x,y,cols,rows.
Canvas(width, height, *, transparent=None, buffer=None)
Sekce “Canvas(width, height, *, transparent=None, buffer=None)”RAM kreslicí plocha skládaná jako vrstva Scene — obecný domov pro tvary.
Přidej ji do Scene a kresli do ní; znovu se odešlou jen dirty regiony. Barvy mají wire order.
Předáním existujícího buffer (zapisovatelný buffer o width*height*2 bajtech)
podložíš plochu vlastní RAM, místo aby si ji Canvas alokoval sám.
- Primitiva (všechna berou barvy ve wire order):
clear(color),pixel(x, y, color),fill_rect(x,y,w,h,color),rect(x,y,w,h,color),line(x0,y0,x1,y1,color),circle(cx,cy,r,color),fill_circle(cx,cy,r,color),ring(cx,cy,r,thickness,color),triangle(x0,y0,x1,y1,x2,y2,color),fill_triangle(...),ellipse(cx,cy,rx,ry,color),fill_ellipse(...),fill_round_rect(x,y,w,h,r,color),frame3d(x,y,w,h,light,dark)(zkosený box: světlo nahoře/vlevo, tma dole/vpravo),text(x, y, s, fg, font, bg=None)(složí glyfy fontu v C;bg=None= průhledné, funguje i v pohleduStripDrawbez uchovávání samostatné bitmapy textu),move(x, y). blit(bitmap, x, y, frame=0, flip_x=False, flip_y=False)— vykreslí snímek bitmapy do plochy a respektuje její průhledný klíč. Jde o retained způsob, jak do panelu zapéct ikonu, portrét nebo text.- Vlastnosti jen pro čtení:
x,y,width,height. transparent(barva ve wire order) umožňuje použít plochu jako tvarovaný překryv (HUD, ukazatel, vektorová grafika) nad ostatními vrstvami. Stojíwidth*height*2bajtů RAM, takže ji nadimenzuj na to, co potřebuješ (např. stavový pruh 320×16 = ~10 KB).- Upozornění na RAM:
Canvas(320, 240)přes celou obrazovku má 150 KB, příliš velké pro RP2040 (~190 KB heap, ~130 KB souvislých). Udržuj Canvasy malé, nebo použijTilemappro velká posouvaná pole. Viz poznámky k hardwaru. Pro animovanou plochu přes celý snímek zvažStripDrawníže; neuchovává vlastní pixelovou plochu.
StripDraw(callback, x=0, y=0, width=0, height=0, *, always_dirty=True)
Sekce “StripDraw(callback, x=0, y=0, width=0, height=0, *, always_dirty=True)”Kreslicí vrstva v immediate-mode zcela bez pixelového bufferu. Přidává se do Scene
jako jakákoli vrstva, ale místo uchovávání pixelů volá kreslicí funkci jednou pro každý
strip, který se překrývá s jejím obdélníkem:
def draw(view, vx, vy, vw, vh): # `view` je Canvas nad právě vykreslovaným stripem, oříznutý na průnik s vrstvou. # Jeho místní bod (0, 0) odpovídá pixelu obrazovky (vx, vy) a (vw, vh) # udává velikost výřezu. Kresli běžnými metodami Canvas; obsah zůstane # uvnitř obdélníku vrstvy. for ly in range(vh): Y = vy + ly # řádek obrazovky view.fill_rect(0, ly, vw, 1, sky_or_road(Y))
scene.add(pg.StripDraw(draw, 0, 0, 320, 240))- RAM: vrstva neuchovává pixelovou plochu o velikosti
width*height*2. Pseudo-3D silnice přes celou obrazovku se proto obejde bez 150 KB pixelového bufferu, který by potřeboval celoobrazovkovýCanvas. ObjektStripDraw, callback a herní stav však paměť používají. - S výchozím
always_dirty=Truese jeho obdélník překresluje každý snímek (žádné přeskočení přes dirty-rect), takže ho použij pro animovaný obsah: pseudo-3D silnice, gradientní oblohy, raycastery, plazmu, procedurální pozadí, nebo tvary, které se mění každý snímek. Pro statickou grafiku, která většinou stojí, jeCanvaslevnější na CPU (překresluje se jen při změně); vybírej podle pohybu, ne podle velikosti. always_dirty=Falsez něj udělá vrstvu na vyžádání: překreslí se jen když zavoláš.invalidate()(jinak ji dirty-rect přeskočí jako Canvas), panel ve scéně bez vlastní pixelové plochy, který se překresluje jen při změně. Takto kreslí své panelypicogame_ui.SceneBox/SceneMenu.- Udržuj vnitřní smyčku lehkou: kreslicí funkce volá primitiva v C, takže několik volání
fill_rectnebohlinena strip je levných. Vyhni se náročnému Pythonu pro každý pixel. - Read/write vlastnosti
x,y,width,heightpřesunou nebo změní velikost vrstvy za běhu; po zmenšení zavolejscene.invalidate(), aby se uvolněná oblast překreslila. - Kreslí se v prostoru obrazovky (ignoruje offset kamery/view). Ve posouvané scéně
(která volá
set_view) ho přidej jako fixed (scene.add(sd, fixed=True)), aby jeho dirty rect odpovídal tomu, kam kreslí; ve scéně se statickou kamerou na tom nezáleží. Uvnitř callbacku převeď bod obrazovky na souřadnice stripu pomocí(screen_x - vx, screen_y - vy). Skládá se nad nižší vrstvy a pod vyšší, jako každá vrstva. Vizexamples/picogame_stripdraw_example.pyaexamples/journey_hw/journey_mono.py(silnice závodu, intro tvary, dialogový box RPG).
Particles(capacity, *, size=1, gravity=0.0, fade=False)
Sekce “Particles(capacity, *, size=1, gravity=0.0, fade=False)”Sdružená částicová vrstva (mnoho malých pohyblivých teček) vykreslená jako jedna vrstva Scene,
mnohem levnější než jeden Sprite na částici. Přidej ji do Scene. S fade=True
každá částice během svého života stmívá k černé (vzhled jisker/uhlíků/kouře).
emit(x, y, count, speed=1, life=30, color=0xFFFF)— vytvořícountčástic na (x, y) s náhodnou rychlostí ažspeedpx/tick, žijícíchlifeticků, ve barvě ve wire order (použijpicogame.rgb565).tick()— posune o jeden krok (pohyb, gravitace, stárnutí); volej jednou za snímek.clear()— odstraní všechny částice.- Pozice jsou sub-pixelové (fixed-point); vrstva překresluje jen tam, kde částice
jsou (a byly), takže nezanechávají stopy. v1 kreslí plné tečky
size×size.
Příprava grafiky a map
Sekce “Příprava grafiky a map”tools/png2picogame.py (na straně hostitele, potřebuje Pillow) převádí PNG/BMP na importovatelné
moduly s grafikou a mapami, jejichž barvy už mají správné wire order.
# Sprite nebo vodorovný atlas animace (formát PAL8/RGB565 se zvolí automaticky):python3 tools/png2picogame.py hero.png -o hero.py --frames 6
# Svislý či mřížkový tileset -> vodorovný atlas Bitmap (tily 16x16):python3 tools/png2picogame.py tiles.bmp -o tiles.py --tile 16x16 --transparent-index 15
# Tilemap (indexy palety obrázku jsou indexy tilů) -> datový modul:python3 tools/png2picogame.py level.bmp -o level.py --mapNa zařízení:
import hero, tiles, levelspr = pg.Sprite(hero.bitmap(pg), 40, 120)tileset = tiles.bitmap(pg)tm = pg.Tilemap(tileset, level.WIDTH, level.HEIGHT)level.fill(tm) # načte data mapyVolby: --format auto|pal8|rgb565, --frames N, --tile WxH, --map,
--transparent-index N (považuje index palette v režimu P za průhledný), --rle (RLE-komprese
jednosnímkové pozadí PAL8).
Volby šetřící velikost (PAL8):
--dither(+--colors N, výchozí 255): Floyd–Steinberg dither při redukci na PAL8; skrývá pruhování gradientů (oblohy, osvětlení). Nízké--colors(např. 16–32) +--dither= retro vzhled.--dedup(s--tile WxH) — sloučí tily, které jsou identické až na orientaci (všech 8: 4 rotace × zrcadlení) do menšího tilesetu → méně RAM tilesetu. Vydá tabulkuREMAP; přestav svou mapu pomocív, fx, fy, tp = REMAP[old_index]; tm.tile(x, y, v, flip_x=fx, flip_y=fy, transpose=tp)(nese otočení a zrcadlení každého tilu; příznaky orientace lze zadat jen jménem). Typické ručně kreslené úrovně mají 40–70 % duplicit. Funguje spolu s orientací jednotlivých buněkTilemap.
Náklady a omezení enginu
Sekce “Náklady a omezení enginu”Pro nasazení si přečti Spuštění na hardwaru (
.mpy, firmware a testování na zařízení) a Vejít se do paměti (náklady a měření).
- Uchovávané plochy plánuj podle změřené haldy. Celoobrazovkový
Canvas(320,240)má 150 KB a přesahuje největší souvislý blok současného buildu pro RP2040 PicoPad. Drž plochyCanvasmalé, pro velká pole použijTilemapa pro animovaný celoobrazovkový obsahStripDraw. Náklady a rozhodovací matice: Kreslicí cesty + MEMORY.md. - Dirty regiony snižují provoz na SPI při soustředěném pohybu. Překreslení celé obrazovky stále platí cenu za skládání i přenos; dominantní část závisí na scéně, firmwaru a taktu SPI.
- Až šest dirty regionů: překrývající se změny se nejprve spojí. Pokud jich zbývá více
než šest,
Scenepostupně slučuje dvojici s nejmenším nárůstem plochy. Pohyb na malé ploše tak zůstává levný, ale změny rozeseté po obrazovce se mohou blížit úplnému překreslení.refresh()vrací pro diagnostiku jejich společný ohraničující obdélník, vykreslovač však jednotlivé regiony zpracuje samostatně. - Nativní typy (
Sprite,Bitmap, …) nemohou nést vlastní atributy — pro stav objektu použijsprite.data. - PAL8 používá polovinu prostoru RGB565 (1 B/px proti 2). U větší grafiky zvaž také zmrazená data, ROMFS nebo postupné čtení; viz Kde je uložená grafika.
Pod kapotou
Sekce “Pod kapotou”Jak se refresh() nebo render() dostane na výstup:
- SPI cíle se vykreslují po vodorovných stripech. Engine používá jeden nebo dva malé buffery. Pro každý strip vyčistí pozadí, složí překrývající se vrstvy a výsledek odešle.
- Framebufferové cíle skládají obraz do výstupního framebufferu. SPI řádkové buffery nealokují. Větší dirty region stále znamená více pixelů ke složení, ale bez přenosu přes SPI.
- Rychlý SPI backend (
pg.Display) používá dva buffery a asynchronní DMA. CPU skládá další strip, zatímco předchozí je ještě na SPI sběrnici. Přenositelný backend přes běžnýbusdisplaypoužívá jeden buffer a blokujícíbus.send. - Výška stripu plyne z velikosti alokovaného bufferu (
buffer_len / (width*2)). Menší stripy umožňují jemnější překryv CPU a přenosu na DMA backendu; větší stripy znamenají méně blokujících odeslání na přenositelném backendu. Proto se výchozíSTRIP_Hdesky liší (8 s DMA, 24 bez). - Sledování změn porovnává každou vrstvu s uloženým stavem položky: pozicí, snímkem,
měřítkem, úhlem, efekty a hodnotou
seqzvýšenou přestouch().Canvas,TilemapaParticlesshromažďují vlastní dirty regiony a předají je přirefresh(). - Rotace a škálování používají inverzní mapování s pevnou řádovou čárkou. Transformace spritu se přepočítá jen při změně úhlu, měřítka, bitmapy nebo kotevního bodu.
Build firmwaru
Sekce “Build firmwaru”Engine je nativní modul uvnitř forku CircuitPythonu; jeho build popisuje samostatný průvodce Build firmwaru (nástroje, konfigurace desek a volby). Hotový firmware pro podporované desky: Podporovaný hardware.
Příklady
Sekce “Příklady”V kořeni projektu (zkopíruj do CIRCUITPY/code.py):
| Soubor | Co ukazuje |
|---|---|
examples/picogame_demo_code.py |
sprite libovolné velikosti, rychlý Display, rozpis FPS/časování |
examples/picogame_scene_demo.py |
retained Scene + dirty-rect (statické pole + pohyblivé objekty) |
examples/picogame_play_demo.py |
vstup z D-padu → Scene (pohyb omezený snímkovou frekvencí) |
examples/picogame_hud_demo.py |
HUD text přes přibalený font (picogame_font.py) |
examples/picogame_tilemap_demo.py |
tilemap pozadí + sprite nad ním |
examples/picogame_audio_demo.py |
PWM audio: překrývající se pípnutí přes mixér (picogame_audio.py) |
examples/picogame_scroll_demo.py |
kamera a posouvání: svět 640×480 s pohledem sledujícím hráče (scene.set_view) |
examples/picogame_particles_demo.py |
částicová vrstva: výbuch (A) + fontána (B) s gravitací (pg.Particles) |
demos/picogame_arkanoid.py |
kompletní hra Breakout/Arkanoid: Tilemap cihly + sprite + collide + částice + HUD |
games/squest/code.py |
střílečka ve stylu Seaquest: stav spritů v sprite.data, projektily, collide, částice, ukazatel kyslíku v HUD a tónový zvuk |
Struktura projektu
Sekce “Struktura projektu”lib/ pomocné moduly enginu (picogame_*) -> potřebné zkopíruj do CIRCUITPY/lib/examples/ hry, dema a jejich soubory -> vybraná hra bude code.py v kořenitools/ převodníky grafiky a dat (png2picogame, ...)Nasazení hry na zařízení (pomocné moduly, .mpy a grafika) pokrývá
Spuštění na hardwaru.