2 Uživatelské rozhraní
2.1 Úvod
Uživatelské rozhraní(GUI), stejně tak jako u většiny her, je nejsložitější
součástí 8 Kingdoms. Je zároveň nejnáročnější, co se týká procesorového
času, a to během chodu celého programu, ne jenom nárazově. Návrh
uživatelského rozhraní byl veden v duchu moderních počítačových her. Jádro
uživatelského rozhraní spoléhá na standardně zavedené, multiplatformní
renderovací API
OpenGL, jehož
prostřednictvím maximálně využívá renderovací potenciál grafického
akcelerátoru. V současné implementaci jsme se rozhodli nejít za hranice
OpenGL verze 1.1, díky čemuž lze projekt 8 Kingdoms efektivně provozovat i
na poměrně starém hardware(nVidia TNT).
Díky použití OpenGL a další podpůrných multiplatformních knihoven, z nichž s
uživatelským rozhraním nejvíce souvisí
SDL
a
SDL_Mixer,
je 8 Kingdoms snadno portovatelné na každou platformu, kterou tyto knihovny
podporují. Vývoj probíhal na OS Linux a Windows.
Soubory zdrojového kódu ke všem prvkům uživatelského rozhraní se nacházejí v
adresáři gui/ hlavního adresáře projektu. Jsou rozděleny do čtyř podadresářů
se zdrojovým kódem čtyř tématicky odlišných okruhů:
- Obecné funkce, 2D engine
- Statická část 3D engine(+reprezentace objektů)
- Dynamická část 3D engine(+datové struktury)
- Implementace kontextů
2.2 Životní cyklus
Díky složitosti, komplexnosti a provázanosti uživatelského rozhraní s
ostatními částmi programu je uživatelské rozhraní celkem bohatě rozčleněno
do hierarchie objektů. Některé jsou pouze zastřešující a jejich funkce je
veskrze organizační. Cílem bylo vytvořit základní rámec pro ostatní funkční
moduly, jakožto veskrze nezávislé stavební kameny. Diagram 1 ukazuje
základní strukturu objektů uživatelského rozhraní.

Diagram 2.1: Základní struktura uživatelského rozhraní.
Uživatelské rozhraní běží celé především na hlavním vlákně, protože
renderovací knihovna OpenGL smí být na většině platforem volána pouze z
hlavního vlákna procesu, respektive vlákna odpovídajícího renderovacího
kontextu(aplikačního okna v gui OS). To jak program vykonává kód různých
metod různých tříd se dá chápat jako životní cyklus programu. Mezi
nejdůležitější třídy patří TGUI, TScreen a TContext. Jejich popis bude následovat.
2.3 Třída TGUI
Na nejvyšší úrovni leží instance třídy TGUI.
Tato instance je jediná instance této třídy. Pro její alokaci a dealokaci
používají statické metody třídy TGUI a
ukazatel na ni je statický člen TGUI. Toto
schéma je použito u více tříd.
Tato instance je viditelná a čitelná pro všechny prvky GUI. Její členy jsou
hlavně pointery na globální data, struktura reprezentující transceiver
Message Systému a "kontexty" uživatelského rozhraní.
Obsahuje zmíněné statické metody volané z hlavního programu(main). Její
konstruktor rovnou inicializuje různé moduly jako TextureManager, Screen,
SoundInterface, atd. a registruje transceiver v Message Systému. Také
alokuje sadu kontextů, které tvoří nezávislé stavební bloky GUI.
Nejdůležitější nestatickou metodou je main(), která je volána z hlavního programu, tzn.
na hlavním vlákně a program se z ní vrací až při svém ukončení. Uvnitř této
metody se odehrává běh celého programu.
V neposlední řadě je nutné zmínit metody, které umožňují nahrávat a
uvolňovat data v systému Resource Manageru(RM). Úkol dynamického nahrávání a
uvolňování dat je velmi těžké efektivně a hlavně jednoduše předem
naplánovat. Postupné nahrávání dat považujeme za nutné proto, abychom se
vyhnuli tomu nejjednoduššímu řešení, nahrávat všechna data při spuštění
programu. Je to tedy řešeno rozfázováním běhu programu. Při vstupu a výstupu
z fáze jsou volány příslušné metody(enterResourcePhase, leaveResourcePhase) instance TGUI. Tyto metody pak efektivně, podle potřeby,
nahrávají a uvolňují data držená RM.
2.4 Obrazovka
Obrazovka je jedním z hlavních podsystému uživatelského rozhraní. Jejím
reprezentantem je právě třída TScreen.
Nejpodstatnější metodou je enterMainLoop().
Obsahuje hlavní smyčku, která přijímá vstup ze vstupních zařízení(klávesnice
a myš), zpracovává je do vnitřní reprezentace typu INPUT a posílá aktuálnímu kontextu. Pokud není na
vstupu nic ke zpracování, předa jednou za DELAY_WORK pouze prázdnou strukturu INPUT aktuálnímu kontextu. Dále pokud uběhlo víc
jak DELAY_FRAME od posledního překreslení
překreslí aktivní kontext. Aby se šetřilo časem procesoru a zabránilo se
zbytečným prázdným cyklům, tak pokud není splněna ani jedna z předchozích
podmínek, vlákno se uspí na dobu než bude splněna podmínka pro překreslení.
Diagram 2 ukazuje práci hlavní smyčky.

Diagram 2.2: Hlavní smyčka.
Další funkcí třídy TScreen je správa množiny
kontextů. Ty tvoří nezávislé, oddělené, stavební kameny, které se starají o
samotný vystup na obrazovku a interpretaci vstupu uživatele. Hlavní operací
nad kontexty je přepínání mezi nimi. To lze realizovat pomocí jména kontextu
- textového řetězce. Hlavní program při spuštění přepne na kontext
"MAINMENU". Další přechody už jsou plně pod kontrolou samotných kontextů.
2.5 Kontexty - stavební kameny GUI
Kontext zodpovídá za konkrétní výstup na obrazovku a vstup od uživatele.
Kontexty jsou potomky třídy TContext. Každý
kontext definuje povinně vlastní metody activateContext, deactivateContext. Život kontextu je znázorněn na
Diagramu 3.

Diagram 2.3: Život kontextu.
Projekt 8 Kingdoms obsahuje sedm kontextů: MainMenu, LocalMulti, MultiHost,
MultiJoin, LoadingScreen, Game a FinalStatistics. Nejvýznamnějšími kontexty
jsou MainMenu a Game. Přechody mezi jimi, tak jak je může vidět uživatel,
jsou vidět v diagramu 4. V následujících podkapitolách jsou popsány všechny
existující kontexty, jejich stavba a funkce.

Diagram 2.4: Přechody mezi kontexty.
2.5.1 Kontext MainMenu
Tento kontext je aktivní při spuštěni hry. Nejdřív uživatel vybere svůj
profil, tedy svoje jméno a s ním spojené nastavení. Pak se dostane do hlavní
nabídky, odkud může měnit nastavení a vybrat typ hry (viz obrázek).
Diagram 2.5: Mapa kontextu MainMenu.
Významnější Okna kontextu:
- Výběr mapy: Vylistuje seznam nových her (uložených v xml-souborech v
adresáři /res/xml/maps) a nebo po přepnutí seznam uložených her (tj.
souborů z adresáře /savegame). U nových her se zobrazuje jméno mapy, u
uložených jméno souboru.
- Výběr serveru: okno pro zadání IP + seznam vytvořených her, o kterých
víme
- Nastavení: rozlišení, fullscreen, hlasitost zvuků, hudby, jazyk
- Credits: kdo se zasloužil, že program vznikl
2.5.2 Kontext LocalMulti
Tento kontext obsahuje pouze jedno okno. Je přístupný z hlavního menu po
výběru mapy. Okno kontextu obsahuje informace o vybrané mapě (její název,
velikost, počet hráčů pro který je určena a stručný slovní popis) a ovládací
prvky pro nastavení hry. Je to především seznam rolí, které se v mapě
vyskytují. Pro každou roli je potřeba nastavit, kdo ji bude ovládat (hlavní
hráč, tedy vlastník aktivního profilu, další hráč se zadaným jménem a nebo
umělá inteligence jedné ze tří obtížností). Druhým nastavením je typ
ukončení hry (vyvraždění všech nepřátel/obsazení měst viz. pravidla). Okno
bylo navrženo podle zkušeností z jiných her.
2.5.3 Kontext MultiHost
MultiHost je obdoba kontextu LocalMulti pro serverovskou část síťové hry.
Přibyl tu tudíž seznam hráčů přihlášených k tomuto serveru. Informace o mapě
a typ ukončení hry je totožný. Zůstává také seznam rolí ve hře. K rolím
se ale přiřazují připojení hráči nebo umělá inteligence. Okno se chová z
části automaticky. (Nově připojený hráč nahrazuje první neobsazenou roli.)
Kontext MultiHost se tedy kromě nastavování síťové hry stará také o
aktualizaci seznamu připojených hráč (klientů) a o rozesílání informací
jednak o nastavení hry a jeho změnách a také o připojených hráčích všem
klientům. K tomu slouží zpráva
MSG_NET_ROLESETTINGDATA (viz. kapitola
2.6 Zprávy).
V oknech kontextů pro nastavení síťové hry je také chatbox. (Seznam došlých
zpráv a krátký řádek pro napsání zprávy). Má sloužit jednak na komunikaci
mezi hráči a také na výpis zpráv typu, že se někdo připojil nebo odpojil.
Chatbox posílá a přijímá zprávu MSG_NET_CHAT
se jménem odesílatele a textem zprávy.
2.5.4 Kontext MultiJoin
Kontext MultiJoin je kopií kontextu MultiHost s rozdílem, že prvky pro
nastavení nepřijímají vstup od uživatele, ale pouze informují o nastaveních,
které provedl server.
Kontext zpracovává zprávu MSG_NET_ROLESETTINGDATA
, která obsahuje informace o změnách v nastavení.
2.5.5 Kontext LoadingScreen
Tento kontext obsahuje také pouze jedno okno, které navíc nepřijímá od
uživatele vstup. Je to mezistupeň mezi kontexty LocalMulti, MultiHost a
MultiJoin a kontextem Game. V době kdy se na pozadí načítají resources a
inicializují se datové struktury, okno tohoto kontextu informuje o tom,
co se děje. Pro zobrazení těchto informací slouží metody: showStateMsg() a setProgress()
.
2.5.6 Kontext Game
Game je samozřejmě nejkomplexnější kontext programu. Vedle hlavního okna s
mapou obsahuje ještě malá okna s nastavením, uložení hry, diplomacií a
okno s informacemi (viz diagram 6).
Diagram 2.6: Mapa kontextu Game.
Součásti hlavního okna:
- 3d mapa světa: pohled na výřez světa s možností přesunu a natočení
kamery
- Minimapa: celkový pohled na svět se čtyřmi úrovněmi (terén, nadmořská
výška, hranice království, rasy)
- Herní menu: přístup k dalším oknům kontextu
- Informace o hráči: jméno hráče, počet peněz, počet odkrytých hexů
- Herní akce: konec tahu, předchozí, další jednotka
- Informace o jednotce/o budově
- Akce jednotky/budovy
Obrázek 2.1: Ukázka kontextu Game.
Z funkčního hlediska pracuje kontext TGame
jako stavový stroj. Stavu odpovídá zvolená akce/jednotka/budova a to zdali
je hráč na tahu, či ne. Stav definují atributy actionsPanelState, infoPanelState, iGUIOwner, a další(viz dokumentace zdrojového
kódu). Změna stavu je zapřičiněna třemi typy událostí. První z nich je vstup
od uživatele (volba akce, jednotky, cíle, budovy,...). Druhou jsou pak
odpovědi herního enginu přicházející prostřednictvím zpráv Message Systému.
Třetí jsou pak události animačního enginu, které mají zajistit, aby grafika
zůstala konzistentní s hrou. Aby se zabránilo nekonzistencím je nutné
příjem a zpracování těchto událostí serializovat. K tomu slouží jednoduché
zamykání(vstupu uživatele) a řazení do front(zprav z herního enginu).
2.5.7 Kontext FinalStatistics
se stává aktivním na konci hry. Obsahuje statistiky bitvy. Cesta odsud vede
do hlavního menu.
2.6 Zprávy
Uživatelské rozhraní je přímo závislé na příjmu a odesílání zpráv. Hlavně
jeho herní část(kontext Game). Příjem zpráv probíhá v handleru GUI_MSG_HANDLER. Zde se zpracovávají zprávy:
- Inicializující hru.
- Komunikující s jinými GUI přes síťový modul. To jsou zprávy popsané
v kapitole 2.5 Kontexty (MSG_NET_CHAT a
MSG_NET_ROLESETTINGDATA
- Zachytávající běhové chyby na vláknech a při komunikaci.
- Herní.
Herní zprávy nejsou hned zpracovány, ale řadí se do fronty. Kontext Game si
je vyzvedává v okamžiku, kdy není zamčený z důvodu zpracování předchozí
zprávy.
2.7 Výjimečné stavy
Vyšší úrovně uživatelského rozhraní generují v případě chybových stavů
výjimky typ
E_8K_GUI a jejich potomků.
Potomek
E_8K_ASE_READER je generován
parserem souborů s modely formátu ASE.
E_8K_TGA_READER je generován načítadlem TGA
souborů. Více informací je v první kapitole programátorské dokumentace
1.7 Výjimky
Fatální chyby vzniklé a zachycené během chodu programu jsou reportovány
prostřednictvím funkce
CONSOLE(). K takovým
chybám by v ideálním případě nemělo docházet. Další informace v podkapitole
2.15 Příkazový řádek.
2.8 Matematická knihovna
Celý funkční aparát uživatelského rozhraní, který má něco společného s
výpočtem zobrazeni se opírá o matematickou knihovnu mymath.h. Tato knihovna
implementuje nejdůležitější matematické operace potřebné pro výpočet
transformací zobrazovaných objektů. Hlavními datovými typy jsou:
P2F, P2D
| struktury pro 2D souřadnice(x,y) ve float a double |
P3F, P3D
| struktury pro 3D souřadnice(x,y,z) ve float a double |
P4F, P4D
| struktury pro 4D homogenní souřadnice(x,y,z,w) ve float a
double |
MX4 | pole typu float
velikosti 16 pro reprezentaci matic 4x4 |
MX3 | pole typu float
velikosti 9 pro reprezentaci matic 3x3 |
V4D, V4F
| pole typu double a float délky 4 pro reprezentaci vektorů
|
V3D, V3I
| pole typu double a int délky 3 pro reprezentaci vektorů
|
V2D, V2I
| pole typu double a int délky 2 pro reprezentaci vektorů
|
QUATER | struktura pro
reprezentaci kvaternionu |
AXISANG | struktura pro
reprezentaci rotace kolem osy o jistý úhel |
Tabulka 2.1: Výčet datových typů mymath.
Některé struktury jsou ve skutečnosti uniony a díky tomu nabízejí svoje data
v několika různých reprezentacích. Například P2F
obsahuje položku float
p[2]. Díky této vlastnosti se typy pro vektory VnD/F/I téměř nepoužívají.
Zbytek knihovny je tvořen makry a funkcemi, které provádějí na těchto typech
operace. Pro základní a jednoduché operace typu nastavení, součet, součin,
velikost vektoru jsou zvoleny spíše makra, aby se ušetřilo jedno volání
funkce, což může být na některých kritických místech kódu znatelné
urychlení. Jiné složitější a nepříliš kritické operace jsou vykonávány
funkcemi. Mezi hlavní skupiny operací patří:
- Vektorové operace - nastaveni, kopírování, součet, rozdíl, skalární součin, vektorový součin
- Normalizace vektoru, velikost vektoru
- Maticové operace - nastavení, kopírování, nastavení rotační a translační matice, násobení, násobení vektorem
- Transpozice, Determinant, Inverzní matice
- Transformace souřadnic
- Kvaternionové operace - násobení
- Převody mezi různými reprezentacemi - AA-Q, Q-MX, Eulerovy úhly,...
- SLERP
- Vzdálenost dvou bodu, Velikost úhlu mezi vektory
- Řešení kvadratické rovnice a soustavy rovnic 3x3
- Zaokrouhlování, maximum, minimum, absolutní hodnota, sudé, liché
- Převody mezi radiány a stupni.
- Konstanty: PI, odmocniny, zlomky PI...
Rozšíření matematické knihovny mymath_ext.h, obsahuje objektovou verzi
vektoru(TVector), s kterou se lépe a
efektivněji pracuje. Nepoužívá se ovšem jako typ pro ukládání dat.
Reprezentace matic v mymath je opačná než v OpenGL, avšak operace násobení
vektoru a matice a matice s maticí se provádějí v opačném pořadí. Takže
výsledek je stejný a dá se tak přecházet z OpenGL a mymath bez speciálních
konverzi.
2.9 Křivky a plochy
Křivky a plochy jsou používány v počítačové grafice a pro počítačovou
animaci. V projektu jsou použity pro:
Křivky jsou implementovány v modulu AdvGeom.cpp/h. Každá křivka je potomkem
třídy TGenericCurve. Důležitým úkolem, vedle
samotného vypočítání bodů křivky, je způsob parametrizace. Pro pohyb objektů
po křivce je nutné mít možnost kontrolovat rychlost pohybu a její absolutní
pozici na křivce. Klasicky definované křivky mají nerovnoměrnou
parametrizaci. Třídy implementující křivky tento problém řeší předpočítáním
pozic na křivce a následné lineární interpolací parametrů mezi těmito body.
Metoda není přesná, ale poskytuje uspokojivé výsledky.

Obrázek 2.2: Parametrizace křivky.
Tabulka 2 shrnuje všechny typy implementovaných křivek.
TGenericCurve | Předek pro
všechny křivky. Obsahuje základní
datové struktury, jako seznam řídících bodů a metody na jeho zpracování.
Popisuje základní rozhraní, které křivka musí podporovat, jako hodnota v
bodě, první derivace v bodě, druhá derivace, nebo matice lokální soustavy.
|
TJoinQuadricBezierCurve |
Spojená Bezierova křivka. Umožňuje
vytvořit libovolné množství hladce napojených Bezierových kubik. Řeší
jejich parametrizaci. |
TJoinLinearCurve | Lomená
čára |
THermiteanCubic |
Hermitovská kubika. |
TJoinHermiteanCubic |
Spojené Hermitovské kubiky. Umožňuje
vytvořit libovolně mnoho hladce napojených Hermitovských kubik. |
Tabulka 2.2: Seznam tříd implementujících křivky.

Obrázek 2.3: Spojené křivky (kvadriky, kubiky).
2.10 Rastrová data.
Projekt 8 Kingdoms načítá rastrová data, obrázky, ze souborů ve formátu TGA,
nebo BMP. TGA mají tu výhodu, že podporují osmibitový alfa kanál. Tzn.
průhledné a poloprůhledné obrázky. Načítání provádí RM. Pro načítání BMP se
používá část knihovny SDL. Pro načítání TGA se používá modul TGA_lib.cpp/h,
obsahující funkci LoadTGA. Tato funkce umí
načítat nekomprimované obrázky ze souboru TGA do datové struktury SDL_Surface stejně jako ekvivalent pro načítání
BMP.
Rastry lze v projektu použít pouze jako textury. Renderovací knihovna OpenGL
klade na textury omezení, že jejich velikost smí být pouze mocnina dvou.
Proto jsou všechny rastry čtvercové a mají velikost 128x128, 256x256, nebo
512x512. Pro kontrolu a nahrávání rastrů do paměti grafické karty v
prostoru identifikátorů OpenGL byl navržen Texture Manager(TM). Ten spravuje
seznam rastrů načtených do texturovací paměti. TM je implementován v modulu
TextureManager.cpp/h. Je reprezentován jedinou globální instanci třídy TTextureManager, která se inicializuje při
inicializaci GUI.
Každá část aplikace, která chce použít texturu musí požádat Texture Manager
o její načtení metodou loadTextureQuery. Je
možné vytvořit texturu bez obsahu načítaného z externího souboru. Požadavky
na načtení se ukládají do zásobníku a k načtení textur dochází až ve chvíli,
kdy se zavolá metoda loadTextures. Pří
načítání textur se požádá RM o rastr a prostřednictvím volání OpenGL se
vytvoří textura v texturovací paměti. Je nutné připomenout, že OpenGL se smí
volat pouze na hlavním vlákně. Stejně tak i loadTextures. Zde se může zdát kumulované načítání
textur jako špatný nápad.

Diagram 2.7: Fungování Texture Manageru.
2.11 Fonty
Pro psaní textu používáme fonty pevné velikosti (8x16 a 8x13), které jsou
ve formě binárních dat uloženy přímo v kódu programu. Pevná velikost se nám
zdála výhodná jednak kvůli snadné implementaci a také kvůli zaručené
velikosti textu na obrazovce.
Pokryto je prvních
384 znaků unicode sady. Jsou mezi nimi všechny české a německé znaky. Do
budoucna by bylo dobré fonty rozšířit například o azbuku a doplnit o
chybějící francouzské znaky.
Výhodnější by pravděpodobně bylo používat fonty nainstalované v systému.
Přístup k fontům v jednotlivých operačních systémech je ale odlišný. Proto
jsme se rozhodli pro snazší řešení, ale do budoucna by tohle byla správná
cesta.
Při textovém vstupu od uživatele se některé znaky špatně zobrazují. To není
chyba fontů ale překladu vstupu do unicodu knihovnou SDL (viz. komentář k
INPUT_KEY_DOWN v kapitole
2.12 2D Engine). Řešení by bylo
implementovat tento překlad sami. Postup by byl opět na obou OS odlišný.
Částečným řešením by také bylo zakázat na vstupu znaky s kódem vyšším než
127.
2.12 2D Engine
Především kvůli přenositelnosti mezi platformami jsme v našem projektu
implementovali vlastní 2d grafické rozhraní pro komunikaci s uživatelem.
Jednak jsme si mysleli, že si uděláme rozhraní přesně na míru a také
dostupné systémy jsou často pouze pro jeden OS. Prvotní návrh jsme ale
podcenili a přidávání nových prvků a funkcí vedlo ke značné nepřehlednosti
systému.
Náš 2D engine Je systém tzv. ActiveObjectů (viz. níž), který uživateli
umožňuje klikání na tlačítka, vybírání položek ze seznamů a podobně.
Obrázek 2.4: Ukázka 2D engine.
2.12.1 ActiveObjecty
ActiveObject je 2D entita čtvercového tvaru, která je schopná se nakreslit a
zpracovávat vstup z klávesnice nebo od myši (tlačítko, okno, ...).
class TActiveObject {
public:
int x, y, width, height;
int state;
virtual void show();
virtual void hide();
virtual void drawObject()=0;
virtual int workInput(INPUT *input)=0;
/* ... */
};
ActiveObjecty je možné rozdělit do několika skupin:
- Jsou to jednak pasivní objekty, jako je text nebo obrázek. Tyto prvky
se dokáží nakreslit, ale na vstup od uživatele nijak nereagují.
- Dále aktivní, například tlačítko nebo editační box. Tyto jsou potomky
třídy TButton.
- Třetí skupina jsou kontejnery. Tedy entity, které obsahují další
ActiveObjekty.
Zpracování vstupu: Vzhledem k tomu, že 2d objektů se v každém našem kontextu
vyskytuje relativně málo pohromadě, rozhodli jsme se, že každý vstup z
klávesnice a od myši bude dostávat každý ActiveObject. Tedy ne jenom ten
nad kterým je myš, nebo který má focus. Toto řešení je sice náročnější na
výkon, ale na druhou stranu je každý prvek autonomní. Také to usnadňuje
situaci, kdy chtějí dva prvky reagovat na stejný vstup.
Každý ActiveObject má svůj "stav", který obsahuje informaci o tom, zda je
kurzor myši právě nad ním, zda má objekt focus a podobně. K zjišťování stavu
pak slouží makra (CLICKED, PUSHED, FOCUSED,
MOUSEOVER, ...)
if CLICKED(mybutton) { /*...*/ }
ActiveObject je o vstupu informován metodou workInput. Jako parametr je mu
předána struktura INPUT. Tato struktura
obsahuje především typ události, která nastala a dále parametry, které s
touto událostí souvisí (která klávesa byla zmáčknuta...). Každý input navíc
obsahuje informaci o pozici myši v době události.
struct MOUSEPOS{
Sint16 x,y;
};
struct KEY {
SDLKey sym;
Uint16 unicode;
};
struct INPUT {
int type;
MOUSEPOS mousepos;
union {
KEY key;
MOUSEPOS relpos;
Uint8 button;
};
};
Možné typy vstupů jsou:
INPUT_MOUSE_DOWN | Bylo
zmáčknuté tlačítko myši. button
obsahuje které tlačítko |
INPUT_MOUSE_UP | Bylo
puštěno tlačítko myši. button obsahuje
které tlačítko |
INPUT_MOUSE_MOTION | Pohnula
se myš. relpos udává relativní pohyb od
předchozí pozice |
INPUT_KEY_DOWN | Zmáčknutá
klávesa. sym říká, která to byla. unicode je znak, kterému to odpovídá
Pozn.: na přeložení klávesy do unicodu používáme rozhraní knihovny SDL. V
něm je ale chyba a správně překládá pouze unicody menší než 256. To má za
následek že vstup od uživatele je v některých případech špatně
reprezentován. To se projevuje především u písmen s háčky a čárkami. |
INPUT_KEY_UP | Puštěná
klávesa. |
INPUT_NO | Po dobu
DELAY_WORK nedošlo k žádné události |
Tabulka 2.3: Typy vstupu.
Naše ActiveObjecty si nedělají ambice být úplným okénkovacím systémem.
Vznikaly postupně podle toho, co jsme potřebovali. Implementovány jsou:
TLabel | Jeden řádek textu.
|
TMultiLabel | Víceřádkový
text |
TIcon | Jednoduchý obrázek
(výřez z textury). |
TIconExt | Rozšíření TIcon. Obrázek s rámečkem. |
TButton | obdélník, který
mění svůj vzhled když je stisknut (popřípadě i když je nad ním kurzor). Má
dvě verze: standart, toolbar. |
TTextButton | Potomek
TButton, který navíc obsahuje TLabel. |
TSoundedTextButton | Potomek
TTextButton, který, když se na něj klikne,
přehraje zvuk. |
TIconButton | Potomek
TButton, který má navíc TIcon |
TRadioBox | Přepínátko.
Maximálně jeden TRadioBox v jednom
TGroupBaru (viz níž) může být vybrán.
|
TCheckBox | Zaškrtávátko.
|
TLineTextField |
Jednořádkové políčko pro textový vstup. |
TScrollBar | Obdélník s
dvěma šipkami a jezdcem mezi nimi. Dvě verze: vertikální, horizontální.
|
TBar | Předek pro všechny
kontejnery. Má metodu Add(TActiveObject *)
na přidání objektu do kontejneru. Metoda
DrawObject() pak kreslí všechny takto přidané objekty. Stejně tak
workInput(INPUT *) předá všem těmto
objektům vstup od uživatele. |
TWindow | TBar na nejvyšší úrovni z hlediska stromu vykreslování
(hned pod kořenem). Může být pohyblivé/nepohyblivé. Typicky má nějakou
texturu jako pozadí, ale může být i poloprůhledné. |
TGroupBar | Potomek TBaru, který graficky zvýrazňuje určitou oblast.
Stará se o přepínání radioboxu. (tj. aby v něm byl vybrán maximálně jeden
TRadioBox.) |
TListBar | Seznam s
vertikálním scrollbarem. Lze do něho přidávat
TItemy. ListBar> se pak stará o
skrolování seznamem. Mezi TItemy lze
vybírat podobně jako mezi radioboxy. Pouze jede item muže být vybrán.
|
TItem | Položka TListBaru a zároveň kontejner |
TCursor | Je to speciální
ActiveObject. Současně existuje pouze jednou. Jeho poloha odpovídá poloze
kurzoru myši. Je to potomek TIcon, ale
jeho obrázek se může měnit v závislosti na poloze (na okraji obrazovky se
ve hře mění na šipku v daném směru). |
TFrame | Také TFrame existuje vždy jen jednou. Typicky je to předek
kontextu (viz výše). Je to vlastně kořen hierarchie vykreslování a
zpracování vstupů ActiveObjectů. Stará se také o překrývání oken. |
Tabulka 2.4: Seznam ActiveObjectů.
Kromě víceméně standardních obecných ActiveObjectů, jsme potřebovali
i nějaké speciálnější. Jsou to většinou potomci některého z výše
uvedených objektů, rozšířené o další možnosti, nebo úplně nové objekty,
které se ale nepoužívají běžně.
TConsoleWindow | Konzole,
tedy řádek na zadávání textů (příkazů) a seznam historie. |
TOSD | Průhledné okno,
kterému se metodou showMsg dají posílat
textové zprávy. TOSD tyto zprávy
zobrazuje. Dále se stará o jejich uspořádání podle priority a času
příchodu. |
TWallpaper | Velký obrázek
na pozadí |
TScrollingTitles |
Skrolující titulky |
TIconTextButton | Tlačítko s
obrázkem i textem zároveň |
TProgressBar | obdélník,
který mění svůj rozměr a tím naznačuje míru pokroku probíhající akce |
Tabulka 2.5: Seznam rozšiřujících (konkrétních) ActiveObjectů.
2.13 3D Engine
8 Kingdoms obsahuje vlastní 3D engine pro zobrazování dynamického
trojrozměrného světa, terénu, překážek, modelů vojáčků atd. Implementuje
některé standardní postupy, které se v počítačových hrách běžně používají.
Skládá se ze statické části, která drží data v reprezentaci vhodné pro
rychlé vykreslování pomoci API OpenGL a dynamické části, která simuluje
pochody ve virtuálním světě v průběhu času. 3D engine sám o sobě je umístěn
ve vykreslovacím systému jakožto potomek TActiveObject, konkrétně potomek TFrame. Tímto je zařazen do stromu TActiveObjectů jak je uvedeno v části o 2D
enginu. Pokaždé když se volá metoda drawObject() zděděna po TActiveObjectu vykreslí se jeden frame do oblasti
dané zděděnými parametry TActiveObjectu.
Poté se provede update dynamické části a řízení se vrátí zpátky do hlavní
smyčky.
2.13.1 Graf scény
Hlavním objektem 3D enginu je TScene. TScene
si pamatuje objekty, které jsou v dané scéně, pozice a parametry světelných
zdrojů a aktuální mlhu.

Diagram 2.8: Objekt
TScene
Mlha slouží především k tomu, aby se nemusely kreslit objekty, které jsou
ve scéně ve výřezu, který vidí kamera, ale které jsou daleko. Navíc změnou
její barvy simulujeme změny počasí.
Nejdůležitější součástí scény jsou ale TSceneObjecty. Obecně to může být cokoli, co má
nějakou pozici a orientaci. Pro zrychlení výpočtu je každý TSceneObject obalen osově orientovaným kvádrem
(TAABB). Při výpočtech (kolize dvou TSceneObjectů, kolize TSceneObjectu s paprskem, ...) se potom objekt
nahrazuje svým TAABB.
2.13.2 Rendering
Objekty nejsou ve scéně v jednom seznamu, ale jsou uloženy ve stromu. Když
se má pak z pohledu nějaké kamery scéna nakreslit, nekreslí se všechny
objekty ale jen objekty z nějakých uzlů. Protože naše scéna má dvourozměrný
charakter (ve směru osy z jsou nad sebou typicky maximálně dva objekty),
rozhodli jsme se pro datovou strukturu Quad-tree. Jedná s v podstatě o
rekurzivní dělení scény na čtvrtiny, tak aby ve výsledku každý uzel
obsahoval přibližně stejný počet TSceneObjectů.

Diagram 2.9: Quad-Tree
Obrázek popisuje, jak by mohl vypadat Quad-tree pro jednoduchou scénu. Na
počátku je ve scéně moc objektů, tak se rozdělí na čtvrtiny. Pak už je to
lepší až na první kvadrant, který se dále dělí. Pokud je nějaký na rozhraní
Quad-nodů, uložíme odkaz na něj do obou.
TScene je potomkem objektu TQuadNode. Na začátku se do scény umístí všechny
objekty, pak se spustí tohle dělení. Když se potom objekt přesouvá z jednoho
quad-nodu do druhého, struktura se už nepřepočítává.
Při zobrazování scény se nejprve spočítá jehlan kamery. Kreslí se ty
quad-nody do kterých tento jehlan zasahuje. Každý TSceneObject si pamatuje, jestli byl v tomto
průchodu již nakreslen, tím zabraňujeme, aby se objekt na rozhraní dvou
quad-nodů kreslil dvakrát.
2.13.3 Model světa
Ke grafické reprezentaci světa slouží třída TguiMap je to potomek obecné scény (TScene). Oproti TScene obsahuje navíc seznam hexů, jednotek a
budov. Má svojí vlastní kameru. Stará se o stupně viditelnosti objektů.
Zpracovává vstupy od myši a z klávesnice.
2.13.4 Import 3D Modelů
Struktura scény je hierarchická. Na nejnižších úrovních jsou body a
trojúhelníky. Body a trojúhelníky jsou sdruženy do komplexnějších objektů,
které reprezentují tuhá tělesa ve virtuálním světě. Těmto tělesům se říká
modely. Modely jsou předvytvořené odděleně během vývoje hry. Jelikož jsou
celkem komplikované, používá se k jejich vytvoření sofistikovaný modelovací
software. Například:
- 3D Studio MAX
- Blender
- Gmax - volně šiřitelná verze 3D Studia s omezenou funkčností
Součástí modelů, jsou i předpřipravené animace, jako chůze, mávání mečem,
upadnutí na zem, apod. Tyto animace se také vytvářejí v modelovacím
software.
Vytvořený model z modelovacího programu vyexportuje do souboru formátu .ASE
(Ascii Scene Export). Daly by se použít i jiné soubory s 3D daty, pro které
by bylo třeba napsat příslušnou importovací knihovnu. Soubor ASE je textový
a obsahuje geometrii a animace jedné scény vytvořené v modelovacím software.
Některé jeho části jsou povinné, a některé nepovinné. Pro použití v
8 Kingdoms potřebujeme především geometrii objektů a jejich animace. Jak
bylo řečeno, soubor obsahuje jednu animaci pro celou scénu. Proto bylo nutné
uložit různé animace jednoho objektu do více souborů. Máme tedy pro jeden
objekt primární soubor s geometrií a sekundární soubory s animacemi.
Je důležité aby si tyto soubory odpovídaly. Soubory s animací objektů
obsahují redundantně i geometrii, kvůli tomu, aby byly sami o sobě
konzistentní. Tato geometrie se při načítaní sekundárních souborů ignoruje.
Považuje se za už načtenou z primárního souboru. Z animačních souborů se
tedy nahrávají pouze animace nad stejnou geometrii. Odkazy na geometrii musí
sedět.
Pro načítání modelů ze souborů ASE se používá knihovna reader_ase.cpp/h,
kterou si volá Resource Manager, když potřebuje nahrát požadované zdroje.
Protože je ASE soubor textový, je jeho parsování pomalejší, než tomu
je u binárních formátů. Přesto je dostatečně rychlé na běžném počítači, aby
stačilo nahrát všechny modely, se kterými 8 Kingdoms pracuje. Výhodou
textového formátu je jednodušší práce během vývoje. Detailní popis souboru
ASE se dá nalézt na těchto adresách:
Knihovna reader_ase.cpp exportuje dvě funkce load_ASE. Které nahrávají geometrii a animace do
objektu typu TModel. První funkce nahrává
přímým způsobem primární verzi objektu, druhá funkce slouží k nahrávání
zjednodušených verzí modelů pro použití LOD. LOD není v
8 Kingdoms použito.
Je nutné zmínit, že každý model se nahraje do programu pouze jednou. To že
je vidět na scéně vícekrát, je způsobeno instanciováním modelu. To znamená,
že se vytvoří jednoduchá unikátní konstrukce, instance, odkazující se v
klíčových bodech na geometrii v TModel. Více
informací v podkapitole o grafu scény a o hierarchické animaci.
2.13.5 Kontroléry
Kontroléry tvoří jádro dynamické části 3D engine. Zajišťují změny obsahu
statické scény v čase. Jinými slovy pohyb. Oživují scénu animacemi a
speciálními efekty. Jsou hierarchicky uspořádané a mají plug-in charakter.
Snadno se vyvíjí a přidávají k již hotovému systému a tím přidávají nové a
další zajímavé efekty a funkcionalitu.
Architektura kontrolérů je inspirována principy na kterých fungují nástroje
na vytváření 3D animací, také trendy ve vývoji moderních 3D engine.(V
neposlední řadě přednáškou Antonína Hildebranda: Návrh animačního systému
pro herní engine.)
Kontrolér je objekt, který modifikuje nějaká data v závislosti na čase. Jeho
struktura vypadá zhruba následovně:
class controller
{
private:
void* data;
public:
void update(float time);
};
Základní návrh lze modifikovat mnoha způsoby: hierarchická struktura,
závislosti, updatování podle přírůstku, spoolovaná alokace, LOD, atd. V
8 Kingdoms kontroléry implementují některé tyto vlastnosti. Pro stručnost a
přehlednost jsou shrnuty v následujícím výčtu:
- Všechny kontroléry jsou potomky třídy TController.
- Každý kontrolér může mít libovolný počet synů a má jednoho rodiče.
- Přidávání a odebíraní synů se provádí metodami addChildControler a removeChildControler.
- Každý kontrolér je updatován voláním metody update(time), kde time je
absolutní čas. A je na kontroléru, co si pamatuje a jak si čas převede.
- Hierarchie kontrolérů se updatuje voláním updateTree(time) na kořenovém
kontroléru. Kde time je čas předaný všem kontrolérům v hierarchii.
- Updatování probíhá na každém počítači jinak rychle. Je odvozeno od
rychlosti procesoru a grafické karty udávající to, jak rychle probíhá
vykreslení jednoho snímku a také dobu samotného updatu hierarchie.
Kontroléry by tedy měli pracovat s reálným časem.
- Update stromu probíhá průchodem do hloubky. Zde se musí dát pozor na
modifikaci seznamu synů z updatu potomků samotných. Proto se skutečné
mazání provádí až po průchodu a updatu všech synů.
- Kontrolér a celá hierarchie pod ním může být deaktivována, nebo
aktivována. Podle toho se provádí, nebo neprovádí update.
- Kontrolér má vlastnost fTimeRatio,
která napovídá jak se má interpretovat čas při update. Tato vlastnost se
dá změnit voláním setTimeRatio(ratio).
Změnu je možné delegovat do celé hierarchie
- Pro usnadnění práce s přírůstkem má každý kontrolér iLastTime pro uložení času posledního updatu.
Toho využívají některé náročnější kontroléry proto, aby se updatovali méně
často a ne pro každé volání update()
- Pro usnadnění ladění, má každý kontrolér 10-ti bytový identifikátor
szIdent, metodu RTTID pro jeho nastavení a printSubtree pro výpis hierarchie.
Kontroléry jsou svázány čistě pouze s 3D scénou. Jediná 3D scéna je v
kontextu TGame a typ teto scény se jmenuje
TguiMap. Jeden její člen je speciální
potomek třídy TController, TControllerManager, který tvoří kořen hierarchie
všech kontrolérů na scéně. Diagram 10 zachycuje práci kontrolérů.

Diagram 2.10: Struktura kontrolérů.
Typů kontrolérů je mnoho a jejich počet poměrně rychle naroste. Následující
tabulka 6 obsahuje nejdůležitější z nich rozdělené podle funkce.
TController |
Předek všech kontrolérů. Viz výše. |
TAdvController |
Vylepšený kontrolér. Přidány funkce pro počítání přírůstků a
relativního času. |
TControllerManager |
Tvoří kořen hierarchie kontrolérů. Obsahuje metodu
destroyAllControllers a metodu setSpeed pro nastavení rychlosti cele
hierarchie |
TSceneObjectManipulator |
Umožňuje pohybovat s objektem po scéně pomocí vstupu z
klávesnice. Nepoužívá se. |
TTRSController |
Základní kontrolér pro hierarchickou animaci.
Modifikuje parametr P3F a AXISANG v závislosti na čase. Obsahuje prostředky pro
interpolaci. |
TNodeAnimationController |
Svazuje TRSController s animační
tabulkou pro přehrávání animací importovaných z 3D modelovacího software.
Viz hierarchická animace.
|
TModelAnimationController |
Tvoří kořen hierarchie kontrolérů pro jednu animační tabulku. Tzn. pro
jednu konkrétní animaci. Obsahuje metody play()
a stop() pro aktivaci a
přehrávání |
TPuppetController |
Tvoří zastřešující kontrolér pro všechny animace na jedné instanci
modelu. Obsahuje metody addAnimation() pro
přidání nového stromu kontrolérů pro animaci instance modelu a metody
playAnimation(aid) a stopAnimation(aid) pro přehrání a zastavení konkrétní
animace. |
TParticles |
Předek pro všechny částicové animace. Obsahuje datové složky pro pole
pozic a směrů částic, metodu addPoint pro
přidávání bodů, virtuální |
TBloodSplash |
Efekt "výstřiku krve". Vkládá se do scény statickou metodou
installSmallBloodSplash(), která přijímá
jen nezbytné parametry, jako je poloha a směr. |
TExplosion |
Efekt výbuchu je téměř identický s
TBloodSplash, jen částice jsou jinak velké a barevné. Vkládá se
pomocí statické metody installExplosion().
|
TSmoke |
Trvalý, nebo dočasný efekt stoupajícího kouře. Vkládá se statickou
metodou installSmoke(). |
TDistantAttack |
První verze střely. Rozlišuje dva druhy podle vnořeného typu
TDistantAttackType na střelu z katapultu a
střelu z luku a magickou střelu. Nepoužívá se. |
TDistant_Attack |
Druhá verze střeleckých útoků. Předek pro všechny. Obsahuje hlavně
datové položky. |
TProjectileAttack |
Střela reprezentovaná 3D modelem. Obsahuje update pro let hmotného
bodu. |
TArrowAttack |
Šípový útok. Pouze využívá speciální typ modelu. |
TCatapultAttack |
Útok katapultu kombinující částicový efekt stopy za letící střelou s
3D modelem projektilu |
TMagicMissileAttack |
Většinou stejná jako u střely z katapultu jen optimalizováno pro
magickou střelu. Přidána tlakové vlna po dopadu. |
TDestruction |
Exploze při zničení budovy. Je tvořena pomocí potexturované koule a
disku vytvořené funkcemi glu. |
TFlyAway |
Není to vlastně částicový efekt, ale funguje podobně, vyletí s
objektem scény do vzduchu a pak ho odstraní ze scény a smaže. |
TSparkle |
Efekt jiskření. Pro zdůraznění události na mapě. Je zároveň potomkem
částic i billboardů(jiskry se otáčejí na kameru). |
TAtmosphericEffect |
Předchůdce pro částicové atmosférické efekty. Implementuje efektivní
algoritmus pro rozmístění částic jen v okolí kamery. Ve stručnosti jde o
devět krychlí, které se vyměňují podle toho přes který okraj prostřední
krychle kamera přešla. |
TSnow |
Potomek TAtmosphericEffect, který
simuluje pád vloček - tetelení, a vykresluje je jako jednoduché body. |
TRain |
Potomek TAtmosphericEffect. Simuluje
dešťové kapky, zvukový efekt hromu a záblesky. Nastavení časových prodlev
je možné pomocí konstant v Effects.h |
TWeatherController |
Zastřešující kontrolér pro ovládání tří stavů počasí (Léto, Zima,
Podzim) a jejich plynulého přechodu. Změna barvy pozadí a mlhy. |
TScheduler |
Předek pro plánovací kontorolery. Slouží pro načasování spouštění
akcí. Akce je reprezentována datovou strukturou
TSheduledAction. Pokud je akce naplánována pomocí metod linkActionAfterLast(act), insertActionAfter(act1, act2) a insertAction(act) spouští se ve stanoveném
intervalu updateAction(rtime, act)
pokaždé, když se zavolá metoda kontroléru
update(time). Akce mohou samy řídit svoji dobu běhu. Z toho
důvodu není zaručeno, kdy akce končí a nedá se tak plynule navázat na
druhou pouhým nastavením počátku následující za konec předchozí. Proto se
dají akce zřetězit explicitně. Platí, že když akce skončí aktivuje se akce
která je na ni zřetězená. Dají se tak vytvořit sekvence činností: běž
dokud se nedostaneš na místo->bojuj dvě vteřiny->umři. |
TBuildingController |
Plánovací kontrolér pro budovy. Umožňuje naplánovat zničení, spuštění
scénáře a odstranění z mapy |
TUnitMemberController |
Plánovací kontrolér jednoho modelu z jednotky. Umožňuje naplánovat
pohyb scénou po křivkách, nebo za použití steeringu(viz Jednotky). Dále
umí naplánovat spuštění scénáře, zmizení a objevení modelu a odstranění
modelu ze scény. |
TMapControllerManager |
Potomek TControllerManager tvořící
kořen hierarchie v TguiMap. Drží
ukazatel na stav vstupních zařízení, který updatuje při každém updatu
hierarchie. Spolupracuje s TInputController
. |
TInputController |
Při vytvoření získá ukazatel na
TMapControllerManager, kterého se ptá na stav vstupů. Dovoluje tak
odvozeným kontrolérům pracovat kromě času i se vstupem z klávesnice. |
TMainCameraController |
Kontrolér ovládající pohyb kamery po scéně v závislosti na vstupu z
myši a klávesnice. Realizuje pohyb uživatele po scéně. |
TMovingCameraController |
Implementuje automatický pohyb kamery po scéně z místa na místo.
Zaostření na událost na mapě, atd. |
TEventPlayer |
Přehrávač událostí. Dostane jako vstup vektor událostí typu
TEventInfo* a přehraje je uživateli.
Události se týkají herních dějů. Například smrt zraněné jednotky,
dostavění budovy. Události jsou sbírány v průběhu hry, od konce posledního
hráčova tahu do začátku následujícího. Tak se dozví, co se odehrálo
důležitého. |
TVisibilityScheduler |
Plánovač skrývání a odkrývání mapy. Spolupracuje se scénáři. Například
soubojem, sebevraždou, nebo autodestrukcí. Dovoluje naplánovat zmizení
chvíli potom, co scénář skončí. |
TSteeringKernelController |
Udržuje mapu pro steering jednotek. Viz Jednotky. Mapa je
reprezentována v quadtree pro vyhledávání v logaritmickém čase. Zastřešuje
třídu TQuadrant. Na čase a updatování
hierarchie není přímo závislý. |
TSteeringController |
Jako potomek TAgent reprezentuje
virtuálního agenta pro steering. Viz Steering. |
TSoundInterfaceController |
Updatuje hlasitost u zvuků se specifikovaným zdrojem v prostoru podle
vzdálenosti k asociované kameře pozorovatele(posluchače). |
TUnitController |
Nic nedělá. |
Tabulka 2.6: Seznam typů kontrolérů.
Některé z kontrolérů budou podrobněji popsaný ve zbytku dokumentace.
Implementační detaily je lepší dohledat v dokumentaci zdrojového kódu.
2.13.6 Objekty na scéně
Z popisu grafu scény vyplynulo. že nejmenší jednotkou, která se samostatně
vykresluje jsou modely a jejich instance. Jako model je zvlášť reprezentován
každý hex na mapě. Jako model je reprezentován každý typ jednotky, budovy a
terénní překážky. Jejich vsazení do scény je pak instance modelu. Instance
modelu je objekt typu TModelInstance.
Existuje více instancí(instancí objektu TModelInstance) jednoho modelu(instance objektu
TModel). Tím se zabrání redundanci dat na
úrovni vrcholů, trojúhelníků a ploch.
To jak zachytit v grafu scény, jehož listy jsou instance modelů, herní
objekty podle pravidel 8 Kingdoms je řešeno pomocí objektů typu THex a TProxyObjekt. Tyto objekty jsou specifické pro
scénu typu TguiMap.
Tato scéna je speciální tím, že zachycuje mapu bitevního pole 8 Kingdoms
skládající se z šestiúhelníkových buněk, hexů. Jeden hex je reprezentován
potomkem TModelSceneObjektu THex. TguiMap
obsahuje explicitně pole ukazatelů na tyto objekty, kromě toho, že jsou
někde v grafu scény. Hex obsahuje jedinou instanci modelu povrchu.
Každý hex si drží ukazatel na scénu TguiMap.
Hex je navíc potomkem THighlighting, která
mu dává možnost zvýraznění se například po přejetí myší.
Stejně tak jako v pravidlech hry, každý hex je prostorem pro výskyt
ostatních herních objektů, i zde každý hex obsahuje odkazy na reprezentace
herních objektů, na potomky třídy TProxyObjekt.
Potomci TProxyObjekt sdružují modely scény
do množin, které reprezentují herní objekt. Proxyobjekty jsou kategorizovány
typem TProxyType, který může nabývat hodnot
ptStatic, ptDynamic, ptTerrain, ptBuilding. Konkrétní od TProxyObjekt odvozené typy jsou:
- TUnit - reprezentuje vojenskou jednotku skládající se z modelů
panáčku, strojů, apod. Je typu ptDynamic.
- TBuilding - reprezentuje budovu, která
se může skládat i z více modelu, ale zatím se používá jen jeden na budovu.
TBuilding se dál dědí kvůli rozlišení
otevřené a uzavřené struktury budov(viz dále). Je typu ptBuilding
- TTerrainEntity - reprezentuje terénní
objekty na hexu. Potomků tohoto proxyobjektu je tolik, kolik různých
terénů, které vyžadují reprezentaci v pravidlech hry je. Je typu
ptTerrain.
Každý proxyobjekt si zároveň drží ukazatel na hex, na kterém se nachází.
Umisťování proxyobjektů na hexy se řeší obecnými metodami TProxyObjectu addToHex(), moveToHex(), které si každý potomek může
předefinovat. Každý proxyobjekt ukazatel na scénu TguiMap. Vztahy scény a objektů na ní ukazuje
diagram 11.

Diagram 2.11: Vztahy scény a objektů na ní.
Následující odstavce popisují specifické vlastnosti konkrétních
proxyobjektů.
2.13.6.1 Jednotky
Jednotky vojáčků jsou v GUI projektu reprezentovány třídami TUnit a TUnitMember. TUnit
je potomek TProxyObject, který tvoří záštitu
vojenského útvaru podle pravidel. Je s ním svázán objekt typu TUnitController, který je potomek TController a sám o sobě nemá zatím žádnou funkci.
Je zde jen proto, aby zastřešoval objekty TUnitMemberController, který zase pracuje v
tandemu se statickým TUnitMember(potomek
TSceneObject). Doplňkovým objektem je TUnitFormation jehož potomci mají řešit speciální
požadavky na rozmístění panáčku na mapě(mimo terénní překážky, do různých
útvarů a řad,..). Jednotka nese zbarvení hráče, který ji vlastní.
Operace a funkce TUnit víceméně kopírují
pravidla hry:
- Statické metody a prvky pro manipulaci s typy jednotek(trpaslíci,
lučištnice,..)
- Statické metody pro vytvoření a odstranění jednotky
- Umístění jednotky na mapu, do budov
- Formace jednotky
- Přidání a odstranění členů jednotky
- Seznam odkazů na TUnitMembery živé a mrtvé
- Pohyb po mapě z hexu na hex podle cesty TPath
- Boj jednotky s jednotkou, budovou, jednotkou v budově,...
- Sebevražda jednotky
- Stavba budovy jednotkou
- Oprava budovy jednotkou
- Léčeni jednotky
- Doplnění jednotky
- Stop stavby
TUnitMember je objekt vojáčka ve virtuálním
světě jeho metody a vlastnosti přímo souvisí s grafickým výstupem:
- Odkaz na ovladač hierarchických animací(TPuppetController), jehož prostřednictvím spouští
vlastní animace.
- Odkaz na TUnitMemberController, který
používá na programování dalšího svého chování na scéně, jako je pohyb,
zviditelnění, zneviditelnění, volání scénáře a odstranění.
- Odkaz na TSteeringController. Jeho
funkce není oficiálně implementována. Tvoří alternativu k pohybu po scéně
pomocí TUnitMemberControlleru.
- Odkaz na jednotku do které náleží
- Animace chůze
- Animace boje
- Střelba na jiného vojáčka, nebo budovu
- Krvácení
- Umírání
- Mizení a znovuobjevování
- Obecná kontrola animací
- Pohyb z místa na scéně na jiné místo po křivkách zadaných řídícími
body
- Pohyb po scéně pomocí steeringu(neoficiálně).
- Řízení scénářem
- Umístění do scény
Pohyb jednotek probíhá po křivkách. Neoficiálně je implementován steering,
což je pohyb virtuální agenta, nebo agentů ve světě překážek. Metoda je
inspirovaná článkem
http://www.red3d.com/cwr/steer/
.
2.13.6.2 Budovy
Budovy a jejich herní logika je reprezentována objektem TBuilding potomkem TProxyObject. Konkrétní objekty budov na scéně
jsou reprezentovány TSceneBuildingObject.
Doplňuje ho TFlag reprezentující geometrii
vlajky, která se objevuje na budovách, když jsou v nich jednotky. Budova
nese zbarvení hráče, který ji vlastní. Budovy jsou svázány s ovladačem typu
TBuildingController, který se stará o
spouštění scénářů, výbuch budov a vyvěšení vlajky. Budovy jsou dvou typů:
- Otevřené - mosty, rozestavěné budovy. Tyto budovy jsou reprezentovány
speciálním potomkem typu TOpenBuilding.
Jednotky, které do nich vejdou nezmizí, ale jsou pořád vidět na scéně. Boj
probíhá přímo v nich. Koordinace takového boje(pomocí scénáře TOpenBuildingCombat) je náročná a není příliš
dobře dořešena. Na takových budovách se nevztyčuje vlajka, pokud je v nich
jednotka. U otevřených budov, zvláště mostů, je důležitá jejich
orientace.
- Uzavřené - ostatní dostavěné budovy. Jsou reprezentovány speciálním
potomkem TClosedBuilding. Tyto budovy se
můžou bránit střeleckým protiútokem pokud je na ně veden útok pěchotou.
Boj s takovými budovami je řízen scénářem TBuildingAttack.
Budovy k sobě vážou doplňková data:
- TPlacementArea - oblasti pro rozmístění jednotek.
- TApproachRoute - cesty pro vstup jednotek do budovy.
- TGate - kontrolní body na cestách TApproachRoute.
- TAttackPosition - pozice pro útok na budovu.
- TBuilderPosition - pozice pro umístění stavitele, pokud jde o stavbu.
- TDamage - Poškození.
Akce kopírují pravidla:
- Seznam objektů TSceneBuildingObject. Většinou je pouze jeden.
- Umístění na hexu
- Statická databáze typů budov
- Statické metody pro vytváření a rušení budov.
- Scénáře
- Odstranění
- Obsazeni nepřítelem
- Průhlednost a orientace
- Stavba, umístění stavitele a výroba jednotek
- Pohyb z a do budovy
- Boj s budovou a protiútok
- Poškození a oprava
- Vlajka
2.13.6.3 Terén
Poslední přímý potomek TProxyObjectu, TTerrainEntity je předkem pro všechny
terénní specializace podle pravidel 8 Kingdoms. Tyto specializace zastřešují
objekty scény(stejně jako TUnit a TUnitMember). Samotné objekty
scény(potomci TModelInstance) jsou reprezentovány TSceneTerreainObject a
TTownObject. Konkrétní terénní specializace většinou obsahují pouze data o
modelech, způsobu rozmístění po hexu, zbarvení a velikosti. Speciální
výjimkou je terén TTerrainTown, který si drží barvu hráče, jež ho vlastní a
umožňuje ji měnit. Terénní specializace jsou:
- Les - TTerrainForest
- Hvozd - TTerrainDeepForest
- Skály - TTerrainRocks
- Bažina - TTerrainSwamp
- Město - TTerrainTown
Data k terénním objektům jsou inicializovány pomocí statických metod každé
specializace a centrálně pak pomocí statických metod TTerrainEntity.
2.13.6.4 Povrch
Herní plán je složen z šestiúhelníků (hexů). Každý hex je určen typem terénu
a svou nadmořskou výškou. Různé terény zvýrazňujeme jednak terénními
překážkami (stromy, kameny, ...) a jednak různými texturami povrchu.
Nadmořská výška je znázorněna vymodelováním povrchu hexů. Kvůli iluzi
plynulého přechodu mezi nadmořskými výškami je každý hex rozdělen na několik
trojúhelníků.

Obrázek 2.5: Dělení hexu.
Souřadnice x a y každého vrcholu v této síti trojúhelníků je určená. Z-ovou
souřadnici dopočítáváme metodou spline-ploch. Jeden plát kubické spline
plochy je určen šestnácti řídícími body. Za řídící body jsme použili středy
hexů. Jejich nadmořská výška je známá.

Obrázek 2.6: Řídící body spline ploch pro modelování hexů.
Nezávisle na nadmořské výšce je pak do povrchu případné vymodelované koryto
řeky.
Každý hex je samostatným objektem scény. Jinou možností je, považovat celý
povrch za jeden objekt. Rozdělení povrchu je výhodné pro renderování - každý
hex se buď nakreslí nebo nenakreslí podle toho, zda zasahuje do výhledu
kamery. Také operace jako změna barvy hexu se provádí snáze. Na druhou
stranu po rozdělení povrchu nelze implementovat LOD (různé úrovně detailů
modelu v závislosti na vzdálenosti od pozorovatele) - hexy by na sebe
nenavazovaly přesně. Implemetace LODu povrchu by zřejmě vedla k výraznému
zrychlení renderování scény.
2.13.7 Kamera
Pro renderování je kromě samotné scény potřeba popsat také pozorovatele. Ten
je dán parametry tzv. kamery. Jsou to: pozice, směrový vektor pohledu,
up-vektor (z-ová souřadnice), zorný úhel a dosah viditelnosti (dál už je
jen mlha).
Kamera v našem případě není součást obecné scény, ale je to jedna z položek
TguiMap. Používáme jednu kameru, která zabírá vždy výřez scény. Lze s ní
pohybovat, natáčet a zoomovat. Možným rozšířením by bylo přidat ještě další
kameru a přidat možnost přepínání pohledu z kamery a pohledu jednotky.
2.13.8 Hierarchická animace
Velkým přínosem architektury kontrolérů je podstatné zjednodušení
implementace hierarchické animace. Hierarchická animace je animace
hierarchického objektu prováděná časovou změnou lokálních transformací v
uzlech. Tento princip demonstruje obrázek 7.

Obrázek 2.7: Hierarchická animace.
Jak už bylo zmíněno v kapitole o importu modelů, data popisující změnu
lokální transformace jsou vytvářena v 3D modelovacím nástroji. Do programu
jsou importována společně s geometrií modelů.
Jak tato data vypadají? Jsou to dlouhé řady čísel a vektorů říkajících, jaké
hodnoty mají mít lokální transformace popisující vektory v jistém čase od
začátku animace. Tyto data se drží v strukturách uvnitř TModel. Aby se v těchto datech dalo lépe
vyhledávat a byla všechna v jednoduché struktuře, vytvářejí se z nich
animační tabulky. Pro každou animaci, např. zachycenou v jednom ASE souboru,
je jedna tabulka. Animační tabulky se vytvářejí při nahrávaní animací
metodou TModel->loadAnimation(). Ta volá po
nahrání struktur TModel z ASE souboru funkci
CreateTableForModel, která vytvoří tabulku a
uloží ji do cache tabulek animací. Tato cache a funkce pro práci s ní jsou
implementovány v modulu Animation.cpp.
Jak se data v těchto tabulkách aplikují na instance modelů? Právě díky
kontrolérům TTRSController, TNodeAnimationController a TModelAnimationController. TTRSController si drží ukazatele na vektory
popisující lokální transformace. TNodeAnimationController ho kombinuje s ukazatelem
na tabulku a do příslušných políček tabulky. V TNodeAnimationController vzniká vazba mezi
konkrétní lokální transformací (veličinou) a tabulkou pro animaci instance
modelu(daty). TModelAnimationController pak
zastřešuje všechny kontroléry, které pracují s jednou tabulkou, tzn. jednou
animací. Tyto vztahy také popisuje diagram 12.

Diagram 2.12: Struktury a kontroléry pro hierarchickou animaci.
Tento model hierarchické animace je naprosto základní. Další možná pokročilá
rozšíření jako jsou Animation blending, nebo Skeletální animace se dají
doimplementovat.
2.13.9 Efekty
Dnešní hry se neobejdou bez nesmírného množství detailní vizuálních efektů,
jako jsou oheň, kouř, déšť, stíny. Dočasné objekty pohybující se scénou,
například kameny, nebo šípy. A mnoho jiných doplňků, které jsou nad rámec
základní funkčnosti objektů na scéně.
8 Kingdoms implementuje tuto skupinu objektů v modulech Effects.cpp/h.
Efekty jsou vlastně speciální kontroléry, protože jsou skoro vždy závislé na
čase a v čase mění svůj stav definující vzhled. Jde tedy o malé,
procedurálně generované animace. Hlavní třídy zde jsou TEffectEngine, TParticles a TBillBoard.
TEffectEngine je zastřešující třída, pro
kterou existuje v programu jediná instance. Zatím se neuvažuje o tom, že by
najednou bylo víc scén, které by potřebovaly svůj vlastní EffectEngine.
Tento objekt se stará o hromadnou žádost o nahrání příslušných zdrojů pro
všechny efekty, které to potřebují. Drží některé atributy společné pro
všechny efekty. Jedním takovým je například iPRP, což je perioda obnovení pro částicové
systémy. Efekty se jeho prostřednictvím umisťují a odstraňují ze scény a ze
systému kontrolérů přes atributy scene a ctrlmng.
Velkou skupinu efektů tvoří tzv. částicové systémy. Pomocí nich lze
namodelovat chování složitějších animací jako je oheň, kouř, výbuch a jiné.
Částicové systémy fungují tak, že vytvoří, většinou náhodně, velké množství
vrcholů v prostoru a pravidelně mění jejich polohu, rychlost, velikost a
jiné parametry podle zadání. To se děje v update fázi kontrolérů. Proto jsou
částicové systémy potomky TController. Aby
se daly částicové systémy renderovat, musí být zároveň potomky TSceneObject. Při fázi vykreslování je možné na
jejich pozici umísti body, trojúhelníky, nebo celé plochy, potažené
texturou. Všechny částicové systémy jsou potomky třídy TParticles, která obsahuje základní atributy jako
pointery na 3D souřadnice pro ukládání pozice a směru pohybu částic.

Obrázek 2.8: Příklad částicových systémů.
Dalším užitečným efektem jsou billboardy. Princip billboardů je následující.
Struktura některých objektů je příliš složitá na to jak jsou tyto objektu
pro pozorovatele nezajímavé, proto stačí ukazovat jen jejich 2D obrázek a
pří pohybu scénou ho natáčet čelem k uživateli. Tato technika byla v jistých
dobách jediným způsobem jak uživateli rychle zobrazit nějaký objekt na
scéně.

Obrázek 2.9: Příklad billboardů.
Billboardy nejsou závislé na čase, nejsou proto potomky TController. Musí však obsahovat odkaz na kameru,
aby se při vykreslení mohly zobrazit pokaždé správně natočené k
pozorovateli. Billboardy jsou často kombinovány s částicovými systémy.
Všechny billboardy jsou potomky TBillBoard.
Posledním zmiňovaným efektem je TSimpleShadow. Ten umožňuje, pokud je předkem
nějakého modelového objektu, zobrazit kolem tohoto objektu jednoduchý stín,
který dává lepší dojem ze scény. Je nutné po vykreslování scény volat
statické metody TSimpleShadow, aby proběhly
další běhy víceprůchodového algoritmu na vykreslení stínů. Ty pracují se
stencillbufferem kam si ukládají příznaky o příjemci stínu, tak aby se stín
vykreslil pouze na něj i při vypnutém z-bufferu. Tento postup je naznačen na
obrázku 4.

Obrázek 2.10: Princip vykreslování stínů.
TEffectEngine |
Správce pro všechny efekty. Obsahuje některá společná data pro
souhru efektů na jedné scéně. Počítá jen s jednou instancí scény. |
TParticles |
Předek pro všechny částicové efekty. Obsahuje základní datové
struktury a rozhraní pro implementované metody, jako přidávání
částic(addPoint()), inicializace(
setUp()) a základní vykreslení částic
jako bodů(drawObject()) |
TSimpleSpray |
Jednoduchý efekt určený pro testování. Vystřikuje částice ve výseči
v náhodném směru, náhodnou rychlostí. |
TAtmosphericEffect |
Předek pro atmosférické efekty jako je déšť nebo sníh. Stará se o
efektivní využívání množiny částic, aby to budilo dojem, že částice jsou
na celé scéně. Přitom jsou jen v okolí kamery. Velikost toho to okolí se
ovlivňuje konstantou AE_CELL_SIZE. |
TSnow |
Sníh. Částice se mihotavě pohybují zhruba ve směru gravitace.
Velikost, barva a hustota částic se dá řídit konstantami SNOWFLAKE_SIZ,
SNOWFLAKE_COL a SNOWFLAKE_DENSITY
. |
TRain |
Efekt deště. Dešťové kapky padají zhruba nakloněny ve směru
vanoucího větru. Délka, velikost, barva a hustota se dá řídit
konstantami RAINDROPS_LEN,
RAINDROPS_SIZ,
RAINDROPS_COL a RAINDROPS_DENSITY
. Občas se i zableskne. Blesk využívá světelný zdroj 1. Interval, délka
blesku a odstup zahřmění se dá ovlivnit
LIGHTING_INTERVAL_MIN,
LIGHTING_INTERVAL_MAX,
LIGHTING_INTERVAL_LEN, THUNDER_TIMING
.
|
TWeatherController |
Umožňuje plynulé přepínání počasí mezi zimou (wsWinter, sníh), létem (
wsSummer) a podzimem (wsAutumn,
déšť) s postupnou změnou barvy pozadí |
TBloodSplash |
Implementuje výstřik krve v průběhu soubojů. Krev vystříkne ve
výseči v požadovaném směru, po oblouku dopadne na definovanou nulovou
úroveň a po chvilce zmizí a automaticky se odstraní ze scény. |
TExplosion |
Výbuch je podobný výstřiku krve, liší se jen velikostí a barvou
částic a v budoucnu možná ještě něčím. Používá se při útoku na budovu. |
TBillBoard |
Předek pro všechny billboardy. Obsahuje ukazatel na kameru. |
TSmoke |
Kouřový efekt. Je kombinací částic i billboardů. Každá částice je
čtyřúhelník potažený poloprůhlednou texturou. Tvoří tak dohromady
obláček dýmu. Pomalu stoupa k nebi. Dá se spustit v nekonečně dýmající
smyčce, nebo aby dýmal jen chvíli a pak se sám odstranil ze scény. |
TSimpleShadow |
Staticky implementuje ad-hoc algoritmus pro vykreslení jednoduchých
stínů. Objekt sám slouží jako předek pro vrhače stínů. Je to tříkrokový
algoritmus:
- Vykreslení scény z pohledu kamery. Zachycení všech objektů co
vrhají stíny. Do stencil bufferu se zapíše 0 tam kde je vrhač a 1 tam
kde je příjemce stínu.
- Vykreslení stínu na místa označená 1 jen do z-bufferu s drobnou
modifikací. Posunutí směrem k pozorovateli o magickou konstantu (SIMPLESHADOW_MAGIC_CONSTANT) a inkrementuje
stencil buffer tam kde projde z-test
- Vykreslí stíny při normální projekci tam kde je stencil buffer
dost velký
Tato metoda nemá s moderními způsoby realtime stínů nic společného. Není
přesná a vykazuje chyby např. velké objekty stojící v kopci mají
stínovací polygon hodně pod povrchem, odkud ho magická konstanta
nedokáže vytáhnout.
|
TDistantAttack |
Implementuje střelbu při střeleckém útoku, nebo obraně. Místo
částice se používá model projektilu (šíp, balvan). První verze.
Zastaralé. |
TDistant_Attack |
Druhá verze střeleckých útoků. Předek pro všechny. Obsahuje hlavně
datové položky: souřadnice zdroje a cíle, zvukový efekt a doba
trvání |
TProjectileAttack |
Střela reprezentovaná 3D modelem. Dědí navíc TModelSceneObject. Obsahuje update pro let hmotného
bodu. |
TArrowAttack |
Šípový útok. Pouze využívá speciální typ modelu. |
TCatapultAttack |
Útok katapultu kombinující částicový efekt stopy za letící střelou
s 3D modelem projektilu. Některé parametry se dají nastavit konstantami:
CATAPULT_TRACE_DENSITY, CATAPULT_TRACE_PARTICLE_SIZE, CATAPULT_TRACE_PARTICLE_COLOR. Ostatní jsou přímo v
kódu.
|
TMagicMissileAttack |
Většina stejná jako u střely z katapultu jen optimalizováno pro
magickou střelu. Přidána tlakové vlna po dopadu. Parametry střely lze
modifikovat podobně jako u střely z katapultu(konstanty začínající MAGIC_) |
TDestruction |
Stylizovaná exploze typu ohnivá koule, tlakové vlna a vyletující
částice doprovázena ohlušujícím zvukovým efektem. |
TFlyAway |
Vyhazuje do vzduchu roztočený objekt a automaticky ho po nějaké době
zničí a odstraní ze scény. |
TSparkle |
Jiskření. Slouží hlavně k zdůraznění událostí na mapě, které nelze
jiným rozumným a viditelným způsobem zobrazit. Změna hodnoty,
vlastnosti, atd. |
Tabulka 2.7: Seznam efektů.
2.13.10 Scénáře
Scénáře, nebo také skripty, jsou vedle kontrolérů další důležitou částí,
která vnáší život do statických scén. Řeší se pomocí nich organizačně
složité úlohy jako souboje a pohyb skupin modelů a jakékoliv složitější
chování, které zahrnuje více elementů scény.
Scénáře často fungují jako stavové stroje. Předek pro všechny scénáře je
třída TSceneScript. Každý scénář musí
implementovat metodu decision, která funguje jako přechodová funkce. Stav
pak je určen z parametru této funkce a dat, která si konkrétní skript u sebe
ukládá. Scénáře nejsou kontroléry, protože nejsou přímo závislé na čase, ale
na stavu. Bývají z kontroléru spouštěny, resp. jejich přechod bývá volán z
kontorolerů, který tak činí v závislosti na čase. Nejčastěji to bývá
kontrolér typu plánovač(TSheduller). Skript
má tak možnost naplánovat si vlastní spuštění daným objektem. Princip
volání scénářů osvětluje diagram 13.

Diagram 2.13: Schéma spouštění a práci scénářů.
Jak bylo naznačeno, scénářů je mnoho, pro každý úkol je speciální. Do
budoucna se nabízí možnost implementovat scénáře pomocí skriptovacího
jazyka. Prozatím jsou scénáře napsány v C++. Jejich úplný seznam s popisem
zachycuje tabulka 8. Detaily o fungování přechodové funkce jsou nejlépe
vidět ze zdrojového kódu.
TSceneScript |
Předek pro všechny scénáře. Definuje povinné rozhraní pro scénáře,
metody decision a getStatusMsg a pamatuje si scénu. |
TCombat |
Předek pro všechny soubojové scénáře. Souboje jsou komplikované tím,
kolik možných kombinací existuje. Aby se snáze psali stavové přechody.
Byly rozděleny do více tříd. Vstupem pro tento stavový stroj je
TSceneObject ke kterému je jednoznačně navázán TCombatant, datová
struktura, která si udržuje další speciální informace. TCombat> obsahuje datové položky pro účastníky i
výsledky boje a některé metody pro vyhledávaní cílů, nebo například
leavescript pro opuštění scénáře |
TCloseCombat |
Implementace boje tváři v tvář. |
TDistantCombat |
Implementace útoku střelbou. |
TOpenBuildingCombat |
Implementace boje v otevřené budově. |
TBuildingAttack |
Implementace útoku na budovu. |
TBlastAttack |
Implementace sebevražedného destrukčního útoku. |
TMarchMove |
Pohyb jednotek z hexu na hex, z budovy, do budovy. |
TBuildBuilding |
Stavba budov. |
TReleaseUnit |
Sebevražda jednotky a odstranění ze scény. |
TDemolishBuilding |
Autodestrukce budovy a odstranění ze scény. |
TRepairBuilding |
Oprava budovy. |
TUnitDeserted |
Dezertující jednotka. |
TUnitMemberDied |
Umře zraněná a neléčená část mužstva. |
Tabulka 2.8: Seznam scénářů.
Na závěr je uveden, jako příklad, vývojový diagram analýzy a přechodů stavu
nejjednoduššího soubojového scénáře TCloseCombat.

Diagram 2.14: Analýza stavu a přechody objektu podle scénáře
TCloseCombat.
2.14 Zvuk
Zvukový doprovod je součástí většiny her. Jeho implementace je poměrně
jednoduchá, na druhou stranu získat, nebo vytvořit zvuková data je úkol
obtížnější. Samotné přehrávání zvuku zprostředkovává multiplatformní
knihovna SDL. A přehrávání konkrétních zvukových formátů a některé technické
detaily obstarává doplňková knihovna SDL_mixer. Zvuková podpora se dělí na
přehrávání hudby(music tracks) z jednoho zdroje, která běží neustále na
pozadí a přehrávání zvuků(sound samples), které jsou kratší a v jednu
chvíli jich může běžet víc najednou. O mixování hudby a zvuků do jednoho
datového toku a posílání na zvukové rozhraní SDL se stará právě knihovna
SDL_mixer.
V 8 Kingdoms jsou volání SDL_mixeru obalena metodami třídy TSoundInterface
případně TSoundInterfaceController. TSoundInterface má pouze jednu instanci, která se
inicializuje při inicializaci uživatelského rozhraní. Implementuje metody
pro přehrávání zvuků a hudby získané ze Správce zdrojů(Resource Manager).
Zároveň si udržuje vlastní přehled o přehrávaných zvucích, které obsazují
volné sloty tzv. kanály(channels). Nakonec umožňuje oddělenou regulaci
hlasitosti hudby a všech zvuků.
Oživení do prostého přehrávání zvuků v 3D scéně přináší TSoundInterfaceController. Umožňuje právě tu
vlastnost prostoru, tlumit zvuky ze vzdálenějších zdrojů. Ve scéně je
potřeba pouze jedna jeho instance, kterou stačí vytvořit na začátku scény a
asociovat s kamerou na scéně. Tento kontrolér pak při updatu mění hlasitost
všech kanálů přehrávajících zvuk, která má specifikovánu polohu zdroje v
prostoru podle vzdálenosti tohoto zdroje od kamery. Tato jednoduchá úprava
dává aspoň základní pocit trojrozměrného zvuku. Dalším rozšířením by byla
regulace hlasitosti zvuku na různých částech reprosoustavy.

Diagram 2.15: Schéma zvukového subsystému.
Pro přehrávání zvuků slouží metoda playSample(int rid) a pro přehrávání
zvuku se specifikovaným zdrojem v prostoru se používá playSampleSpatialConrolled. Zvuk se přehraje
okamžitě pokud existuje neobsazený kanál. Počet kanálů, současně
přehratelných zvuků, je definován makrem DEFAULT_CHANNELS_COUNT, jehož hodnota se může
pohybovat od 8 do 64. Při větším počtu kanálů dochází k většímu zatížení CPU
a výsledek není o mnoho realističtější.
Hudba se přehrává metodami playMusic, stopMusic. Vždycky se přehrává maximálně jedna
skladba. Dokonce v jednu chvíli smí být v paměti nahrána pouze jedna. To je
omezení SDL_mixeru. To je celkem logické, protože čistá data skladeb
zabírají mnoho místa. SDL_mixer je online streamuje, dekóduje a přehrává ze
souboru na disku. Má smysl pracovat s jedním otevřeným souborem.
2.15 Příkazový řádek
Příkazový řádek patří mezi uživatelské rozhraní, proto je nutné ho zde
alespoň krátce zmínit. Zpracování parametrů programu z příkazového řádku
probíhá na samotném začátku programu ve funkci main. Podle některých z parametrů se totiž
rozhoduje co se bude dál dít s grafickým rozhraním. O zpracování se stará
jediná instance objektu TCommandLine.
Atributy tohoto objektu jsou všechny možné údaje, které lze z parametrů
příkazového řádku získat. Tato jediná instance TCommandLine je se vytváří voláním statické metody
parseCommandLine(argv, argc) a ukazatel na
ni se drží v statické proměnné cl. Díky tomu
je dostupná z každého místa programu od začátku jeho běhu. Jaké chování lze
parametry ovlivnit ukazuje tabulka 9.
iRunMap a
iMapType==0 |
-m <n> |
Spustí mapu číslo n. Má smysl jen pro hru jednoho hráče a pro
síťovou hru v roli serveru. |
iRunMap a
iMapType==1 |
-l <n> |
Nahraje mapu číslo n ze savegame/. Má smysl jen pro hru jednoho
hráče a pro síťovou hru v roli serveru. |
iListMaps |
-e |
Vylistuje mapy na standardní výstup. |
iPrintHelp |
-h |
Vytiskne stručný popis parametrů. |
iNoSound |
- |
Není implementováno. |
iNetworkHost, iTimeOut |
-s -t <ms> |
Spustí hru jako Server. Je nutné použít parametr -m pro nastavení
mapy. Program pak čeká ms milisekund, dokud se nepřipojí nějací klienti
a spustí mapu se zbytek počítačových hráčů. |
iNetworkClient, szConnectTo |
-c <adr> |
Připojí se na hru na adrese adresa adr jako klient. |
iRunAsDemon |
-d |
Zatím není implementováno. Nefunguje |
iDevelopersConsole |
-x |
Dovolí během hry otvírat vývojovou konzoli pro spouštění speciálních
příkazů. |
iUseProfileName, szProfileName |
-p <jméno> |
Spustí hru v profilu jméno. Pokud se použije některý ze zrychlených
spuštění hry, a nepoužije tento parametr, spustí se hra v posledním
profilu. |
Tabulka 2.9: Parametry příkazového řádku.
Výstup je standardně prováděn přes funkci CONSOLE()
, která je implementována v závislosti na OS. V Linuxu vypisuje na
standardní výstup a ve WIN32 prostřednictvím volání
MessageBox(). Některá strukturované vypisy
nejsou ve WIN32 dostupné. CONSOLE() se
používá i pro výstup chyb během chodu programu. K těm by ovšem nemělo
docházet.