12. diel - 3D bludisko v XNA - Hráčska kamera
Vitajte po dva-a-dvadsiatej. V tomto diele si pokusnú guličku nahradíme kamerou a prvýkrát si teda vyskúšame bludisko prejsť ako hráči, teda z pohľadu 1. osoby.
Hráčska kamera
Ako kameru pre hráčov nemôžeme použiť tú čo máme teraz. Naša kamera
nerešpektuje kolízie a navyše s ňou dá lietať hore a dole. Vytvoríme si
teda kameru novú, do priečinka na kamery si pridáme nový súbor s triedou
FPSKamera
. Dediť budeme od TargetKamery
, rovnako ako
v prípade voľnej kamery. Potreba budú dve premenné pre natočenie kamery,
nič nové pod slnkom:
float fYaw, fPitch; public float Yaw{ get{ return fYaw; } set{ fYaw = value; } } public float Pitch{ get{ return fPitch; } set{ fPitch = value; } }
Novinkou je naopak kolízne gule.
BoundingSphere koule;
Ktorú si v konstruktoru spolu s ostatnými premennými nastavíme:
public FPSKamera(GameScreen okno, Vector3 pozice, Vector3 target) : base(okno, pozice, target){ fYaw = 0; fPitch = 0; koule = new BoundingSphere(pozice, 5); }
Pozícia stredu gule je rovnaká ako pozície kamery a polomer guľa je päť
jednotiek. Len pripomeniem, že veľkosť kociek sme si zvolili na 20 jednotiek,
takže je okolo gule dostatok miesta pre pohyb. Máme všetko pripravené až na
to, že kamera je zatiaľ statická. Vezmeme si metódu Update
z
voľnej kamery a tú si len mierne upravíme. Takže len pre úplnosť ako
metóda vyzerá:
public override void Update(){ fYaw -= Parent.Engine.Input.DeltaX*0.01f; fPitch -= Parent.Engine.Input.DeltaY * 0.01f; Matrix rotace = Matrix.CreateFromYawPitchRoll(fYaw, fPitch, 0); Vector3 posun = Vector3.Zero; if (Parent.Engine.Input.DrzenaKlavesa(Keys.Up)) posun += Vector3.Forward; if (Parent.Engine.Input.DrzenaKlavesa(Keys.Down)) posun += Vector3.Backward; if (Parent.Engine.Input.DrzenaKlavesa(Keys.Left)) posun += Vector3.Left; if (Parent.Engine.Input.DrzenaKlavesa(Keys.Right)) posun += Vector3.Right; posun *= 0.1f * (float)Parent.Engine.GameTime.ElapsedGameTime.TotalMilliseconds; Pozice += Vector3.Transform(posun,rotace); Target = Pozice + Vector3.Transform(Vector3.Forward,rotace); base.Update(); }
Prvá vec, ktorú musíme napraviť, je rotačné matice. Nechceme, aby bolo možné stúpať s kamerou hore a dole. Preto nastavíme druhý parameter na nulu:
Matrix rotace = Matrix.CreateFromYawPitchRoll(fYaw, 0, 0);
Rýchlosť pohybu je moc veľká, polovičné bude stačiť a preto zmeníme konštantu z 0,1 na 0,05:
posun *= 0.05f * (float)Parent.Engine.GameTime.ElapsedGameTime.TotalMilliseconds;
Teraz je čas zohľadniť kolízie. Máme vypočítané o koľko sa akým smerom chceme pohnúť. Rovnako ako u pokusné guličky si uložíme starú pozíciu:
Vector3 stara = koule.Center;
Vypočítame novú pozíciu guľa:
Pozice += Vector3.Transform(posun, rotace); koule.Center = Pozice;
A ak nie je pohyb nulový tak skontrolujeme kolízie:
if (posun != Vector3.Zero && Parent is CollidableGameScreen){ CollidableGameScreen okno = Parent as CollidableGameScreen; koule.Center = okno.CollisionManager.Collide(koule, stara, koule.Center); Pozice = koule.Center; }
Musíme posunúť cieľ kam sa kamera pozerá. Ale tu budeme potrebovať oba dva uhly, umožníme hráči pozerať sa hore a dole. Vypočítame si znovu rotačné maticu a výpočet ciele necháme tak ako bol:
rotace = Matrix.CreateFromYawPitchRoll(fYaw, fPitch, 0);
V hernom okne potom už len zmeníte nastavenie kameru za novovytvorenú. Jej polohu a to kam sa pozerá vezmeme z načítané mapy:
Kamera = new FPSKamera(this, new Vector3(mapa.Start.X, 10f, mapa.Start.Z), new Vector3(mapa.Start.X, 10f, mapa.Start.Z));
Všimnite si, že som zvolil výšku 10. Pokusne som sa k tomuto číslu
dostal a skrátka to s ním vyzeralo asi najlepšie. Pre budúce použitie sa
nám síce moc hodiť nebude a to v prípade, kedy by sme chceli aplikovať
gravitáciu a brať výšku z terénu. Zatiaľ to ale bude stačiť. Ak si teraz
skúsite hru zapnúť a testovacie bludisko si prejsť, skôr alebo neskôr
narazíte na problém. Myš sa vám dostane na koniec obrazovky a jednoducho už
nemôžete zatáčať na jednu stranu. To je celkom veľký problém, avšak nie je neriešiteľný. Do
triedy Input
, ktorá sa nám stará o klávesnicu a myš, si
pridáme novú metódu CenterMouse
, ktorá nám myš pekne
vycentruje na stred obrazovky a nikdy sa nám už nestane, že by sa myš
dostala do pozície, z ktorej by nám nešlo hru ovládať. Nie som si istý,
ako presne tento problém rieši ostatné, ale podľa mňa to asi ani inak
nejde. Do tejto triedy si najprv pridáme premennú pre engine, skrze nej budeme
získavať veľkosť okna a budeme môcť myš vždy centrovať:
private Engine Engine;
V kontruktoru ju nastavíme:
public Input(Engine en){
Engine = en;
}
A konečne môžeme pridať onú metódu CenterMouse
, tá myš
vycentruje:
public void CenterMouse(){ Mouse.SetPosition(Engine.GraphicsDevice.PresentationParameters.BackBufferWidth / 2, Engine.GraphicsDevice.PresentationParameters.BackBufferHeight / 2); mysState = Mouse.GetState(); }
V konstruktoru enginu potom pridáme parameter:
fInput = new Input(this);
A máme hotovo. V našej novej kamere potom už len túto metódu zavoláme. A to ihneď po tom, čo zistíme o koľko sa myš pohla:
Parent.Engine.Input.CenterMouse();
Hotovo. Teraz už by sa malo podariť bludisko prejsť bez komplikácií. Je pravdou že kolízie nie sú optimálne a že sa občas stane že sa postava zasekne, obzvlášť keď vyberá zákrutu alebo sa snažia kĺzať po stene. Je to ale dúfam prijateľná obeť za jednoduchosť toho ako sú kolízie riešené.
To by bolo pre dnešok všetko. Nabudúce neviem čo urobíme, máme možnosť urobiť menu a hru tak doobalit do nejakého výsledného tvaru. Opäť čakám na komentáre.
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é 267x (1.78 MB)
Aplikácia je vrátane zdrojových kódov v jazyku C#