IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

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#

 

Predchádzajúci článok
3D bludisko v XNA - Kolízia prvýkrát
Všetky články v sekcii
3D bludisko v XNA
Preskočiť článok
(neodporúčame)
3D bludisko v XNA - Kolízia tretíkrát a snáď naposledy
Článok pre vás napísal vodacek
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Vodáček dělá že umí C#, naplno se již pět let angažuje v projektu ŽvB. Nyní studuje na FEI Upa informatiku, ikdyž si připadá spíš na ekonomice. Není mu také cizí PHP a SQL. Naopak cizí mu je Java a Python.
Aktivity