Lekce 9 - 3D bludiště v XNA - Kolize podruhé
Vítejte po devatenácté. Posledně, 3D bludiště v XNA - Kolize poprvé, jsme si připravili velmi primitivní kolizní manažer, který se nám postará o základní kolize.
V tomto díle si jej dokončíme, přidáme mu metodu pro hledání kolize a také si kolize vyzkoušíme. Jdeme na to.
Ještě než přidáme kolizní metodu, tak si přidáme vykreslení všech kolizních tvarů. To se myslím bude velmi hodit. Otevřeme si třídu s manažerem a přidáme si tam proměnnou, se kterou budeme vykreslování povolovat nebo zakazovat.
public bool DebugDraw=true;
A dále metodu Draw
, kde vše vykreslíme, máme-li to
dovoleno.
public void Draw(Matrix View, Matrix Projection){ if (DebugDraw){ foreach (BoundingBox box in Boxes){ BoundingRenderer.Render(box, View, Projection, Color.Black); } } }
Ještě si ji v herním okně zavoláme:
public override void Draw(){ base.Draw(); if (CollisionManager.DebugDraw) CollisionManager.Draw(Kamera.View, Kamera.Projection); }
A to je vše. Není to brnkačka? Celý systém se nám opět začíná vyplácet a vložená námaha vracet. Stejně jako to bylo s komponentami. Řešení celého bludiště pak bylo otázkou jen pár řádků. Poslední věcí v základním kolizním manažeru je bezesporu metoda pro řešení kolizí.
Hledání kolize
V zájmu největší jednoduchosti bude tato metoda velmi snadná. Přidáme
si tedy metodu Collide
. Jako parametry dovnitř vstupuje kolizní
koule, u které chceme, aby se zkontrolovala kolize. Dále stará poloha koule a
poloha nová. Kouli otestujeme vůči všem zaregistrovaným krabicím a
kolidující si uložíme do pole. Pokud v poli nic není, nedošlo k žádné
kolizi a my můžeme v klidu s koulí hnout na novou pozici. Pokud ale v poli
nějaké prvky máme, tak pohyb koule nedovolíme a vrátíme starou pozici. Je
to velmi primitivní způsob, nicméně pro začátek dostačuje velmi dobře.
Přídáme si tedy tuto metodu:
public Vector3 Collide(BoundingSphere sphere, Vector3 old, Vector3 nova)
Projedeme všechny zaregistrované krabice a zkontrolujeme zda kolidují. Pokud ano, přidáme je do pole:
List<BoundingBox> colliding = new List<BoundingBox>(); foreach (BoundingBox box in Boxes){ if (sphere.Intersects(box)){ colliding.Add(box); } }
A potom pouze testujeme na velikost pole:
if (colliding.Count != 0){ return old; } return nova;
To je vše. Opravdu to je vše. Možná se ptáte proč dáváme kolidující krabice do pole, když pro ně zatím nemáme žádné využití. Ano nemáme pro to žádné použití. Prozatím. A nyní k tomu vytouženému bodu...
Používáme kolizní manažer
Máme vše více-méně hotovo a tak můžeme přikročit k reálné aplikaci na našem bludišti. Budeme nyní výhradně pracovat v naší hře. Třída s naším herním oknem nebude dědit od základního okna, ale od okna umožňující kolize, takže tedy z
public class MojeHerniOkno: GameScreen
převedeme na:
public class MojeHerniOkno: CollidableGameScreen
Jediný objekt, který se kterým budeme chtít kolidovat bude políčko se zdí. To uděláme tak, že pouze opět změníme třídu od které budeme dědit. Takže tedy
public class Zed: Model3D
převedeme na
public class Zed: CollidableModel3D
A to je opět vše co musíme provést. Není nyní ten život tak snadný? Jistěže je. O nic se dál nestaráme, vše se vypočítá samo, vše se všude přidá samo zavoláme pak metodu pro kolizi a ono se vše vyřeší a my jen aplikujeme výsledek. Celkem fajn servis, však trvalo nějakou tu dobu, než jsme jej napsali, ale přesto to byla dobrá investice.
Pro testovací zkoušení si vytvoříme kouli, se kterou budeme hýbat
třeba klasickou sadou kláves WASD
. Přidáme si tedy nový soubor
s komponentou. Nazveme ji třeba PokusnaKulicka
a do ní si dáme
proměnnou pro kouli:
BoundingSphere koule;
Přepíšeme metodu Load
a v ní ji vytvoříme. Poloměr dáme
5 jednotek, krabice jsou velké 20, takže bude kolem koule bude dost místa.
Pozici dáme třeba (-10,5,0)
:
koule = new BoundingSphere(new Vector3(-10, 5f, 0), 5);
Přidáme metodu Update
, kde budeme koulí pohybovat. Vlastně
můžeme tuto část okopírovat 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ásobit nebudeme, rychlost je tak akorát. Je sice závislá na
FPS
, ale to nám v tomto zkušebním případu vadit nebude. Starou
pozici středu si uložíme a kouli posuneme na nové místo:
Vector3 stara = koule.Center; koule.Center += posun;
Pak pokud je posun nenulový, zkontrolujeme kolize a výsledek uložíme zpět do pozice středu koule. Zároveň uděláme kontrolu, zda-li je okno ve kterém je komponenta přidána herní okno, které kolize ovládá:
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še. Opravdu. Už jen tedy kouli vykreslíme, třeba žlutě:
BoundingRenderer.Render(koule, View, Projection, Color.Yellow);
Komponentu přidáme v herním okně mezi ostatní, ale až jako úplně poslední:
AddComponent(new PokusnaKulicka());
Pokud nyní hru spustíme, tak můžeme koulí po obrazovce hýbat a snad nám i koliduje se zdmi. Pokud ne, nebojte se ozvat v komentářích.
Ještě jedna drobnost. Hodilo by se kouli umístit přesně na místo startu, bude se to hodit pak později pro kameru s hráčem. K tomu bude potřeba menší změna v komponentě s mapou. Do načítání mapy přidáme pouze uložení počáteční dlaždice:
public Vector3 Start;
a do switche dáme výpočet této hodnoty:
case 99:{ c = new StartovniPodlaha(i, j); Start = new Vector3(10+i*20, 0, 10+j*20); break; }
Používaný vzorec je stejný jako u minulých výpočtů pozic. Vytvoříme konstruktor u třídy s pokusnou koulí a přidáme mu parametrem mapu bludiště:
Mapa mapa;
public PokusnaKulicka(Mapa map){
mapa = map;
}
Tu si uložíme a pak ji v načítání použijeme následovně:
koule = new BoundingSphere(new Vector3(mapa.Start.X, 5f, mapa.Start.Z), 5);
Vzoreček na výpočet polohy je stejný jako u tvorby bludiště. Výšku si raději nastavíme opět na poloměr, aby nebyla koule zabořená v podlaze.
To je myslím pro dnešek všechno. Jistě jste si všimli menší mezery v našem plánu. A nebo možná ani ne, ale to nevadí.
Příště, 3D bludiště v XNA - Kolize potřetí a snad naposledy, si ji pokusíme odstranit. Do té doby můžete komentovat, kritizovat, dotazovat se třeba v komentářích pod články.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 182x (1.78 MB)
Aplikace je včetně zdrojových kódů v jazyce C# XNA