8. diel - 3D bludisko v XNA - Kolízia prvýkrát
Vitajte po osemnástej. V dnešnom diele sa pokúsime o kolízne manažér. Skoro určite sa to nezmestí do jedného dielu.
Už som sa o tom, ako to bude všetko fungovať, spomenul v jednom z predchádzajúcich článkov, ale napriek tomu radšej znovu všetko osvetlím. Každý model, s ktorým sa má kolízie odohrávať, si do kolízneho manažéru zaregistruje svojou krabici. Potom už len pri každom pohybe pohyblivého objektu skontrolujeme, či ak nám koliduje a ak áno, pohyb nepovolíme. To je všetko. Nič viac, nič menej. Pusťme sa teda do toho.
Okrem toho čo som naznačil vyššie bude potrebné vytvoriť si špeciálny herný okno s kolíznym manažérom. Vo všetkých situáciách ho nebude potrebné používať, treba pre menu a alebo pre iné hry. Preto potrebujeme novú triedu. Rovnako naložíme is modelom. Opäť vytvoríme vlastnú triedu a to všetko len pretože nie všetky modely potrebujú, aby sa s nimi kolidovalo.
Vytvoríme si zložku Collision
, kam budeme triedy súvisiace s
kolíziami skladovať. Pridáme si do nej triedu CollisionManager
.
To je práve tá trieda, ktorá sa nám stará o riešenie kolízií. Urobíme
ju verejnú, upravíme jej menný priestor. Základom bude zoznam všetkých
krabíc, s ktorými budeme kolidovať. Pridáme si ho:
protected List<BoundingBox> Boxes;
Ďalej bude potrebné odkaz na herný okno, ku ktorému manažér patrí.
Meno ponecháme tradičné Parent
:
public GameScreen Parent{ get; private set; }
V konstruktoru vytvoríme polia a priradíme herné okno:
public CollisionManager(GameScreen screen){ Parent = screen; Boxes = new List<BoundingBox>(); }
Ešte nám chýba metódy pre pridávanie a odoberanie krabíc. Nie je na nich nič moc neobvyklé:
public void AddBox(BoundingBox box){ if(!Boxes.Contains(box))Boxes.Add(box); } public void RemoveBox(BoundingBox box){ Boxes.Remove(box); }
Chýba už len metóda pre riešenie kolízií, ale tú si ponecháme na
neskôr. Pridáme si ďalšiu triedu CollidableGameScreen
alebo si
ju pomenujte akokoľvek je libo. Toto bude herné okno s práve vytvoreným
kolíznym manažérom. Dedíme od všeobecného herného okna a pridáme
kolízne manažér:
public CollisionManager CollisionManager{ get; set; }
V konstruktoru ho vytvoríme:
public CollidableGameScreen(string jmeno):base(jmeno){ CollisionManager = new CollisionManager(this); }
To je všetko Naozaj! Potrebujeme ešte jednu triedu pre model. Tú si pridáme do zložky s komponentmi. Pomenujeme si ju CollidableModel3D. Urobíme ju opäť verejnú, upravíme menný priestor, ale na to ste snáď už zvyknutí a to že budeme dediť od triedy Model3D je snáď tiež jasné. Budeme potrebovať celkom dve premenné pre kolízne krabice. Jednu pre základné netransformované, extrahované z modelu a druhú už transformovanú a pripravenú na použitie.
protected BoundingBox ZakladniBox; private BoundingBox fTransformedBox;
Verejne prístupná bude len transformovaná krabice. Pridáme teda getter a setter pre túto premennú:
public BoundingBox TransformedBox{ get{ return fTransformedBox; } private set{ if (fTransformedBox != value){ if (Parent!=null && Parent is CollidableGameScreen){ CollidableGameScreen okno = Parent as CollidableGameScreen; okno.CollisionManager.RemoveBox(fTransformedBox); okno.CollisionManager.AddBox(value); } fTransformedBox = value; } } }
Getter je celkom tradičné. Ale v Setter sa dejú nejaké čiary. Prejdime
si ich. Ak sa pokúsime krabici modifikovať, je potreba starú odobrať a novú
naopak pridať do kolízneho manažérovi. To zaistí, že krabice budú vždy
aktuálne. Prepíšeme metódu Load
, kde vytvoríme základnej
krabici a prvýkrát ju transformujeme.
protected override void Load(){ base.Load(); ZakladniBox=Utility.VypoctiBoundingBox(Model, transformace); TransformBox(); }
Metóda TransformBox
nie je žiadna iná ako tá, ktorú sme si
pripravili posledne, ale pre úplnosť ju znovu uvádzam, takže len
telegraficky:
protected void TransformBox(){ Matrix transform = Matrix.CreateScale(Meritko) * Matrix.CreateTranslation(Pozice); BoundingBox transformed = ZakladniBox; transformed.Min = Vector3.Transform(transformed.Min, transform); transformed.Max = Vector3.Transform(transformed.Max, transform); Vector3[] body = new Vector3[8]; transformed.GetCorners(body); for (int i = 0; i < body.Length; i++){ body[i] = Vector3.Transform(body[i], Rotace); } transformed = BoundingBox.CreateFromPoints(body); fTransformedBox.Min = transformed.Min; fTransformedBox.Max = transformed.Max; }
Toto metódu musíme ešte zavolať zakaždým v metóde Update
.
Nie je to moc ideálny stav, ale kvôli animáciám objektov je nutné všetko
prepočítať.
public override void Update(){ base.Update(); TransformBox(); }
Ďalšie nutnosťou sú konštruktory, iba len volajúci ich predkov:
public CollidableModel3D(Vector3 pozice, string model): this(pozice,Matrix.Identity,model){ } public CollidableModel3D(Vector3 pozice, Matrix rotace, string model): this(pozice,rotace,Vector3.One,model){ } public CollidableModel3D(Vector3 pozice, Matrix rotace, Vector3 meritko, string model):base(pozice,rotace,meritko,model){ }
Ešte nám zostáva zaregistrovať krabici ihneď, akonáhle je pridáme do
herného okna. Zdalo by sa, že stačí krabici pridať v metóde
Load
, ale nie je to pravda. Metóda Load
sa volá len
prvýkrát. Je potrebné dodať špeciálne metódy, ktoré sa zavolajú
zakaždým. Otvoríme si teda triedu so základnou komponentom a pridáme tam
dve virtuálne metódy.
public virtual void OnAdded(){ } public virtual void OnRemoved(GameScreen okno){ }
Metódy potom v hernom okne pri pridaní komponenty zavoláme. Hneď potom čo komponent nahráme:
c.LoadComponent(); // stary radek
c.OnAdded();
To isté pri odoberaní komponenty z herného okna.
c.Parent = null; // stary radek c.OnRemoved(this);
V triede s naším špeciálnym modelom prepíšeme obe metódy a v nich pridáme krabice do kolízneho manažéra:
public override void OnAdded(){ if (Parent is CollidableGameScreen){ CollidableGameScreen okno = Parent as CollidableGameScreen; okno.CollisionManager.AddBox(TransformedBox); } } public override void OnRemoved(GameScreen okno){ if (okno is CollidableGameScreen){ CollidableGameScreen okn = Parent as CollidableGameScreen; okn.CollisionManager.RemoveBox(TransformedBox); } }
Všetko je teraz pripravené. Aj keď sa to tak asi nezdá, chýba len samotný riešiteľ kolízií. Dnes sme napísali systém pre registráciu krabíc na jednom mieste. Touto jednou vetou sa dajú vyjadriť tri predchádzajúce stránky. Hrozné pomyslenie. Občas si hovorím že na túto prácu by sa hodil nejaký stroj, ktorý by sa pripojil na hlavu a len by stačilo vybaviť si čo je potrebné urobiť. Trebárs niekedy v budúcnosti.
V budúcom diele si vytvoríme metódu pre riešenie kolízií a tiež si ich vyskúšame. Na to ako kolízie kolidujú sa môžete pozrieť na videu dole. Čakám na komentáre pod článkom, otázky, námety, sťažnosti, nápady. Však to poznáte.
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é 153x (1.77 MB)
Aplikácia je vrátane zdrojových kódov v jazyku C#