6. diel - XNA tvorba v 3D - Engine druhýkrát a nie naposledy
Vitajte siedmykrát. Minule sme si pripravili triedu enginu, dnes sa pozrieme
na triedu GameScreen
ktorá nám reprezentuje herné okna. Už
minule sme si v nej pripravili dve virtuálne metódy Update
a
Draw
. Predovšetkým si vytvoríme konštruktor. Jeho jediným
parametrom je meno okna. Meno nie je až tak systémovo dôležité, ale pre
editor sa nám bude veľmi hodiť. Zároveň by bolo dobré, keby meno nebolo
null
a alebo prázdny reťazec.
private string fName;//vodackovina public string Name{ get{ return fName; } set { if (!String.IsNullOrEmpty(value)){ fName = value; } else{ if (fName == null) fName = "Herni okno"; } } } public GameScreen(string jmeno){ Name = jmeno; }
Ďalej bude potrebné zaviesť poľa pre komponenty. Opäť použijeme generický List:
private List<Component> fComponents; public List<Component> Components{ get{ return fComponents; } }
V konstruktoru tradične inicializujeme:
fComponents = new List<Component>();
Pridáme metódu AddComponent
, cez ktorú budeme komponenty
pridávať. Na mieste bude asi pridávanú komponent otestovať, či ak ju už
nemáme v zaznačené.
public void AddComponent(Component c){ if (!Components.Contains(c)){ Components.Add(c); } }
Podobne ľahko zatiaľ vytvoríme metódu RemoveComponent
:
public void RemoveComponent(Component c){ fComponents.Remove(c); }
Teraz máme všetko pripravené a môžeme sa bližšie pozrieť na metódu
Update
. Tá, ako bolo už minule vysvetlené, sa stará o
updatované všetkých komponentov. Nemôžeme ich ale len tak položku po
položke prejsť a zavolať ich vnútorné metódu Update
. Čo keď
by sa komponent rozhodla zmazať sa z okna? Alebo by naopak vytvorila svoju
kamarátku, ktorú nutne potrebuje. V takom prípade by nám aplikácia spadla.
Obísť to možno veľmi ľahko. Vytvoríme si ďalší List
a do
neho súčasné komponenty prekopíruje a všetko budeme volať v ňom. Najprv
si ale vytvoríme virtuálne metódy Update
a Draw
(nech ju máme pripravenú pre ďalšiu písanie) v triede
Component
:
public virtual void Update(){ } public virtual void Draw(){ }
V metóde Update
teda prvýkrát vyčistíme pomocné pole.
Všetko do neho nakopírujeme a neskôr ho prejdeme:
public virtual void Update(){ updated.Clear(); foreach (Component c in fComponents){ updated.Add(c); } foreach (Component c in updated){ c.Update(); } }
Metóda Draw
je na tom obdobne. Tu ale postačí iba prejsť
komponenty a zavolať ich Draw
metódu. Pri vykreslenie by sa
nemalo stať, že by sa nám komponent zmazala a alebo si urobila
kamarátku:
public virtual void Draw(){ foreach (Component c in fComponents){ c.Draw(); } }
Bude sa nám tiež hodiť metóda LoadGameScreen
, kde môžeme
vykonať nahranie dôležitých zložiek okna. Zaistíme tiež, že nebude táto
metóda zavolaná viackrát ako raz. Metóda nie je virtuálne (teda nedá
potomkami prepísať) je to tak schválne. Na účely potomkov je tu virtuálny
chránená metóda Load
, ktorá sa tu volá:
bool loaded; public void LoadGameScreen(){ if (loaded) return; loaded = true; // sem muzeme pozdeji pridat ncitani treba systemu svetel a dalsich veci ktere jsou pro // vsechna okna spolecne a musi byt vzdy nahrany Load(); } protected virtual void Load(){ // kdezto sem dame veci specificke pro kazde dalsi zdedene okno, //pridavani komponent a jine } public bool Loaded{ get{ return loaded; } }
Mohlo by sa zdať, že to je z triedy GameScreen
všetko čo
potrebujeme. Nie je tomu tak. Ešte sa bude hodiť odkaz na engine, v ktorom je
okno umiestnené:
internal Engine engine; public Engine Engine{ get{ return engine; } }
Tento odkaz budeme nastavovať pri pridanie okna v metóde
PushGameScreen
. Do tejto metódy ešte pridáme kontrolu či ak nie
je okno už prítomné a zároveň skontrolujeme či ak dané herné okno
nepoužíva treba iná inštancia. Zavoláme tiež našu metódu
LoadGameScreen
. Výsledok bude teda vyzerať nasledovne:
public void PushGameScreen(GameScreen okno){ if (okno.Engine == null && !Screens.Contains(okno)){ Screens.Add(okno); okno.engine = this; okno.LoadGameScreen(); } }
V metóde PopGameScreen
oknu engine odstránime riadkom:
ret.engine = null;
Teraz to je konečne z triedy GameScreen
všetko podstatné.
Presuňme sa do triedy Component
. Každý komponent by si tiež
zaslúžila vlastné meno. Pre potreby editora ho vrelo uvítame. Meno
komponentu by ale malo byť unikátne v danom hernom okne. Táto požiadavka si
však ponecháme na inokedy. Uspokojíme sa zatiaľ s akýmkoľvek menom rovnako
ako u herného okna. Takže len vytvoríme premennú Name
a
necháme ju zatiaľ nenastavený. Taktiež vytvoríme premennú
Visible
, ktorá nám bude určovať, či ak sa má komponent
vykresľovať:
private string fName; public string Name{ get{ return fName; } set{ fName = value; } } public bool Visible{ get; set; }
A v konstruktoru, ktorý si tiež vytvoríme, nastavíme premennú
Visible
na true
:
public Component(){ Visible = true; }
Rovnako ako okno uchováva odkaz na engine, tak komponenta si bude uchovávať odkaz na svoje herné okno.
private GameScreen fParent; public GameScreen Parent{ get{ return fParent; } set{ if (fParent == value) return; if (fParent != null) fParent.RemoveComponent(this); fParent = value; if (value != null) fParent.AddComponent(this); } }
Zastavme sa u nastavovacie časti. Ak je nastavované okno rovnaké ako to ktoré už máme, neurobíme pochopiteľne nič. Inak okno odoberieme od starého a pridáme novému. Rovnaký trik žiaľ nebolo možné vykonať aj u herných okien. Engine nevlastní žiadnu metódu pre priame odobratie daného okna. Bude potrebné tiež prakticky rovnaký mechanizmus pre nahrávanie obsahu, aký sme si vytvorili u herného okná, takže len telegraficky:
bool loaded; public bool Loaded{ get{ return loaded; } } public void LoadComponent(){ if (loaded) return; loaded = true; Load(); } protected virtual void Load(){ }
Pri pridaní komponenty do herného okna ešte tieto metódy zavoláme a
nastavíme tiež Parent
. Pri odobratí okná nastavíme naopak
null
. Pridal som ešte pár testov pred pridaním a odobratím:
public void AddComponent(Component c){ if (c!=null && !Components.Contains(c)){ Components.Add(c); c.Parent = this; c.LoadComponent(); } } public void RemoveComponent(Component c){ if (c != null && Components.Contains(c)){ fComponents.Remove(c); c.Parent = null; } }
Ešte zohľadníme hodnotu v premennej Visible
v metóde
Draw
u herného okna:
if(c.Visible)c.Draw();
Skvele. Dúfam, že ste sa nestratili niekde cestou. Ak áno, nič sa nedeje. Sú tu komentáre a prípadne zachráni priložený kód pod článkom. Nabudúce si nami napísaný engine naroubujeme do našej hry. Pridáme si herné okno a skúsime si napísať prvý komponent.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 319x (1.58 MB)
Aplikácia je vrátane zdrojových kódov v jazyku C#