Jak již bylo napsáno v rozvboru řešení, je nutno mít vlastní program rozdělený na dvě, pokud možno co nejméně závislé části:
Platformě závislá část obsahuje rozhraní pro vstup a výstup, konkrétně realizuje 3D zobrazení a manažer událostí (event manager). Implementace grafického systému je v souborech GFX.H a GFX.CPP. Implementace event manageru je v souborech EVENTMNG.H a EVENTMNG.CPP. Dále do této kategorie patří upravena funkce main, která se pro verzi používající knihovnu Allegro nachází v souboru ALEGMAIN.CPP. Dále se některé platformě závislé deklarace nacházejí v souboru COMMON.H.
Zbytek je platformě nezávslý. Základem programu je hlavní aplikační smyčka, která se nachází v souboru APP.CPP. Levely jsou uloženy ve struktoře deklarované a implementované v souborech LEVELS.*. Struktura která ukládá informace o hráči a právě hrané levelu se nachází v souborech HRAC.*.
Nejprve je nutno vysvětlit jak je v programu reprezentován 3D prostor. Všechny viditelné objekty hry jsou umístěny do pravoúhlé sítě bodů, které ve dvou vrstvách leží nad sebou. Tato síť je předgenerována na začátku programu a je uložena do proměnné world. Všechny body této sítě mají pevně přidělený index, který je univerzální, nezávislí na platformě. Proto se tento index používá při komunikaci platformě nezávislých a závislích částí.
Animace hráče je řešena systémem dvojic předgenerovaných textur, kde na jedné sadě textur hráč mizí do jedné strany a na druhé sadě textur vyjíždí. Zobrazováním vždy odpovídající si dvojice vedle sebe je dosaženo animace.
Rychlost pohybu panáčka z políčka na políčko je dána v podstatě počtem animačních fází při jeho pohybu z políčka na políčko. Počet animačních fází si uživatel může nastavit při běhu programu a tak si přizpůsobit rychlost hry svým potřebám.
Jako u každé 3D aplikace i zde je nutno řešit problém viditelnosti. Většinou se tento problém řeší pomocí paměti hloubky (Z-Buffer, Scanline-Buffer), ale na to se v tomto případě nemůžeme spolehnout, protože není zaručeno, že cílová platforma bude něco takového podporovat, např. Allegro pro to standardně podporu nemá. Je proto nutné vybrat nějaký algoritmus, který nám zaručí správné pořadí při vykreslování polygonů. Nejčastěji se většinou volí malířův algoritmus, ale ten je pro takto jednoduché zobrazení zbytečný, postačí vykreslovat polygony v pořadí:
Proto jsou i programu 3 vektory pro indexy bodů polygonů: texsdole, walls, texshore.
Tato smyčka je implementována jako metoda run() třídy SokoApp:
/**************************************************************************** SokoApp::run ~~~~~~~~~~~~ Spusti vlastni hru -- provadi vlastni aplikacni smycku. ****************************************************************************/ void SokoApp::run() {
Nejprve jsou vytvořeny pomocné proměnné:
Udalost u; Hrac hrac(gfx); float x=0, y=0, z=DEFAULTZ; int leveln = 0;
Přiřadíme hráči výchozí level:
hrac.assign(levely[leveln]);
Tento flag nabývá hodnoty true při pohybu kamery:
bool need_new_aligned = true;
Vlastní aplikační smyčka:
do {
Vygenerujeme 3D reprezentaci aktuálního levelu:
hrac.generate_3D_objects();
Pokud se pohnula kamera musíme o tom říci grafickému systému:
if (need_new_aligned) { gfx.move3D(x, y, z, 0-x, 0-y, -1, 0, 1, 0); need_new_aligned = false; }
Vykreslíme scénu i s případnou animací:
gfx.draw3DwithAnim();
Vyměníme viditelnou a neviditelnou video stránku:
gfx.swap();
Pokud jsme bednami zaplnily všechny cíle a nejsme na konci tak se posuň do dalšího levelu:
if (hrac.zbyva_cilu()==0 && leveln<levely.size()-1) { // vyhrali jsme? ++leveln; u = restart;
Jinak počkej na událost:
} else u = eventmng.wait_for_event();
Vykonej činnost podle události:
switch (u) { // pohyb hrace case vlevo : hrac.move_left(); break; case vpravo : hrac.move_right(); break; case nahoru : hrac.move_up(); break; case dolu : hrac.move_down(); break; // ovladani pohledu case plusP : z--; need_new_aligned = true; break; case minusP : z++; need_new_aligned = true; break; case vlevoP : x -= KROK; need_new_aligned = true; break; case vpravoP : x += KROK; need_new_aligned = true; break; case nahoruP : y += KROK; need_new_aligned = true; break; case doluP : y -= KROK; need_new_aligned = true; break; case hvezdaP : x=0; y=0; z=DEFAULTZ; need_new_aligned = true; break; // prochazeni levely case vpred : if (leveln < levely.size()-1 && eventmng.time_for_move()) ++leveln; hrac.assign(levely[leveln]); break; case vzad : if (leveln > 0 && eventmng.time_for_move()) --leveln; hrac.assign(levely[leveln]); break; // zobrazeni pomocne site bodu case debug : debugflag = !debugflag; need_new_aligned = true; break; // zobrazeni pocitace snimku za sekundu case fps : fpsflag = !fpsflag; break; // uloz obrazek case save_pict : gfx.save_screen_to_file(); break; // pomocne fce pro ovladani panacka case undo : hrac.undo(); break; case restart : hrac.assign(levely[leveln]); break; // zmena poctu animacni fazi panacka => zmena rychlosti case vicframu : if (eventmng.time_for_move()) gfx.moreframes(); break; case minframu : if (eventmng.time_for_move()) gfx.lessframes(); break; }
Opakuj dokud není konec:
} while (u != konec); }
Editor levelů je jednoduchá aplikace skládající se z několika jednotek. Většina jednotek byla navržena univerzálně, aby se daly použít i v jiných projektech.
Popis jednotek:
Dále je součástí soubor STEH3DED.PAS, který obsahuje hlavní begin ... end..