Obsah
1. Grafický subsystém herní konzole Atari 2600
2. Skládání obrazu herního světa ze šesti typů objektů
3. Podrobnější informace o grafických objektech
4. Jak jsou tedy vykresleny skutečné herní scény?
5. Využití možností emulátoru Stella pro „debugging“ grafiky
6. Práce s jednotlivými grafickými objekty v Batari BASICu
10. Priorita zobrazení střel vůči pozadí i střel vůči sobě
12. Míč (ball), šířka vykreslení míče
13. Shrnutí a ukázka z třetího článku – relativně složité demo využívajících necelé 2kB ROM
14. Repositář s demonstračními příklady
1. Grafický subsystém herní konzole Atari 2600
V úvodní kapitole si ve stručnosti popíšeme princip generování grafického obrazu na herní konzoli Atari 2600, protože se jedná o vlastnost, která pravděpodobně nejvíc ovlivnila její úspěch (a na druhou stranu zapříčinila velké bolesti hlavy programátorům, kteří museli tento systém do nejmenších detailů pochopit – to ovšem není při použití Batari BASICu přesně náš příklad). Vzhledem k tomu, že kapacita operační paměti konzole Atari 2600 byla rovna pouhým 128 bajtům (byl zde mimochodem umístěn i zásobník), bylo zřejmé, že v tak malé paměti není možné vytvořit plnohodnotný framebuffer (obrazovou paměť), a to ani v případě, že by byl černobílý a měl nepatrné rozlišení. Steve Mayer a Ron Milner, kteří navrhovali prototyp této herní konzole, se tedy rozhodli, že obraz bude generován přímo v průběhu zobrazování herní scény na obrazovce monitoru.
Obrázek 1: Obraz generovaný čipem TIA s uvedením přibližného časování.
O generování obrazu se staral čip nazvaný TIA (Television Interface Adaptor), který využíval data dodávaná programem (většinou nějakou hrou) a ukládaná do řídicích režimů čipu TIA. Teoreticky je sice možné přímé řízení intenzity elektronového paprsku (či trojice paprsků u barevné obrazovky), to by však bylo realizovatelné pouze v případě velmi přesného časování – i malé časové odchylky při změně barvy paprsku by totiž znamenaly, že se jednotlivé obrazové řádky navzájem posunou, nehledě na to, že výpočetní výkon MOS 6507 nebyl pro tento účel ani zdaleka dostatečný).
Obrázek 2: Barvová paleta herní konzole Atari 2600 při použití televizního systému NTSC. Emulátor Stella podporuje jak NTSC, tak i PAL, NTSC přitom nabízí větší paletu barev.
Obvod TIA vytvářel všechny potřebné signály pro televizor, který zobrazoval 60 půlsnímků (v tomto odstavci popisuji původní verzi určenou pro televizní normu NTSC; PAL má odlišné časování i frekvence). Každý půlsnímek obsahoval 262 obrazových řádků, přičemž 192 řádků bylo viditelných, tři řádky byly použity pro vyslání signálu vertikální synchronizace, 37 řádků bylo využito pro vertikální zatemnění (vertical blank) a zbylých 30 řádků bylo většinou taktéž zatemněných, protože u některých televizorů již tyto řádky ležely mimo zobrazitelnou plochu (jedná se o takzvaný overscan, který ovšem bylo možné využít). Každý obrazový řádek (scanline) se skládal z 228 pixelů vykreslených v 76 strojových cyklech (frekvence krystalu byla dělena třemi). Z oněch 228 pixelů jich bylo viditelných pouze 160, ve zbývající době totiž probíhal návrat elektronového paprsku a taktéž zobrazení okrajů (horizontal blank).
Obrázek 3: Hra Outlaw se dočkala konverze snad na všechny počítačové platformy. Její princip je jednoduchý a přitom se jedná o zábavnou hru. Velikost ROM s touto hrou je pouze 2048 bajtů.
Úkolem každého programátora tedy bylo vhodně měnit obsah řídicích registrů čipu TIA takovým způsobem, aby tento čip zobrazil smysluplnou obrazovou informaci v imaginární bitmapě o rozměrech 160×192 pixelů. Pro každý snímek ovšem bylo k dispozici přibližně pouze 15000 strojových cyklů, v nichž se musela stihnout provést jak vykreslovací rutina, tak i vlastní algoritmus hry (posun hráče, posun střel, výpočet skóre atd. atd.). Tedy – úkol nikoli pro pojídače koláčů, ale pro skutečné programátory.
Obrázek 4: Snímek ze hry Combat při souboji dvou tanků na volném území (opět se jedná o hru uloženou v ROM s pouhými 2048 bajty).
2. Skládání obrazu herního světa ze šesti typů objektů
Každý obrazový řádek složený, jak jsme si již ostatně řekli v předchozí kapitole, ze 160 viditelných pixelů, byl pomocí čipu TIA generován na základě pouhé šestice údajů – horizontální pozice takzvaného hráče 0, pozice hráče 1 (jednalo se o klasické osmipixelové sprity, jejichž horizontální šířka mohla být vynásobena dvěma či čtyřmi, a které se mohly 2× či 3×na jediném řádku opakovat), pozice střely 0, pozice střely 1 (jednopixelové sprity, opět s volitelnou šířkou a barvou příslušného hráče), pozice míče/ball (jednopixelový sprite s možností vertikálního posunu o jeden řádek) a konečně herního pole/playfield.
Obrázek 5: Hra Battlezone ve variantě určené pro herní konzoli Atari 2600 patřila mezi první hry, které se snažily navodit iluzi trojrozměrného prostoru. Zajímavé je, že původní „automatová“ verze této hry používala vektorový displej a traduje se, že existovala i speciální verze pro armádu USA (jednalo by se tak o jeden z prvních digitálních trenažérů).
Herní pole bylo reprezentováno největším objemem dat – 20bitovým vzorkem, který mohl být v pravé polovině obrazovky horizontálně zrcadlen nebo pouze zopakován – horizontální rozlišení pozadí je tedy rovno pouze 40 pixelům, tj. jeho pixely mají oproti hráčům čtyřnásobnou šířku. Programátor přitom mohl před vykreslením každého obrazového řádku změnit horizontální pozice hráčů, střel i míče, modifikovat jejich barvu, popř. i bitový vzorek hráčů a herního pole; navíc bylo možné určit priority zobrazení. Všechny změny byly prováděny zápisem do řídicích registrů čipu TIA, například herní pole bylo uloženo ve třech osmibitových registrech.
Obrázek 6: Nechvalně proslulá „nehratelná“ hra E.T. určená pro herní konzoli Atari 2600.
Výše naznačený způsob generování rastrové grafiky sice na první pohled vypadá složitě (minimálně kvůli nárokům na přesnost časování při zápisu do jednořádkového bufferu pozadí), na druhou stranu však programátorům, kteří překonali prvotní potíže, přinášel poměrně velkou flexibilitu (osobně si myslím, že mnohem větší flexibilitu, než dnešní rigidní framebuffery :-). Zatímco jakákoli změna ve framebufferu (obrazové paměti) většinou znamenala nutnost přesunu relativně velkých bloků paměti, byla tvorba podobného efektu na systému bez framebufferu velmi jednoduchá a neznamenala větší zátěž pro mikroprocesor, než při generování statického obrázku. Proto jsou například hry určené pro herní konzoli Atari 2600 (která tímto systémem tvorby grafiky disponovala jako jeden z mála široce rozšířených systémů s mikroprocesorem) mnohdy plné pohybujících se objektů, protože mikroprocesor byl zatížen prakticky stejně jak při neustálém vytváření jedné neměnné scény, tak i při tvorbě scény, ve které se všechny objekty pohybují.
Obrázek 7: Další režim hry Combat – soubor dvou dvouplošníků.
Obrázek 8: Úvodní obrazovka hry Breakout je současně i jedinou obrazovkou ve hře. Větší počet barev evidentně pro čip TIA nepředstavuje problém.
3. Podrobnější informace o grafických objektech
V následující tabulce jsou pro přehled vypsány základní informace o všech šesti grafických objektech použitých pro postupné vykreslování obrazu na televizoru. K těmto objektům jsem ještě přidal sedmý objekt – pozadí. Tento objekt je definován pouze vybranou barvou a nikoli bitovým vzorkem (a jak jeho název napovídá, vždy se nachází až za ostatními objekty):
# | Typ objektu | Orig.název | Objem paměti | Šířka reprezentovaná jedním bitem |
---|---|---|---|---|
1 | Pozadí | Background | 0 bitů | × |
2 | Hrací plocha | Playground | 20 bitů | 4× základní šířka pixelu |
3 | Míč | Ball | 1 bit | 1×, 2×, 4×, 8× šířka pixelu |
4 | Hráč 0 | Player 0 | 8 bitů | 1×, 2×, 4× šířka pixelu |
5 | Střela 0 | Missile 0 | 1 bit | 1×, 2×, 4×, 8× šířka pixelu |
6 | Hráč 1 | Player 1 | 8 bitů | 1×, 2×, 4× šířka pixelu |
7 | Střela 1 | Missile 1 | 1 bit | 1×, 2×, 4×, 8× šířka pixelu |
Obrázek 9: Jedna z variant herní konzole Atari 2600.
Ve druhé tabulce jsou vypsány vlastnosti jednotlivých grafických objektů, které bylo možné měnit zápisem vhodných hodnot do řídicích registrů čipu TIA:
# | Typ objektu | Orig.název | Volba barvy | Další možnosti |
---|---|---|---|---|
1 | Pozadí | Background | ano | × |
2 | Hrací plocha | Playground | pro jedničkové bity | opakování či zrcadlení v pravé polovině obrazu |
3 | Míč | Ball | = barva hrací plochy | posun, relativní posun, vertikální posun o jeden řádek, změna velikosti |
4 | Hráč 0 | Player 0 | pro jedničkové bity | posun, změna šířky, opakování 2×, 3× |
5 | Střela 0 | Missile 0 | = barva hráče 0 | -//- |
6 | Hráč 1 | Player 1 | pro jedničkové bity | posun, změna šířky, opakování 2×, 3× |
7 | Střela 1 | Missile 1 | = barva hráče 1 | -//- |
Obrázek 10: Další varianta herní konzole Atari 2600.
4. Jak jsou tedy vykresleny skutečné herní scény?
Základem každé hry nebo dema určeného pro herní konzoli Atari 2600 je takzvaný (vykreslovací) kernel. Jedná se o podprogram, který pro každý vykreslovaný řádek naplní obsah řídicích registrů čipu TIA takovým způsobem, aby se celý řádek vykreslil podle potřeb programátora. Ve skutečnosti však nebývá snadné provést všechny výpočty pro každý programový řádek zvlášť, protože pro každý řádek je k dispozici pouhých 76 strojových cyklů (228/3) a instrukce mnohdy trvají 2 až 3 cykly, některé instrukce však i šest cyklů. Proto mnohé kernely modifikují registry každý druhý obrazový řádek a tudíž mají delší čas „na rozmyšlenou“. Tento princip je podporován i čipem TIA, který některé objekty dokáže vykreslit se zpožděním jednoho obrazového řádku. V extrémním případě – pokud nedojde ke změně žádného řídicího registru v průběhu vykreslení snímku – se každý objekt zobrazí na všech obrazových řádcích stejně – stejný tvar, stejné sloupce.
Podívejme se na příklad kernelu použitého ve hře Pitfall:
Obrázek 11: Herní scéna ze hry Pitfall.
Nyní se podívejme, jak vypadá herní scéna ve chvíli, kdy budeme ignorovat modifikace barvových registrů a každému grafickému objektu přiřadíme konstantní barvu. Hráč v herní scéně je vykreslen hráčem číslo 1, ostatní protivníci hráčem číslo 0. Zajímavé je, že hráč číslo 0 i 1 je navíc využit i pro dokreslení stromů (rozvětvení pod listy), aby se odstranilo omezené horizontální rozlišení herního pole. Zajímavé je, že se zde tvůrci konkrétně na této obrazovce obešli bez použití střel. Povšimněte si taktéž liány. Ta je vykreslena jako sekvence míčů (ball), přičemž se postupně mění horizontální poloha těchto grafických objektů (což je vlastně mnohem rychlejší, než kdyby se měl neustále překreslovat framebuffer):
Obrázek 12: A takto jsou využity jednotlivé grafické objekty.
Podobně můžeme prozkoumat herní scénu ze hry River Raid:
Obrázek 13: Herní scéna ze hry River Raid.
V „ladicím“ zobrazení můžeme vidět, že všechny objekty ve scéně (kromě samotného hráče) jsou zobrazeny jako jediný sprite. Objekty jsou z tohoto důvodu postaveny takovým způsobem, že se nikdy vertikálně nepřekrývají – na každém obrazovém řádku je jen jediný objekt. Míč je použit pro zobrazení ukazatele paliva, střely pak pro skutečné střely (zde nejsou vidět, protože nedokážu udělat screenshot a současně držet „trigger“ joysticku):
Obrázek 14: A takto jsou využity jednotlivé grafické objekty.
5. Využití možností emulátoru Stella pro „debugging“ grafiky
V předchozí kapitole jsme mohli vidět, že herní scénu lze v emulátoru Stella zobrazit dvěma různými způsoby – buď tak, jako ji vidí běžný hráč (uživatel) herní konzole a poté způsobem, který jednotlivé objekty, z nichž se herní svět skládá, zobrazí každý odlišnou barvou. Navíc je i herní pole rozděleno na tři části, protože je definováno trojicí registrů. Tento způsob zobrazení tedy zcela ignoruje zápisy do registrů COLUPF, COLUP0 a COLUP1 a dovoluje nám nahlédnout do tajností tvorby herních scén, které mnohdy překvapují počtem barev a/nebo počtem pohyblivých objektů ve scéně. Podívejme se nyní na některé typické příklady.
Obrázek 15: Scéna ze hry H.E.R.O. jak ji vidí hráč.
„Ladicí“ způsob zobrazení stejné herní scény:
Obrázek 16: A takto je scéna rozdělena na sprity a herní pole.
Zajímavé bude zjistit, jak jsou zobrazeni protivníci ve slavné hře Space Invaders:
Obrázek 17: Slavní Space Invaders.
Tajemství je jednoduché – každý sprite je vždy zobrazen třikrát, což je ostatně podporováno přímo čipem TIA:
Obrázek 18: Jednotliví útočníci jsou tvořeni dvojicí spritů. Zajímavé je, že skóre je zobrazeno změnou herního pole.
Vraťme se ještě jednou ke hře Pitfall, tentokrát k jiné obrazovce:
Obrázek 19: Další slavná hra: Pitfall.
Jak klády, tak i zeď je tvořena stejným spritem, pokaždé ovšem s odlišnou barvou:
Obrázek 20: Ve scéně se používá pozadí, dvojice spritů a žebřík je kupodivu zobrazen s využitím míče.
Ve hře Ms. Pacman se pohybuje pět na sobě nezávislých objektů, které se dokonce mohou překrývat:
Obrázek 21: Ms.Pacman s pěti pohybujícími se objekty, každým v odlišné barvě.
„Ladicí“ způsob zobrazení stejné herní scény:
Obrázek 22: Ve skutečnosti se používají pouze dva sprity, u nichž se vhodně mění tvar a barva. Body, po jejichž konzumaci je možné duchy honit, jsou zobrazeny s využitím míčů.
A konečně jeden z prvním leteckých simulátorů viditelný z pozice pilota:
Obrázek 23: Air Raiders jsou pravděpodobně první hrou s naklonitelným horizontem.
„Ladicí“ způsob zobrazení stejné herní scény ukazuje tajemství nakloněného horizontu:
Obrázek 24: Stella odhalí, jak je tento horizont vytvořen – vhodným nastavením herního pole.
6. Práce s jednotlivými grafickými objekty v Batari BASICu
Batari BASIC obsahuje několik grafických kernelů. Prozatím budeme používat základní kernel, v němž se přímo i nepřímo pracuje se všemi šesti grafickými objekty čipu TIA. Vlastnosti těchto objektů se nastavují buď přístupem do řídicích registrů a/nebo nastavením speciálních proměnných a v případě pozadí i hráčů použitím specializovaných konstrukcí. Prakticky vše, co potřebujeme znát pro zobrazení grafických scén, je shrnuto v následující tabulce:
Typ grafického objektu | Barva | Další řídicí registry | Speciální proměnné/konstrukce |
---|---|---|---|
pozadí | COLUBK | × | × |
herní pole | COLUPF | PF0, CTRLPF | Playground |
hráč 0 | COLUP0 | NUSIZ0, REFP0, CTRLPF | player0, player0×, player0y |
hráč 1 | COLUP1 | NUSIZ1, REFP1, CTRLPF | player1, player1×, player1y |
střela 0 | COLUP0 | NUSIZ0, CTRLPF | missile0×, missile0y, missile0height |
střela 1 | COLUP1 | NUSIZ1, CTRLPF | missile1×, missile1y, missile1height |
míč | COLUPF | CTRLPF | ballx, bally, ballheight |
7. Herní pole (playfield)
S konceptem herního pole jsme se již seznámili v úvodním článku o Batari BASICu. Připomeňme si, že při použití standardního kernelu Batari BASICu je možné pole definovat bitmapou o rozměrech 32×11 „pixelů“, přičemž šířka pixelů herního pole je čtyřikrát větší, než šířka hráčů nebo střel (při použití základního zvětšení); toto rozlišení ve směru horizontální osy není možné nijak měnit. V předchozím textu jsme si však řekli, že herní pole je definováno 20bitovým vzorkem, který se může buď 2× opakovat nebo být zrcadlen okolo vertikální osy, což znamená, že horizontální rozlišení by mělo být rovno 40 pixelům a nikoli jen 32 pixelům. Ovšem kvůli omezení vykreslovacího kernelu (časování atd.) je využito jen 80% herního pole, což přesně odpovídá 32 pixelům. Výška resp. přesněji řečeno vertikální rozlišení herního pole, je taktéž velmi malé kvůli časování v kernelu (čistě teoreticky by zde bylo možné dosáhnout 160 řádků).
Víme již, že bitmapa herního pole se specifikuje přes deklaraci playfield; barva herního pole se pak nastavuje řídicím registrem COLUPF:
playfield: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ................................ ................................ ...XXXX....XXX.....XXX...XXXXX.. ...X...X..X...X...X...X....X.... ...XXXX...X...X...X...X....X.... ...X.X....X...X...X...X....X.... ...X..X...X...X...X...X....X.... ...X...X...XXX.....XXX.....X.... ................................ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX end mainloop COLUPF = $14 drawscreen goto mainloop
Výsledná scéna po vykreslení v emulátoru by měla vypadat následovně:
Obrázek 25: Scéna, v níž je použito pouze herní pole.
8. Střely (missiles)
Střely neboli missiles jsou dalším grafickým objektem, přičemž na rozdíl od herního pole jsou střely na obrazovce reprezentovány čtvercem či obdélníkem (v limitním případě jediným pixelem) s měnitelnou polohou na řádku. Šířka střel může být nastavena na jeden pixel, dva pixely, čtyři pixely či dokonce na osm pixelů (připomeňme, že na obrazovém řádku se 160 viditelnými pixely). Tuto šířku lze specifikovat v řídicím registru NUSIZ0 pro první střelu a NUSIZ1 pro druhou střelu. Barva střel je řízena obsahem řídicích registrů COLUP0 a COLUP1, což jinými slovy znamená, že střely mají stejnou barvu jako hráči (první střela má barvu totožnou jako první hráč, druhá střela jako hráč druhý). Dále lze ve specializovaných proměnných nazvaných missileNx a missileNy nastavit pozici střely na obrazovce (N=0 nebo N=1) a proměnná missileNheight obsahuje výšku střely N.
V následujícím demonstračním příkladu je nad herním polem zobrazena první střela, jejíž rozměry jsou nastaveny na 8×8 pixelů (má tedy šířku osmi pixelů a opakuje se na osmi po sobě jdoucích obrazových řádcích). Povšimněte si, že obsah řídicích registrů je zapotřebí v herní smyčce neustále obnovovat, což programu ubírá několik strojových cyklů z dostupných přibližně 5000 cyklů na snímek:
playfield: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ................................ ................................ ...XXXX....XXX.....XXX...XXXXX.. ...X...X..X...X...X...X....X.... ...XXXX...X...X...X...X....X.... ...X.X....X...X...X...X....X.... ...X..X...X...X...X...X....X.... ...X...X...XXX.....XXX.....X.... ................................ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX end missile0x = 64 missile0y = 64 missile0height = 8 mainloop NUSIZ0 = $30 COLUPF = 14 COLUP0 = $1E drawscreen goto mainloop
Výsledek by měl vypadat následovně:
Obrázek 26: Herní scéna s pozadím, herní plochou a jedinou střelou.
Nic nám však nebrání zobrazit si obě střely, každou odlišnou barvou. Povšimněte si, že šířka střel je nastavena na jeden pixel a výška na osm pixelů, takže výsledkem by měly být svislé čárky:
playfield: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ................................ ................................ ...XXXX....XXX.....XXX...XXXXX.. ...X...X..X...X...X...X....X.... ...XXXX...X...X...X...X....X.... ...X.X....X...X...X...X....X.... ...X..X...X...X...X...X....X.... ...X...X...XXX.....XXX.....X.... ................................ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX end missile0x = 80-20 missile0y = 20 missile0height = 8 missile1x = 80+20 missile1y = 20 missile1height = 8 mainloop NUSIZ0 = $0 NUSIZ1 = $0 COLUPF = 14 COLUP0 = $1E COLUP1 = $4E drawscreen goto mainloop
Výsledek by měl v tomto případě vypadat takto:
Obrázek 27: Herní scéna s pozadím, herní plochou a oběma střelami.
9. Šířka vykreslování střel
Šířka střel se nastavuje v horních bitech řídicích registrů nazvaných NUSIZ0 (pro první střelu) a NUSIZ1 (pro střelu druhou). Existují čtyři podporované šířky střel, jak je to ostatně patrné z následující tabulky:
NUSIZ0/NUSIZ1 | Stručný popis |
---|---|
$0× | střela s šířkou jednoho pixelu |
$1× | střela s šířkou dvou pixelů |
$2× | střela s šířkou čtyř pixelů |
$3× | střela s šířkou osmi pixelů |
Úprava předchozího příkladu pro střely s šířkou dvou pixelů by tedy mohla vypadat následovně:
mainloop NUSIZ0 = $10 NUSIZ1 = $10 COLUPF = 14 COLUP0 = $1E COLUP1 = $4E drawscreen goto mainloop
S výsledkem:
Obrázek 28: Herní scéna s pozadím, herní plochou a oběma střelami.
Úprava předchozího příkladu pro střely s šířkou čtyř pixelů:
mainloop NUSIZ0 = $20 NUSIZ1 = $20 COLUPF = 14 COLUP0 = $1E COLUP1 = $4E drawscreen goto mainloop
Výsledek je tentokrát odlišný:
Obrázek 29: Herní scéna s pozadím, herní plochou a oběma střelami.
Úprava předchozího příkladu pro střely s šířkou osmi pixelů:
mainloop NUSIZ0 = $30 NUSIZ1 = $30 COLUPF = 14 COLUP0 = $1E COLUP1 = $4E drawscreen goto mainloop
Výsledek získaný po spuštění tohoto demonstračního příkladu:
Obrázek 30: Herní scéna s pozadím, herní plochou a oběma střelami.
10. Priorita zobrazení střel vůči pozadí i střel vůči sobě
Nastavením jednoho bitu řídicího registru nazvaného CTRLPF (s ním jsme se již setkali) lze řídit, zda se mají střely a současně i hráči zobrazit před herním polem či za ním. Toto chování se ovlivňuje třetím bitem registru CTRLPF. Ukažme si vliv tohoto bitu na způsob vykreslení herní scény. Nejdříve zobrazíme herní pole a dvojici střel, které částečně herní pole překrývají:
playfield: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ................................ ................................ ...XXXX....XXX.....XXX...XXXXX.. ...X...X..X...X...X...X....X.... ...XXXX...X...X...X...X....X.... ...X.X....X...X...X...X....X.... ...X..X...X...X...X...X....X.... ...X...X...XXX.....XXX.....X.... ................................ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX end missile0x = 80-20 missile0y = 28 missile0height = 8 missile1x = 80+20 missile1y = 28 missile1height = 8 mainloop NUSIZ0 = $30 NUSIZ1 = $30 COLUPF = 14 COLUP0 = $1E COLUP1 = $4E drawscreen goto mainloop
Ze zobrazeného výsledku je patrné, že střely jsou zobrazeny před herním polem, tedy mají vyšší prioritu:
Obrázek 31: Herní pole, před nímž jsou zobrazeny střely.
Chování grafických objektů při vykreslování můžeme jednoduše modifikovat, a to konkrétně nastavením třetího bitu řídicího registru CTRLPF na jedničku (tedy namísto hodnoty 1 zde bude uložena hodnota 5):
mainloop CTRLPF = $05 NUSIZ0 = $30 NUSIZ1 = $30 COLUPF = 14 COLUP0 = $1E COLUP1 = $4E drawscreen goto mainloop
Nyní bude scéna s naprosto stejnými grafickými objekty zobrazena odlišně:
Obrázek 32: Herní pole, za nímž jsou zobrazeny střely.
A konečně se podívejme na to, jak jsou zobrazeny překrývající se střely. Prioritu zobrazení těchto dvou typů objektů nelze změnit:
playfield: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ................................ ................................ ...XXXX....XXX.....XXX...XXXXX.. ...X...X..X...X...X...X....X.... ...XXXX...X...X...X...X....X.... ...X.X....X...X...X...X....X.... ...X..X...X...X...X...X....X.... ...X...X...XXX.....XXX.....X.... ................................ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX end missile0x = 80-2 missile0y = 28-2 missile0height = 8 missile1x = 80+2 missile1y = 28+2 missile1height = 8 mainloop CTRLPF = $05 NUSIZ0 = $30 NUSIZ1 = $30 COLUPF = 14 COLUP0 = $1E COLUP1 = $4E drawscreen goto mainloop
Výsledek:
Obrázek 33: Dvojice překrývajících se střel.
11. Detekce kolize střel
Čip TIA umožňuje detekovat kolizi mezi jednotlivými objekty, což je výhodné, protože to ušetří velké množství nutných výpočtů (zásah hráče, náraz hráče do zdi atd.). Pro test kolize v Batari BASICu postačuje použít funkci nazvanou collision, které se předá dvojice grafických objektů. V případě, že tyto objekty kolidují, vrátí se logická hodnota pravda, v opačném případě se pochopitelně vrátí nepravda. V dalším demonstračním příkladu je kolize střel zvýrazněna změnou barvy herního pole:
playfield: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ................................ ................................ ...XXXX....XXX.....XXX...XXXXX.. ...X...X..X...X...X...X....X.... ...XXXX...X...X...X...X....X.... ...X.X....X...X...X...X....X.... ...X..X...X...X...X...X....X.... ...X...X...XXX.....XXX.....X.... ................................ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX end missile0x = 80-20 missile0y = 28-2 missile0height = 8 missile1x = 80+20 missile1y = 28+2 missile1height = 8 mainloop NUSIZ0 = $30 NUSIZ1 = $30 COLUPF = $7F COLUP0 = $1E COLUP1 = $4E if joy0up then missile0y = missile0y - 1 if joy0down then missile0y = missile0y + 1 if joy0left then missile0x = missile0x - 1 if joy0right then missile0x = missile0x + 1 if collision(missile0, missile1) then COLUPF = $48 drawscreen goto mainloop
Obrázek 34: Střely, které nekolidují.
Obrázek 35: Střely, které kolidují.
12. Míč (ball), šířka vykreslení míče
Dalším grafickým objektem, který může tvořit součást herní scény, je takzvaný míč neboli ball. Pokud celou situaci poněkud zjednodušíme, můžeme si pod pojmem ball představit objekt, který se svými základními vlastnostmi podobá střelám – má šířku jednoho pixelu, ovšem lze ho v případě potřeby „roztáhnout“ na šířku dvou, čtyř či osmi pixelů, a to konkrétně úpravou obsahu řídicího registru CTRLPF:
CTRLPF | Stručný popis |
---|---|
$0× | míč s šířkou jednoho pixelu |
$1× | míč s šířkou dvou pixelů |
$2× | míč s šířkou čtyř pixelů |
$3× | míč s šířkou osmi pixelů |
Od střel se míč liší především tím, že má stejnou barvu jako herní pole (playfield). Jeho barva je tedy nastavena obsahem řídicího registru COLUPF. Pozice míče na obrazovce se v Batari BASICu nastavuje proměnnými ballx a bally, jeho výška (specifikovaná v obrazových řádcích) pak proměnnou ballheight.
V dalším demonstračním příkladu je zobrazeno jednoduché herní pole a míč, který se pohybuje pod úhlem 45° a odráží se od okrajů obrazovky – jedná se tedy o míč ze hry Pong. Vše je řízeno výše uvedenými řídicími registry a trojicí speciálních proměnných:
playfield: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ................................ ................................ ................................ ................................ ................................ ................................ ................................ ................................ ................................ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX end ballx = 80 bally = 50 ballheight = 8 rem Posun mice 0 v horizontalnim i vertikalnim smeru let c = 1 let d = 1 mainloop rem Sirka mice CTRLPF = $31 rem Barva pozadi a soucasne i mice COLUPF = 14 ballx = ballx + c if ballx >= 152 then ballx = 152: c =- 1 if ballx <= 1 then ballx = 1: c = 1 bally = bally + d if bally >= 80 then bally = 80: d =- 1 if bally <= 10 then bally = 10: d = 1 drawscreen goto mainloop
Obrázek 36: Míč pohybující se v herní scéně.
13. Shrnutí a ukázka z třetího článku – relativně složité demo využívajících necelé 2kB ROM
Prozatím jsme si popsali jen některé možnosti grafického čipu TIA. Zbývá nám ovšem ještě popis těch nejdůležitějších grafických objektů – hráčů (players), z nichž se na dalších platformách (jak na herních konzolích, tak i na mnoha herních automatech i na některých počítačích) vyvinuly plnohodnotné sprity. TIA umožňuje různé manipulace s hráči, například jejich několikanásobné zobrazení na jediném řádku (viz Space Invaders) atd. Podívejme se nyní jen v krátkosti (a bez dalších podrobností) na následující demo, jehož jednotlivé prvky budou zřejmé po pročtení navazujícího článku:
Obrázek 37: Snímek získaný z dema.
Obrázek 38: Další snímek získaný z dema.
I přes relativně velké množství pohybujících se objektů je kód dema po překladu menší než 2kB:
16:43 $ 2600basic.sh collisions_2.bas Found dasm version: DASM 2.20.14.1 Starting build of collisions_2.bas batari Basic v1.6-SNAPSHOT (c)2021 2600 Basic compilation complete. 2368 bytes of ROM space left Complete. (0) Build complete.
Úplný zdrojový kód tohoto demonstračního příkladu vypadá následovně:
playfield: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ................................ ................................ ................................ ................................ ................................ ................................ ................................ ................................ ................................ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX end player0: %01000010 %10000001 %01011010 %11111111 %11011011 %01111110 %00111100 %00011000 end player1: %10100101 %01011010 %00100100 %11111111 %11011011 %01111110 %00111100 %00011000 end player0x = 20 player0y = 20 player1x = 140 player1y = 30 missile0x = 80 missile0y = 40 missile0height = 4 missile1x = 80 missile1y = 60 missile1height = 4 ballx = 80 bally = 50 ballheight = 8 scorecolor = $98 rem Posun hrace #1 v horizontalnim smeru let a = 1 rem Posun hrace #2 v horizontalnim smeru let b = 1 rem Posun strely 0 v horizontalnim i vertikalnim smeru let c = 1 let d = 1 rem Posun strely 1 v horizontalnim i vertikalnim smeru let e = 1 let f = -1 rem Pocatecni hodnota score score = 0 mainloop rem Sirka strel NUSIZ0 = $20 NUSIZ1 = $20 rem Sirka mice CTRLPF = $31 rem Barvy pozadi i hracu COLUPF = 14 COLUP0 = $1E COLUP1 = $4E player0x = player0x + a if player0x >= 152 then player0x = 152: a =- 1 if player0x <= 0 then player0x = 0: a = 1 player1x = player1x + b if player1x >= 152 then player1x = 152: b =- 1 if player1x <= 1 then player1x = 1: b = 1 missile0x = missile0x + c if missile0x >= 152 then missile0x = 152: c =- 1 if missile0x <= 1 then missile0x = 1: c = 1 missile0y = missile0y + d if missile0y >= 80 then missile0y = 80: d =- 1 if missile0y <= 10 then missile0y = 10: d = 1 missile1x = missile1x + e if missile1x >= 152 then missile1x = 152: e =- 1 if missile1x <= 1 then missile1x = 1: e = 1 missile1y = missile1y + f if missile1y >= 80 then missile1y = 80: f =- 1 if missile1y <= 10 then missile1y = 10: f = 1 if joy0up then bally = bally - 1 if joy0down then bally = bally + 1 if joy0left then ballx = ballx - 1 if joy0right then ballx = ballx + 1 if collision(missile0, player0) then COLUPF = $38:score = score + 1 if collision(missile0, player1) then COLUPF = $48:score = score + 10 if collision(missile1, player0) then COLUPF = $58:score = score + 100 if collision(missile1, player1) then COLUPF = $68:score = score + 1000 if collision(missile0, missile1) then COLUPF = $78:score = score + 10000 if collision(ball, player0) then COLUP0 = $48:score = score + 100000 if collision(ball, player1) then COLUP1 = $48:score = score + 100000 if collision(ball, missile0) then COLUP0 = $48:score = score + 100000 if collision(ball, missile1) then COLUP1 = $48 drawscreen goto mainloop
14. Repositář s demonstračními příklady
Všechny minule i dnes popisované demonstrační příklady určené pro překlad Batari-BASICem byly uloženy do Git repositáře, který je dostupný na adrese https://github.com/tisnik/8bit-fame. Příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý (dnes již poměrně rozsáhlý) repositář:
15. Odkazy na Internetu
- STELLA PROGRAMMER'S GUIDE
https://alienbill.com/2600/101/docs/stella.html - Batari BASIC GitHub repositář
https://github.com/batari-Basic/batari-Basic - Programming Tutorial
https://atariage.com/forums/topic/111938-programming-tutorial/ - batari Basic Commands
https://www.randomterrain.com/atari-2600-memories-batari-basic-commands.html - About batari Basic
https://bataribasic.com/ - Rationale
https://bataribasic.com/rationale.html - Games That Push The Limits of the Atari 2600
https://www.youtube.com/watch?v=zM0IsWdIc_g - Vývojové nástroje používané v dobách osmibitových mikropočítačů
https://www.root.cz/clanky/vyvojove-nastroje-pouzivane-v-dobach-osmibitovych-mikropocitacu/ - Programovací jazyky používané na platformě osmibitových domácích mikropočítačů Atari
https://www.root.cz/clanky/programovaci-jazyky-pouzivane-na-platforme-osmibitovych-domacich-mikropocitacu-atari/ - Programovací jazyky používané na platformě osmibitových domácích mikropočítačů Atari (2)
https://www.root.cz/clanky/programovaci-jazyky-pouzivane-na-platforme-osmibitovych-domacich-mikropocitacu-atari-2/ - Barvové palety čipu TIA
http://www.qotile.net/minidig/docs/tia_color.html - Crazy Limit Pushing Games From the Last Years of the Atari 2600!
https://www.youtube.com/watch?v=ADy1F8v59YU - Atari 2600 VCS Top 100 Games Hits (past week)
http://www.atarimania.com/top-atari-atari-2600-vcs-_G2_7.html - Tobikomi – The Sound Of Thunder [Atari TIA Chip]
https://www.youtube.com/watch?v=j0w-IZ6nAMQ - TIA Visual Objects
https://github.com/jigo2600/jigo2600/blob/master/doc/TIA_Visual_Objects.md - TIA Sound
https://github.com/jigo2600/jigo2600/blob/master/doc/TIA_Sound.md - How To Make An Atari Game
https://www.youtube.com/watch?v=Ww3her2zk_I - Let's Make an Atari 2600 Game! – Part 1
https://www.youtube.com/watch?v=Iqo_oARxjEg - Let's Make an Atari 2600 Game! – Part 2
https://www.youtube.com/watch?v=hFFQjwFbzV8 - Let's Make an Atari 2600 Game! – Part 3
https://www.youtube.com/watch?v=lZ0AL6jCBXY - Let's Make an Atari 2600 Game! Part 4 – Title screens and challenges
https://www.youtube.com/watch?v=-G2kmsmqk-E - Let's Make an Atari 2600 Game! Part 5 – Sound
https://www.youtube.com/watch?v=9rX2eo20×q8 - Let's Make an Atari 2600 game! 6 – Realtime RPG combat
https://www.youtube.com/watch?v=alRGuQ9gjRA - Let's Make an Atari 2600 Game! Part 7 – Monsters
https://www.youtube.com/watch?v=vaAlYC_8YSA - Let's Make an Atari 2600 Game! Part 8 – 3D Engine
https://www.youtube.com/watch?v=c1dPY1ROZe4 - Let's Make an Atari 2600 Game – Part 9 – Homemade cartridge
https://www.youtube.com/watch?v=xKlMohF_9Cc - Bird Poop! – Atari 2600 Homebrew – batari Basic
https://www.youtube.com/watch?v=-m4gKis0vBg - DP Interviews: Bob Whitehead (By Scott Stilphen)
http://www.digitpress.com/library/interviews/interview_bob_whitehead.html - The dasm macro assembler
http://dasm-dillon.sourceforge.net/ - Official home of dasm, a versatile macro assembler
https://dasm-assembler.github.io/ - Dokumentace k DASMu
https://raw.githubusercontent.com/dasm-assembler/dasm/master/docs/dasm.pdf - Atari Programming Workshop Chapter links
http://atariage.com/forums/viewtopic.php?t=47479 - Various Development Kits
http://devkits.handheldmuseum.com/ - Classic Console Development
http://sebastianmihai.com/ccd/ - Atari 2600 development – Snappy (batari basic)
http://sebastianmihai.com/main.php?t=47 - Atari VCS (Atari 2600) – fotografie
http://oldcomputers.net/atari-vcs.html - History of Consoles: Atari VCS/2600 (1977)
http://gamester81.com/history-of-consoles-atari-vcs2600–1977/ - Iag Bogost: Racing the Beam
http://www.bogost.com/books/video_computer_system.shtml - Atari 2600 Programming Tutorial
http://www.randomterrain.com/atari-2600-memories-tutorial-andrew-davie-01.html - Atari 2600 Development Cartridge *Super Deluxe*~!
http://jazz-disassemblies.blogspot.cz/2013/09/atari-2600-development-cartridge-super.html - Atari „Alpine“ Devkit (pro Atari Jaguar)
http://justclaws.atari.org/devcats/hardware/ataridev.htm - 6502 compatible assembler and emulator in javascript
http://www.6502asm.com/ - Atari 2600 Programming
http://atariage.com/2600/programming/ - Retrozone – Brand new original homebrew games by current programmers
http://www.retrousb.com/index.php?cPath=30 - ATARI VCS/2600 TIA CHIPS
http://www.ataricompendium.com/faq/vcs_tia/vcs_tia.html - Elena, New programming language for the ZX Spectrum Next
https://www.vintageisthenewold.com/elena-new-programming-language-for-the-zx-spectrum-next - ZX Spectrum development with modern tools
http://www.breakintoprogram.co.uk/software_development/zx-spectrum-development-with-modern-tools - Z80 Development Toolchain
http://www.breakintoprogram.co.uk/computers/zx-spectrum/assembly-language/z80-development-toolchain - Space Invaders Sprite Sheet
https://www.deviantart.com/gooperblooper22/art/Space-Invaders-Sprite-Sheet-135338373