Implementace -- hra

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.*.

Reprezentace 3D prostoru

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

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.

Kontrola rychlosti pohybu panáčka

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.

Řešení problému viditelnosti

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í:

  1. textury na podlaze
  2. stěny
  3. textury "nahoře"

Proto jsou i programu 3 vektory pro indexy bodů polygonů: texsdole, walls, texshore.

Hlavní aplikační smyčka

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);
}

Implementace -- editor levelů

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..