FableDevil pro ZX Spectrum Next
7. 9. 2026

V posledních několika dnech se mi povedlo zlomit něco, čemu se věnuji už delší dobu. Vím, těch projektů je nějak moc, ale na druhou stranu je pořád co dělat – a když náhodou není, vytáhnu zase něco, co jsem před několika měsíci odložil stranou. Když jsem byl náctiletý pubescent, hráli jsme na PeCi u mé bývalé přítelkyně Elastomanii. Terénní motorka v ní musela překonat trať, posbírat jahůdky a nakonec se dostat ke kytičce. Vím, takhle to zní skoro infantilně, ale byla to opravdu zábava – hlavně proto, že se motorka snažila aspoň nějak simulovat fyzikální zákony. Občas to samozřejmě dělalo pěknou paseku, ale právě proto nešlo jen držet plný knedlík a nějak se dostat do cíle.

ZX Spectrum Next / fyzika hry

Co všechno počítá ZX Moto

V posledních několika dnech se mi povedlo zlomit něco, čemu se věnuji už delší dobu. Vím, těch projektů je nějak moc, ale na druhou stranu je pořád co dělat – a když náhodou není, vytáhnu zase něco, co jsem před několika měsíci odložil stranou.

Když jsem byl náctiletý pubescent, hráli jsme na PeCi u mé bývalé přítelkyně Elastomanii. Terénní motorka v ní musela překonat trať, posbírat jahůdky a nakonec se dostat ke kytičce. Vím, takhle to zní skoro infantilně, ale byla to opravdu zábava – hlavně proto, že se motorka snažila aspoň nějak simulovat fyzikální zákony. Občas to samozřejmě dělalo pěknou paseku, ale právě proto nešlo jen držet plný knedlík a nějak se dostat do cíle.

Později jsme podobnou hru hráli i na mobilním telefonu. A protože když se mi něco líbí, mám nepříjemný zvyk přemýšlet, jak by to vypadalo na ZX Spectrum Next, vzniká teď ZX Moto. A víte co? Nevypadá to úplně blbě.

V tomhle článku ale nechci psát ani tak o samotné hře. Mnohem zajímavější je, co se děje pod ní – jak funguje fyzika motorky, kola, odpružení, tření, kolize s polygonovým terénem a jak se to celé dá spočítat na Z80N padesátkrát za sekundu. A věřte mi, dost jsem se u toho zapotil a informace hledal, kde se jen dalo.

Na obrazovce je jen malá motorka, dvě kola a několik barevných polygonů. Ve skutečnosti je ale obraz až posledním článkem poměrně dlouhého řetězce výpočtů.

Na obrazovce je malá motorka, dvě kola a několik barevných polygonů. Mohlo by se tedy zdát, že při stisku plynu stačí zvýšit vodorovnou rychlost spritu a při brzdění ji zase snížit. ZX Moto tak ale nefunguje. Obraz je až posledním článkem řetězce. Nejdříve se roztočí kolo, potom se v místě dotyku pneumatiky se zemí spočítá skluz a třecí impuls, síla se přenese přes odpružení do rámu a teprve nové polohy fyzikálních těles určí, kam se nakonec nakreslí sprity. Právě tento přístup dává ZX Motu jeho typický pocit. Motorka není obrázek, který se pohybuje po křivce. Je to malá mechanická soustava, ve které se navzájem ovlivňují dvě kola, rám, pružiny, gravitace a terén. Port na ZX Spectrum Next musí tuto soustavu přepočítat padesátkrát za sekundu, a to bez procesoru s desetinnými čísly.

Tři tělesa místo jednoho spritu

Základem modelu jsou tři samostatně se pohybující části: rám a dvě kola. Rám má polohu, rychlost, úhel a úhlovou rychlost. Každé kolo má vlastní polohu a rychlost, ale také úhel pootočení, rychlost otáčení a dvousložkovou odchylku od svého závěsu. Jen trvalý stav motorky zabírá 92 bajtů, tedy 23 znaménkových 32bitových hodnot. Během výpočtu k nim přibývají další dočasné vektory:

  • poloha závěsu kola vůči středu rámu,
  • odchylka kola od závěsu a její změna,
  • síla pružiny a tlumiče,
  • rameno síly a moment působící na rám,
  • normála a tečna povrchu,
  • rychlost ve směru normály a tečny,
  • skluz pneumatiky, kontaktní impuls a okamžité zatížení kola.

Nejde tedy o jednu „rychlost motorky“. Rám i obě kola mají vlastní rychlost v osách X a Y a kola navíc vlastní rychlost otáčení. To je důvod, proč může zadní kolo hrabat, přední kolo narazit do svahu a rám se přitom ještě pohybovat jiným směrem. Rozměry a hmotnosti vycházejí z původního ZX Mota: poloměr kola je 0,35 metru, rozvor 1,4 metru a jedno kolo váží 10 kilogramů. Pro posuv rámu se počítá 125 kilogramů včetně jezdce. Při rotaci je ale situace jiná. V originálu se jako tuhé těleso otáčí pouze 90kilogramový rám; jezdec je samostatná ragdoll soustava. Také kola nejsou v ODE definována jako ploché disky, ale jako koule. Jejich moment setrvačnosti je proto 0,4·m·r², nikoli obvykle očekávaných 0,5·m·r². Zdánlivě malý rozdíl by změnil rychlost rozjezdu i chování při saltech.

Jeden fyzikální krok

Každý snímek proběhne přibližně tento řetězec:

  1. Z úhlu rámu se získá sinus a kosinus a vypočítají se otočené závěsy kol.
  2. Na rám i kola se přidá gravitace.
  3. Pro obě kola se spočítá pružina, tlumič, reakce na rám a moment síly.
  4. Kola se otestují proti hranám terénu a vyřeší se kontakt a tření.
  5. Zpracuje se náklon hráče, pasivní útlum rotace, plyn nebo brzda.
  6. Omezí se pouze patologické rychlosti a úniky soustavy.
  7. Rychlosti se zintegrují do nových poloh a úhlů.
  8. Zkontroluje se rozvor a případně se znovu opraví kontakt s terénem.
  9. Teprve z výsledných fyzikálních poloh se připraví hardwarové sprity.

Pořadí je důležité. Kdyby se například po omezení rozvoru znovu nezkontroloval terén, mohl by doraz posunout přední kolo dovnitř stoupajícího svahu. Druhý průchod proto opravuje geometrii, ale už podruhé neaplikuje tření. Jinak by byl tentýž kopec uměle dvakrát „lepivý“.

Co se opravdu stane po přidání plynu

Plyn přímo nemění polohu ani vodorovnou rychlost motorky. Přidá úhlovou rychlost hnanému kolu. Při jízdě doprava je to zadní kolo; po otočení motorky doleva se role i znaménko otáčení obrátí. V kontaktu se zemí se porovnávají dvě rychlosti. První je pohyb středu kola po tečně povrchu. Druhá je obvodová rychlost pneumatiky vypočtená z otáčení kola a jeho poloměru. Jejich rozdíl je skluz:

skluz = tečná rychlost středu kola − obvodová rychlost pneumatiky

Je-li kolo roztočené, ale motorka ještě stojí, je skluz velký. Kontakt vytvoří opačně orientovaný třecí impuls, který se snaží skluz zrušit. Impuls současně změní posuvnou rychlost kola a ubere část jeho otáčení. Pohyb kola se přes pružinu přenese do rámu. Rozjezd je tedy výsledkem několika navazujících reakcí, nikoli příkazu „posuň sprite o dva pixely doprava“. Velikost tření navíc není neomezená. Závisí na tom, jak silně odpružení tlačí kolo do povrchu, a přičítá se vlastní váha kola. Odlehčené kolo proto přenese menší sílu a může se protočit. Přesně tečné kolo se stále považuje za kontakt i při nulové hloubce průniku. Bez tohoto detailu kontakt po vysunutí mizel ob snímek, motor dostával střídavě záběr a volnoběh a motorka na mírném svahu hrabala.

Brzda: fyzikální myšlenka a praktický kompromis

Také brzda primárně nepřepisuje rychlost spritu. Tlumením zastavuje rotaci obou kol a hlídá, aby se jejich otáčení při malých hodnotách nepřeklopilo přes nulu do opačného směru. Na zemi se zabrzděná pneumatika opře o povrch a přes tření a odpružení brzdí zbytek motorky. Ve vzduchu kontakt neexistuje, takže brzda zpomaluje pouze otáčení kol a nemá kouzelně zastavit letící rám. Čistě fyzikální varianta ale v redukovaném modelu odhalila problém. Rám o hmotnosti 125 kilogramů dokázal dvě zabrzděná kola o hmotnosti 10 kilogramů vláčet vodorovným odpružením dál. Motorka po zabrzdění stále jela přibližně 0,7 m/s. Proto ZX Moto při skutečném kontaktu se zemí přidává také omezené lineární zpomalení rámu. Je to vědomý kompromis: zachovává rozdíl mezi brzděním na zemi a ve vzduchu, ale nahrazuje část vazeb, které původní ODE získává z podrobnější soustavy těles a omezení.

Proč je kopec víc než nakloněná rovina

Při jízdě do kopce zadní kolo tlačí motorku dopředu, zatímco přední kolo se opírá o šikmou hranu. Kontakt se rozloží do dvou směrů. Normála povrchu brání kolu vjet do země a tečna určuje směr, ve kterém může pneumatika zabírat nebo klouzat. Na strmém přechodu tak přední kolo skutečně klade odpor. Síla se přes jeho závěs vrací do rámu a vytváří také moment, který motorku natáčí. Hráč může klávesami O/P měnit úhlovou rychlost rámu. Program tedy nemá zvláštní pravidlo „na kopci zvedni přední kolo“. Natočí rám, tím se změní poloha obou závěsů a pružiny začnou působit jiným směrem. Přední kolo se odlehčí nebo nadzvedne jako důsledek geometrie a sil. Stejný mechanismus funguje při wheelie, přejezdu hrany i při srovnávání motorky před dopadem. Původní ZX Moto používá pro ovládání náklonu krátký doznívající impuls. Při nižší frekvenci portu však byl jeden impuls buď skoro neviditelný, nebo příliš prudký. ZX Moto proto používá plynulé úhlové zrychlení s omezenou maximální rychlostí. Když hráč O/P nedrží, pasivní rotace si v každém kroku ponechá tři čtvrtiny rychlosti. Motorka si tak neodnese drobnou rotaci ze svahu přes celý skok, ale řízené salto zůstává možné.

Odpružení není animace

Pro každé kolo existuje bod závěsu pevně spojený s rámem. Protože se rám otáčí, musí se tento bod každým krokem otočit pomocí sinu a kosinu. Od polohy závěsu se odečte skutečná poloha kola. Výsledkem je dvousložková deformace q = (qx, qy). Síla závěsu má dvě části:

síla = tuhost pružiny · q + tlumení · změna q

Pružina chce vrátit kolo do klidové polohy. Tlumič odporuje rychlé změně zdvihu, aby soustava po každém kamínku nekmitla. Stejná síla působí na kolo a opačná reakce na rám. Z ramene mezi středem rámu a závěsem se navíc vypočítá moment r × F, takže nestejné stlačení předního a zadního odpružení rám natáčí. Původní tuhost 21 000 a tlumení 205 000 byly navržené pro fyziku běžící na 100 Hz. ZX Spectrum Next zobrazuje 50 snímků za sekundu a dva plné fyzikální kroky se do jednoho snímku nevešly. Použití jednoho dvojnásobně dlouhého kroku se starými hodnotami pružinu rozkmitalo a motorka se někdy vůbec nerozjela. Odpružení proto bylo pro 50 Hz přeladěno na tuhost 12 000 a tlumení 90 000. Poměr a charakter systému zůstaly podobné, ale numericky je stabilnější. Klidový rozdíl mezi rámem a středy kol je 0,55 metru: výška těžiště 0,9 metru minus poloměr kola 0,35 metru. Dřívější zkratka 0,4 metru posazovala jezdce o 15 centimetrů níž a při dopadech dostávala jeho tělo mezi kola.

Dopad, průnik a kolo vystřelené pružinou

Kontakt kola s terénem se řeší kombinací poziční korekce a impulsu. Když je střed kola příliš blízko hrany, nejdříve se posune ven přesně o zjištěnou hloubku průniku. Potom se z rychlosti odstraní pouze složka mířící dovnitř povrchu. Tečná složka zůstane k dispozici pro valení a tření. Poziční oprava je nutná, ale pro tlumič vypadá jako okamžitý skok kola. Pokud by se skok zapsal do historie zdvihu, tlumič by jej v dalším kroku vyhodnotil jako obrovské stlačení, saturoval by a odhodil kolo na opačnou stranu. Vznikl by dvoukrokový limitní cyklus — známé klepání kola sem a tam. Proto se stejná korekce odečte také z uložené hodnoty q. Tlumič reaguje na skutečný pohyb, nikoli na technickou opravu kolize. Další ochrany řeší stavy, které jsou v plynulém solveru ODE přirozené, ale v jednom diskrétním kroku mohou uniknout:

  • rychlost kola je po osách omezena na 35 m/s, aby za krok nepřeskočilo celé

kontaktní pásmo široké jeden průměr kola; běžný pohon dosahuje asi 21 m/s,

  • jednotlivý zdvih je omezen na půl metru, ale při úniku se posouvá rám ke

kolu, nikoli kolo skrz již vyřešený povrch,

  • vzpřímená motorka drží vzdálenost středů kol mezi 0,80 a 1,80 metru,
  • volnější nouzový závěs hlídá, aby rám při extrémním nárazu neopustil obě kola,
  • po zásahu dorazu rozvoru proběhne ještě jedna geometrická kontrola kontaktu.

Rozvorový doraz zachovává průměrnou rychlost obou kol a ruší jen jejich vzájemné sbíhání nebo rozbíhání. Kdyby kola jednoduše převzala rychlost rámu, motorová energie zadního kola by se mohla přenést do předního kola opřeného o svah a vystřelit je vzhůru jako z trampolíny.

Jak kolo najde zem bez odmocnin a dělení

ZX Moto dovoluje obecné polygonové bloky, nikoli jen dlaždice a několik pevných sklonů. Za běhu se proto testuje kružnice kola proti úsečkám hran. Na moderním počítači by nebyl problém normalizovat vektory, dělit a počítat odmocniny. Na Z80 by to bylo příliš drahé, takže velká část práce proběhne už při sestavení levelu. Každá hrana má předpočítaný počáteční bod, směrový vektor, jednotkovou normálu, obrácenou druhou mocninu délky, normály obou koncových bodů a obalový obdélník zvětšený o poloměr kola. Jedna hrana zabírá 60 bajtů. Hrany jsou navíc zařazené do metr širokých košů. Výběr koše je pouze celočíselná část souřadnice X, tedy horní slovo čísla 16.16 — žádné dělení. Za běhu se nejdříve čtyřmi porovnáními levně odmítnou vzdálené hrany. Skalární součin určí, zda nejbližší bod leží uvnitř úsečky, nebo na jednom z jejích konců. Další skalární součin dá podepsanou vzdálenost ve směru normály. Ze všech kandidátů se ponechá nejhlubší kontakt. Ani příprava hran není triviální. Překrývající se bloky se skládají jako sjednocení ploch. Hrany se v průsečících rozdělí a zakryté části se zahodí. Jinak by neviditelná spodní hrana jednoho polygonu mohla vyhrát nad viditelným povrchem druhého a zatlačit kolo dovnitř země.

Čísla bez desetinné čárky

Z80N nemá běžnou jednotku pro výpočty s plovoucí desetinnou čárkou. Fyzika proto používá znaménkovou pevnou řádovou čárku 16.16. Horních 16 bitů je celá část, dolních 16 bitů zlomek. Hodnota 1,0 je uložena jako 65 536. Pozice jsou v metrech, rychlosti v metrech za sekundu, úhly v otáčkách a úhlové rychlosti v otáčkách za sekundu. Úhel v otáčkách je praktická volba. Horní bajt zlomkové části rovnou indexuje 256položkovou tabulku sinu a horní půlbajt určuje jedno ze šestnácti natočení spritu. Radiány by vyžadovaly další převody a dělení. Tabulka sinu používá formát 1.15 a mezi sousedními hodnotami se lineárně interpoluje. Nejdražší operací je násobení. Dvě 32bitová čísla se nejdříve převedou na absolutní hodnoty. Instrukce Z80N mul d,e umí jen 8 × 8 bitů, takže plný součin vznikne ze šestnácti dílčích součinů. Ty se sčítají po sloupcích podle své binární váhy do osmibajtového, tedy 64bitového akumulátoru:

32bitový operand × 32bitový operand → 64bitový mezivýsledek
64bitový mezivýsledek >> měřítko    → 32bitový výsledek

Pro běžné násobení dvou hodnot 16.16 se mezivýsledek posune o 16 bitů. Ne všechny konstanty se však do 16.16 vejdou. Tlumič může být příliš velký a dt / hmotnost naopak tak malý, že by se zaokrouhlil téměř na nulu. Konstanty se proto ukládají společně s počtem bajtů, o které se má 64bitový součin posunout. Jedna rutina tak zvládne například 24.8, 16.16 i 8.24 a význam konstanty zůstane přesný. Záporné výsledky se zaokrouhlují dolů stejně jako při aritmetickém posunu. Pokud se při posunu zahodily nenulové bity, musí se záporná absolutní hodnota ještě zvětšit o jedna a teprve potom převést dvojkovým doplňkem. Bez této drobnosti by Python reference a Z80 v záporných silách postupně ujížděly. Kontakty často násobí hodnoty, jejichž nejvyšší bajt je nulový. V takovém případě se použije rychlejší cesta 24 × 24 bitů s devíti místo šestnácti dílčích součinů. Průběžné síly a momenty se také ořezávají do bezpečných mezí. Python má prakticky neomezená celá čísla, ale Z80 by například součet 2,6 miliardy nebo moment 3,7 miliardy tiše přetočil přes znaménko. Referenční model proto používá stejné ořezy jako assembler.

Terén: velký obraz jako kruhové okno

Herní terén se kreslí do vrstvy Layer 2 v režimu 320 × 256 pixelů a 8 bitů na pixel. Celý buffer zabírá 81 920 bajtů v pěti 16KB bankách. Paměť je pro tento režim uspořádaná po sloupcích: všech 256 pixelů jednoho sloupce leží za sebou a spodní bajt adresy je přímo souřadnice Y. Tomu odpovídá i formát levelu. Polygonový terén se při buildu rasterizuje do vertikálních spanů (y0, y1). Jeden sloupec obvykle obsahuje několik běhů „obloha, hrana, zem“. Renderer pouze najde seznam spanů a zapisuje souvislé bajty. Nemusí za běhu pro každý pixel testovat polygon. Buffer se chová jako torus. Souřadnice světa X se mapuje na X mod 320 a Y se obalí přes spodní bajt adresy. Kamera posouvá hotový obraz hardwarovými scroll registry; procesor překresluje jen nově odkryté části. Vodorovný směr je levný, protože nový sloupec je jeden souvislý blok paměti. Svislý směr je mnohem dražší: jeden řádek znamená navštívit všech 320 sloupců a opakovaně přepínat banky. Překreslení celého svislého pruhu původně stálo 139 % jednoho snímku. Řešením je skrytý lem široký 32 pixelů. Viditelná plocha je díky tomu klasických 256 × 192 pixelů, zatímco mimo ni může renderer připravovat data dopředu. Když kamera ujede o osm řádků, začne se kreslit pás šestnácti nových řádků. Práce se rozdělí po čtyřiceti sloupcích do osmi snímků. Hardwarový scroll běží plynule, jen obsah skryté rezervy vzniká po dávkách. Cena klesla přibližně na 12,8 % v běžném a 30,5 % v nejhorším snímku. Kamera má navíc svislé pásmo klidu. Kdyby sledovala každý milimetrový pohyb odpružení, posouvala by celý svět o jeden či dva pixely sem a tam a klidná rovina by vypadala jako zemětřesení.

LoRes pozadí pod průhlednou oblohou

Stromy a vzdálené pozadí nejsou součástí scrollovaného terénu. Leží v LoRes vrstvě o rozlišení 128 × 96 pixelů, která se při zobrazení roztáhne na herní plochu 256 × 192. Používá 4 bity na pixel, tedy šestnáct barev RGB332, a celý framebuffer zabírá jen 6 144 bajtů. Layer 2 leží nad ní. Barva používaná pro oblohu se během hry nastaví jako globálně průhledná, takže v prázdných částech terénní vrstvy prosvítá LoRes obrázek. Zem a její světlá hrana zůstávají neprůhledné. Výsledkem je statické pozadí bez nutnosti kopírovat ho při každém scrollu terénu. Zdrojový obrázek se převádí offline: zachová se poměr stran, zmenší se metodou nearest neighbour, zredukuje na šestnáct barev a zabalí po dvou pixelech do bajtu. I zde se muselo počítat s hardwarem. RGB332 má pro modrou jen dva bity; už hodnota jedna znamená třetinu plné modré, takže zemitá barva s nenulovou modrou snadno skončí fialová. Paralaxový scroll při pohybu kamerou byl již skoro zadarmo - hardware Nextu je na to stavěný...

Miniatury levelů

Každý level má předem vytvořenou miniaturu 256 × 64 pixelů. Stejně jako herní terén je uspořádaná po sloupcích, ale používá jen 4 bity na pixel. Zabere přesně 8 KB, tedy jednu paměťovou stránku. Obsahuje celý profil tratě a barevné značky startu, cíle a jahod. Při změně výběru v menu se příslušná stránka namapuje do stejného adresního okna a data se pouze rozbalí po dvojicích pixelů přímo do Layer 2. Za běhu se nic neškáluje, nehledají se hrany polygonů a nerasterizuje se terén. Statické texty menu si ponechávají své sprite sloty, takže při listování neprobliknou; překreslí se jen miniatura a proměnné údaje. Každý zařazený level vlastní čtyři 8KB stránky: dvě pro spany a entity, jednu pro kolizní hrany a jednu pro miniaturu. MMU vždy namapuje vybranou sadu na pevné adresy, takže renderer ani fyzika nemusí vědět, kde v 2MB paměti level skutečně leží.

Sprity jsou jen vizualizace fyziky

Kola, rám, jahody, cíl, HUD a text se kreslí hardwarovými sprity. Terénní buffer se kvůli nim nemusí mazat ani obnovovat. Všech 128 čtyřbitových patternů zabírá 16 KB sprite paměti a po startu zůstává rezidentních. Kolo i rám mají šestnáct předkreslených natočení po 22,5 stupně. Úhel v otáčkách 16.16 dovoluje získat index patternu pouhým výběrem čtyř bitů. Jízda doleva používá stejné obrázky a hardwarové zrcadlení. Protože zrcadlení obrací i smysl rotace, musí se index úhlu současně negovat. Rychle se točící kolo může mezi dvěma snímky přeskočit několik natočení a vypadat, že se paprsek pohybuje náhodně dozadu. Zobrazený pattern proto sleduje fyzikální úhel po nejkratší kruhové cestě, ale nejvýše o jeden krok za snímek. Je to pouze obrazový filtr; otáčky, trakce ani kontakt se nemění. Podobně se potlačuje jednobodové svislé přeskakování kola způsobené převodem subpixelového zdvihu na celé pixely. Fyzika zůstává přesná a klidnější je jen výsledný obraz.

Herní pravidla stojí vedle fyziky

Jahody, cíl, smrt a čas se vyhodnocují až po fyzikálním kroku a nevracejí do něj žádnou sílu. Dotyk jahody se testuje kružnicemi proti oběma kolům a hlavě. Porovnávají se druhé mocniny vzdáleností, takže není potřeba odmocnina. Původní jezdec má ragdoll a hlavu 1,3 metru nad rámem. Port zobrazuje jediný 16×16 sprite jezdce, proto používá kolizní bod hlavy tam, kde je hlava skutečně nakreslená. Ve vzpřímené poloze se běžné stlačení odpružení nepovažuje za pád na hlavu; boční a převrácený náraz zůstává smrtelný. Je to další kompromis mezi původním modelem a tím, co hráč na obrazovce skutečně vidí. Také zvuk čte fyziku místo umělého „stavu motoru“. Výška tónu sleduje úhlovou rychlost hnaného kola, plyn přidá hlasitost a vyšší otáčky, brzdový šum se ozve jen při kontaktu a smysluplné rychlosti a rána odpružení se spustí podle změny qy. Zvuk tak reaguje na prokluz, let i tvrdý dopad přirozeně společně s obrazem.

Co bylo nutné obětovat

ZX Moto není doslovné přenesení solveru ODE. Je to pečlivě zvolený redukovaný model, který zachovává vztahy důležité pro hru:

  • původních 100 Hz nahradil jeden přeladěný krok na každý 50Hz snímek,
  • ragdoll jezdce nahradil jeden rám a viditelný kolizní bod hlavy,
  • brzdění dostalo na zemi omezenou pomoc pro těžký rám,
  • diskrétní kontakty potřebují bezpečnostní limity rychlosti, zdvihu a rozvoru,
  • obecné polygonové levely se předpočítávají do spanů, hran a prostorových košů,
  • svislý renderer vyměnil část rozlišení za skrytý lem a dávkovanou práci,
  • obraz kol používá jemné filtry, ale fyzikální stav se kvůli vzhledu nemění.

Paměť je stejně tvrdý limit jako čas. Hlavní kód musí zůstat v jediné 16KB stránce od adresy $8000 do $BFFF; v aktuálním buildu končí na $BFF8, tedy jen osm bajtů před hranicí. Levely, hudba, pozadí, sprity a kolizní data proto žijí v dalších bankách a podle potřeby se mapují do adresních oken.

Jak se pozná, že matematika stále sedí

Napsal jsem Z80 self-test, který porovnává stovky aritmetických vektorů a celé stavy motorky bit po bitu — nejen výslednou polohu na obrazovce. Po spuštění v emulátoru musí doběhnout na zelenou obrazovku (chápete - zelená = dobrá) a vykreslit pruhy potvrzující, že jednotlivé sady testů skutečně proběhly. Aktuální test ověřuje 184 případů obecného násobení, 139 násobení s vlastním posunem a 131 hodnot sinu. Fyziku kontroluje ve čtyřech bodech letu bez kontaktů, ve čtyřech bodech pádu na skutečný terén a potom v 80 po sobě jdoucích krocích téhož pádu. Následují samostatné regrese rozvoru, úniku rámu, mezní rychlosti, rozjezdu do kopce a šikmého dopadu. Pocit z jízdy se musí ladit hraním, ale matematika pod ním nesmí být otázkou dojmu. Když se změní jediný bit ve výpočtu síly, kontaktu nebo integrace, test ukáže, ve kterém kroku a ve kterém poli fyzikálního stavu se obě implementace rozešly.

ZX Moto na obrazovce působí jednoduše, ale pod každým snímkem běží řetězec vektorových výpočtů, kontaktů, impulsů, paměťového bankování a hardwarového scrollu. Plyn roztáčí kolo. Tření mění jeho pohyb. Odpružení táhne rám. Svah vrací sílu vlastní normálou. Náklon změní geometrii závěsů. Kamera pouze sleduje výsledek a sprity ho nakonec ukážou. Právě proto motorka při rozjezdu, brzdění, skoku a jízdě do kopce nepůsobí jako obrázek posouvaný programem. V mezích osmibitového stroje se opravdu snaží chovat jako motorka. A ano, začínám trpět nedostatkem spánku... takhle to dál nejde ;) Tohle vše jsem nevymyslel jen já. Na githubu můžete najít zdrojové kódy XMoto, takže se tam dá dohledat to, jak se pracuje s fyzikou... ale přepracování do assembleru Z80N je úplně jiná disciplína. A ano, využíval jsem maximalné rozšiřující sady instrukcí procesoru, který je v Nextu - bez nich bych to opravdu nedal do tohoto stavu. Popravdě měl jsem pár krizových chvil, kdy jsem se chtěl na vše vykašlat, ale jsem rád, že jsem se po čase vždy k tomuto projektu vrátil.

zxmoto-big

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *