9. diel - 3D bludisko v XNA - Kolízia druhýkrát
Vitajte po devätnástej. Naposledy sme si pripravili veľmi primitívne kolízne manažér, ktorý sa nám postará o základnej kolízie. V tomto diele si ho dokončíme, pridáme mu metódu pre hľadanie kolízie a tiež si kolízie vyskúšame. Ideme na to.
Ešte než pridáme kolízne metódu, tak si pridáme vykreslenie všetkých kolíznych tvarov. To sa myslím bude veľmi hodiť. Otvoríme si triedu s manažérom a pridáme si tam premennú, s ktorou budeme vykresľovanie povoľovať alebo zakazovať.
public bool DebugDraw=true;
A ďalej metódu Draw
, kde všetko vykreslíme, ak máme to
dovolené.
public void Draw(Matrix View, Matrix Projection){ if (DebugDraw){ foreach (BoundingBox box in Boxes){ BoundingRenderer.Render(box, View, Projection, Color.Black); } } }
Ešte si ju v hernom okne zavoláme:
public override void Draw(){ base.Draw(); if (CollisionManager.DebugDraw) CollisionManager.Draw(Kamera.View, Kamera.Projection); }
A to je všetko. Nie je to brnkačka? Celý systém sa nám opäť začína vyplácať a vložená námaha vracať. Rovnako ako to bolo s komponentmi. Riešenie celého bludisko potom bolo otázkou len pár riadkov. Poslednou vecou v základnom kolíznom správcovi je bezpochyby metóda pre riešenie kolízií.
Hľadanie kolízie
V záujme najväčšej jednoduchosti bude táto metóda veľmi jednoduchá.
Pridáme si teda metódu Collide
. Ako parametre dovnútra vstupuje
kolízne gule, u ktorej chceme, aby sa skontrolovala kolízie. Ďalej stará
poloha gule a poloha nová. Guľu otestujeme voči všetkým zaregistrovaným
krabiciam a kolidujúce si uložíme do poľa. Ak v poli nič nie je, nedošlo k
žiadnej kolízii a my môžeme v pokoji s guľou hnúť na novú pozíciu.
Pokiaľ ale v poli nejakej prvky máme, tak pohyb guľa nedovolíme a vrátime
starú pozíciu. Je to veľmi primitívny spôsob, však pre začiatok
dostačuje veľmi dobre. Pridáme si teda túto metódu:
public Vector3 Collide(BoundingSphere sphere, Vector3 old, Vector3 nova)
Prejdeme všetky zaregistrované krabice a skontrolujeme či kolidujú. Ak áno, pridáme ich do poľa:
List<BoundingBox> colliding = new List<BoundingBox>(); foreach (BoundingBox box in Boxes){ if (sphere.Intersects(box)){ colliding.Add(box); } }
A potom len testujeme na veľkosť poľa:
if (colliding.Count != 0){ return old; } return nova;
To je všetko. Naozaj to je všetko. Možno sa pýtate prečo dávame kolidujúce krabice do poľa, keď pre nich zatiaľ nemáme žiadne využitie. Áno nemáme pre to žiadne použitie. Zatiaľ. A teraz k tomu vytúženému bodu ...
Používame kolízne manažér
Máme všetko viac-menej hotové a tak môžeme prikročiť k reálnej aplikácii na našom bludisku. Budeme teraz výhradne pracovať v našej hre. Trieda s našim herným oknom nebude dediť od základného okna, ale od okna umožňujúce kolízie, takže teda z
public class MojeHerniOkno: GameScreen
prevedieme na:
public class MojeHerniOkno: CollidableGameScreen
Jediný objekt, ktorý s ktorým budeme chcieť kolidovať bude políčko sa múrov. To urobíme tak, že iba opäť zmeníme triedu od ktorej budeme dediť. takže teda
public class Zed: Model3D
prevedieme na
public class Zed: CollidableModel3D
A to je opäť všetko čo musíme urobiť. Nie je teraz ten život tak ľahký? Isteže je. O nič sa ďalej nestaráme, všetko sa vypočíta samo, všetko sa všade pridá samo zavoláme potom metódu pre kolíziu a ono sa všetko vyrieši a my len aplikujeme výsledok. Celkom fajn servis, však trvalo nejakú tú dobu, než sme ho napísali, ale napriek tomu to bola dobrá investícia.
Pre testovacie skúšanie si vytvoríme guľu, s ktorou budeme hýbať treba
klasickou sadou klávesov WASD
. Pridáme si teda nový súbor s
komponentom. Nazveme ju treba PokusnaKulicka
a do nej si dáme
premennú pre guľu:
BoundingSphere koule;
Prepíšeme metódu Load
a v nej ju vytvoríme. Polomer dáme 5
jednotiek, krabice sú veľké 20, takže bude okolo gule bude dosť miesta.
Pozíciu dáme potrebné (-10,5,0)
:
koule = new BoundingSphere(new Vector3(-10, 5f, 0), 5);
Pridáme metódu Update
, kde budeme guľou pohybovať. Vlastne
môžeme túto časť okopírovať z kamery, takže telegraficky:
Vector3 posun = Vector3.Zero; if (Parent.Engine.Input.DrzenaKlavesa(Keys.S)) posun += Vector3.Forward; if (Parent.Engine.Input.DrzenaKlavesa(Keys.W)) posun += Vector3.Backward; if (Parent.Engine.Input.DrzenaKlavesa(Keys.D)) posun += Vector3.Left; if (Parent.Engine.Input.DrzenaKlavesa(Keys.A)) posun += Vector3.Right;
Ničím násobiť nebudeme, rýchlosť je tak akurát. Je síce závislá na
FPS
, ale to nám v tomto skúšobnom prípadu vadiť nebude. Starú
pozíciu stredu si uložíme a guľu posunieme na nové miesto:
Vector3 stara = koule.Center; koule.Center += posun;
Potom ak je posun nenulový, skontrolujeme kolízie a výsledok uložíme späť do pozície stredu gule. Zároveň urobíme kontrolu, či je okno v ktorom je komponenta pridaná herné okno, ktoré kolízie ovláda:
if (posun != Vector3.Zero && Parent is CollidableGameScreen){ CollidableGameScreen okno = Parent as CollidableGameScreen; koule.Center = okno.CollisionManager.Collide(koule, stara, koule.Center); }
Vualáá to je všetko. Naozaj. Už len teda guľu vykreslíme, treba žlto:
BoundingRenderer.Render(koule, View, Projection, Color.Yellow);
Komponent pridáme v hernom okne medzi ostatné, ale až ako úplne posledná:
AddComponent(new PokusnaKulicka());
Ak teraz hru spustíme, tak môžeme guľou po obrazovke hýbať a snáď nám aj koliduje so múrmi. Ak nie, nebojte sa ozvať v komentároch.
Ešte jedna drobnosť. Hodilo by sa guľu umiestniť presne na miesto štartu, bude sa to hodiť potom neskôr pre kameru s hráčom. K tomu bude potrebné menšie zmena v komponente s mapou. Do načítanie mapy pridáme iba uloženie počiatočné dlaždice:
public Vector3 Start;
a do switche dáme výpočet tejto hodnoty:
case 99:{ c = new StartovniPodlaha(i, j); Start = new Vector3(10+i*20, 0, 10+j*20); break; }
Používaný vzorec je rovnaký ako u minulých výpočtov pozícií. Vytvoríme konštruktor u triedy s pokusnú guľou a pridáme mu parametrom mapu bludisko:
Mapa mapa;
public PokusnaKulicka(Mapa map){
mapa = map;
}
Tú si uložíme a potom ju v načítaní použijeme nasledovne:
koule = new BoundingSphere(new Vector3(mapa.Start.X, 5f, mapa.Start.Z), 5);
Vzorček na výpočet polohy je rovnaký ako u tvorby bludisko. Výšku si radšej nastavíme opäť na polomer, aby nebola guľa zaborená v podlahe.
To je myslím pre dnešok všetko. Iste ste si všimli menšie medzery v našom pláne. A alebo možno ani nie, ale to nevadí. Pokúsime si ju nabudúce odstrániť. Dovtedy môžete komentovať, kritizovať, pýtať sa napríklad v komentároch pod článkami.
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é 182x (1.78 MB)
Aplikácia je vrátane zdrojových kódov v jazyku C#