Rozhodnul jsem se splnit si svůj malý ataristický sen. Napsat alespoň jednu trochu slušnou hru. Napadlo mne, že mohu portovat svou hru "Lost miner" z IBM/PC (s tím, že využiji již vytvořené jeskyně).
Když jsem přemýšlel nad tím, jaké vývojové prostředky použiji, zavrhnul jsem nejprve BASIC (pro pomalost) a také assembler (protože v assembleru jsem naprogramoval jediné malé demo a neměl jsem odvahu psát v něm celou hru). Věděl jsem však o existenci CC65.
CC65 je cross-platform překladač jazyka C a má tyto součásti:
V jazyce C programuji na IBM/PC a vím, že překladače C jsou schopny generovat dostatečně efektivní kód. Volba tedy padla právě na CC65. Atari se od IBM/PC poněkud liší a při tvorbě hry to bylo potřeba vzít v úvahu.
Logiku hry - zejména pohyb horníka po jeskyni - má na starosti hlavní program psaný v C. Potřebuji udržovat stav jeskyně a vyhodnocovat pohyby horníka. Zde mi jazyk C pomůže svými řídícími strukturami (podmínky, cykly, větvení) - vše lze v tomto jazyce přehledně zapsat.
Za použití C se platí pamětí a výpočetním výkonem. Jak tuto cenu snížit?
Proč se našemu oblíbenému počítači říká malé Atari? Protože má málo paměti a jeho procesor malou taktovací frekvenci (ale přesto umí velké věci). Je tedy vhodné omezit plýtvání. Kde to je možné, používat datový typ char místo oblíbeného datového typu int. Malé Atari má také malý zásobník a proto se vyplatí šetřit s proměnnými deklarovanými v tělech funkcí. Navíc přístup k těmto proměnným vyžaduje více instrukcí. Trochu paměti a výkonu se dá ušetřit znovupoužíváním jedné globální proměnné pro řízení cyklů.
Při tvorbě hry jsem se trochu bál, jestli velikost programu nepřeroste Atari přes paměťové čipy, ale výsledných 10,5 KB hlavního programu není až tak moc a náročnost na paměť lze ještě trochu snížit. V assembleru by to ovšem dopadlo lépe - za cenu náročnější údržby kódu a menší přehlednosti (stará písnička). S rychlostí hlavního programu jsem byl spokojen. Bez patřičného zpožďování horník po jeskyni doslova létal.
10,5 KB paměti je pryč. Ale bez jeskyní a bez grafiky si moji hru nikdo nezahraje. Grafika a topologie jeskyní jsou data, která moje hra nezbytně potřebuje. Na IBM/PC jsou tato data obvykle umístěna v externích souborech na pevném disku. Jsem kazetář, a tak preferuji software, který se bez externích souborů obejde...
Řešením je přilepit data k hlavnímu programu. U topologií jeskyní je vcelku jedno, kde v paměti budou umístěny, ale v případě znakové sady nebo display listu to jedno není.
Problém se v assembleru řeší jednoduše direktivami pro nastavení aktuální adresy a vložení dat:
org $4000 .incbin "file.dat"
V jazyce C takto postupovat nelze. Je možné sice převést data na zápis staticky alokovaného pole, ale nelze určit adresy na kterých bude obsah pole uložen. V případě display-listu nebo znakové sady bych byl ztracen. Rozmístění proměnných v paměti totiž neurčuje překladač, ale linker. Linker, který je součástí CC65 umožňuje umísťovat bloky dat na konkrétní adresu. Naneštěstí se taková věc provede pomocí úprav jeho konfiguračního souboru, což je těžkopádné.
Vícesekční formát spustitelných souborů pro Atari umožňuje elegantnější řešení. Stačilo napsat vlastní jednoduchý minilinker (minilinker.jar), který jednoduše ke spustitelnému souboru přilepí další sekce s daty a opatří je patřičnou hlavičkou (počáteční a koncová adresa sekce). Tím je přidávání dat vyřešeno. Jen je třeba vzít v úvahu, že hlavní program roste od adresy $2E00.
Jako kazetář jsem dbal na to, aby se jednotlivé sekce nepřekrývaly. Přidal jsem tedy topologii jeskyní (převzatou z PC verze), grafiku (2bitové bitmapy) a jeden display-list. K přípravě dat mi posloužila také unixová utilita dd - pomohla mi odřezat nepotřebné části souborů z verze hry pro IBM/PC.
Musím s pravdou ven. Nevím, opravdu nevím... jak se programuje čip POKEY. Při programování v BASICu jsem prostě používal SOUND a,b,c,d a to mi k životu stačilo. S CC65 se žádná knihovna na hraní zvuků nedodává. Panice jsem ovšem nepropadl, protože jsem si vzpomněl, že v jistém čísle magazínu FLOP je návod, jak generovat zvuky jen pomocí posílání čísel na určité adresy, což by bylo možné provádět i v jazyce C. Trvalo mi hezkou chvíli, než jsem návod objevil v čísle 34 a napsal podle něj funkci sound(). Spokojen jsem však nebyl. Takto nelze přehrávat zvuk "na pozadí" a o hudbě se nedá ani uvažovat.
Co teď? Pomohla opět vzpomínka na FLOP, tentokrát číslo 48. Nepoužívala hra Cubico ke generování zvukového efektu přehrávací rutinu Raster Music Trackeru!? Používala. Po prostudování dokumentace, příkladů a zdrojových kódů k RMT jsem doplnil svou již dříve vytvořenou hudbu o instrumenty určené ke hraní zvukových efektů. Výsledkem byl soubor s hudebními daty a soubor s přehrávací rutinou (jak už to u takových trackerů bývá). V obou souborech nebyla čistá data, ale rovnou sekce spustitelného souboru. Musel jsem tedy upravit minilinker tak, aby dokázal i takové soubory správně přilepovat. To se podařilo.
Přehrávací rutině se předávají informace pomocí čísel uložených v registrech procesoru. Navíc jsem chtěl přehrávací rutinu volat během vertikálního zpětného běhu. Umístění čísel do registrů se musí psát v assembleru a obsluha VBI také. Žádný velký problém to nebyl.
Jak jsem napsal výše, součástí CC65 je samozřejmě i assembler. Stačilo se podívat, na co přeloží CC65 prázdnou funkci. Pak už zbývalo jen dopsat její tělo a do hlavního programu připsat její prototyp. Vytvořil jsem tedy několik funkcí k řízení přehrávací rutiny v assembleru. Přidal jsem také obsluhu VBI.
Hlavní program a rutiny v assembleru se překládaly zvlášť a pak se slinkovaly. K proměnným deklarovaným v souboru s rutinami v assembleru šlo také snadno přistupovat z hlavního programu. V hlavním programu se jen přidá k jejich deklaraci klíčové slovo extern. Přidání rutin v assembleru šlo nečekaně hladce. Dobrá zpráva pro programátory různých efektů.
Myslím že vývoj pomocí CC65 splňuje základní požadavky ataristů - CC65 produkuje efektivní kód, umožňuje snadno vkládat rutiny v assembleru, není problém umísťovat data na konkrétní adresy. Cenou za přehlednost programu je spíše zvýšená spotřeba paměti, než ztráta výpočetního výkonu. Moje hra vznikla za necelé 3 dny.
Více než tento text vám řeknou zdrojové kódy a kompilační skripty, které si můžete stáhnout.
Vývoj pomocí CC65 doporučuji zejména programátorům v BASICu a jeho variantách. Získají vyšší výkon při zachování vysokoúrovňového jazyka. A také strojové rutiny ve formě DATA řádků se stanou minulostí. Maximální výkon ale z Atari nedostanete.