Lekce 12 - 3D bludiště v XNA - Hráčská kamera
Vítejte po dva-a-dvacáté. V předchozí lekci, 3D bludiště v XNA - Časujeme, jsme si přidali časomíru.
V tomto díle si pokusnou kuličku nahradíme kamerou a poprvé si tedy vyzkoušíme bludiště projít jako hráči, tedy z pohledu 1. osoby.
Hráčská kamera
Jako kameru pro hráče nemůžeme použít tu co máme nyní. Naše kamera
nerespektuje kolize a navíc s ní lze létat nahoru a dolů. Vytvoříme si
tedy kameru novou, do složky na kamery si přidáme nový soubor s třídou
FPSKamera
. Dědit budeme od TargetKamery
, stejně jako
v případě volné kamery. Potřeba budou dvě proměnné pro natočení
kamery, nic nového pod sluncem:
float fYaw, fPitch; public float Yaw{ get{ return fYaw; } set{ fYaw = value; } } public float Pitch{ get{ return fPitch; } set{ fPitch = value; } }
Novinkou je naopak kolizní koule.
BoundingSphere koule;
Kterou si v konstruktoru spolu s ostatními proměnnými nastavíme:
public FPSKamera(GameScreen okno, Vector3 pozice, Vector3 target) : base(okno, pozice, target){ fYaw = 0; fPitch = 0; koule = new BoundingSphere(pozice, 5); }
Pozice středu koule je stejná jako pozice kamery a poloměr koule je pět
jednotek. Jen připomenu, že velikost kostek jsme si zvolili na 20 jednotek,
takže je kolem koule dostatek místa pro pohyb. Máme vše připraveno až na
to, že kamera je zatím statická. Vezmeme si metodu Update
z
volné kamery a tu si jen mírně upravíme. Takže jen pro úplnost jak metoda
vypadá:
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(); }
První věc, kterou musíme napravit, je rotační matice. Nechceme, aby bylo možné stoupat s kamerou nahoru a dolů. Proto nastavíme druhý parametr na nulu:
Matrix rotace = Matrix.CreateFromYawPitchRoll(fYaw, 0, 0);
Rychlost pohybu je moc velká, poloviční bude stačit a proto změníme konstantu z 0,1 na 0,05:
posun *= 0.05f * (float)Parent.Engine.GameTime.ElapsedGameTime.TotalMilliseconds;
Nyní je čas zohlednit kolize. Máme vypočteno o kolik se jakým směrem chceme pohnout. Stejně jako u pokusné kuličky si uložíme starou pozici:
Vector3 stara = koule.Center;
Vypočteme novou pozici koule:
Pozice += Vector3.Transform(posun, rotace); koule.Center = Pozice;
A pokud není pohyb nulový tak zkontrolujeme kolize:
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 posunout cíl kam se kamera dívá. Ale zde budeme potřebovat oba dva úhly, umožníme hráči dívat se nahoru a dolů. Vypočteme si znovu rotační matici a výpočet cíle necháme tak jak byl:
rotace = Matrix.CreateFromYawPitchRoll(fYaw, fPitch, 0);
V herním okně pak už jen přenastavíme kameru za nově vytvořenou. Její polohu a to kam se dívá vezmeme z načtené mapy:
Kamera = new FPSKamera(this, new Vector3(mapa.Start.X, 10f, mapa.Start.Z), new Vector3(mapa.Start.X, 10f, mapa.Start.Z));
Povšimněte si, že jsem zvolil výšku 10. Pokusně jsem se k tomuto
číslu dostal a zkrátka to s ním vypadalo asi nejlépe. Pro budoucí
použití se nám sice moc hodit nebude a to v případě, kdy bychom chtěli
aplikovat gravitaci a brát výšku z terénu. Prozatím to ale bude stačit.
Pokud si nyní zkusíte hru zapnout a testovací bludiště si projít, dříve
nebo později narazíte na problém. Myš se vám dostane na konec obrazovky a
jednoduše už nemůžete zatáčet na jednu stranu. To je celkem velký problém,
avšak není neřešitelný. Do třídy
Input
, která se nám
stará o klávesnici a myš, si přidáme novou metodu CenterMouse
,
která nám myš pěkně vycentruje na střed obrazovky a nikdy se nám už
nestane, že by se myš dostala do pozice, ze které by nám nešlo hru
ovládat. Nejsem si jist, jak přesně tento problém řeší ostatní, ale
podle mě to asi ani jinak nejde. Do této třídy si předně přidáme
proměnnou pro engine, skrze ní budeme získávat velikost okna a budeme moci
myš vždy centrovat:
private Engine Engine;
V kontruktoru ji nastavíme:
public Input(Engine en){
Engine = en;
}
A konečně můžeme přidat onu metodu CenterMouse
, ta myš
vycentruje:
public void CenterMouse(){ Mouse.SetPosition(Engine.GraphicsDevice.PresentationParameters.BackBufferWidth / 2, Engine.GraphicsDevice.PresentationParameters.BackBufferHeight / 2); mysState = Mouse.GetState(); }
V konstruktoru enginu pak přidáme parametr:
fInput = new Input(this);
A máme hotovo. V naší nové kameře pak už jen tuto metodu zavoláme. A to ihned po tom, co zjistíme o kolik se myš pohnula:
Parent.Engine.Input.CenterMouse();
Hotovo. Nyní už by se mělo povést bludiště projít bez komplikací. Je pravdou že kolize nejsou optimální a že se občas stane že se postava zasekne, obzvláště když vybírá zatáčku nebo se snaží klouzat po zdi. Je to ale doufám přijatelná oběť za jednoduchost toho jak jsou kolize řešeny.

To by bylo pro dnešek vše.
Příště, 3D bludiště v XNA - Vertex a index buffer, se mrkneme na problematiku index a vertex bufferů. Opět čekám na komentáře.
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 267x (1.78 MB)
Aplikace je včetně zdrojových kódů v jazyce C# XNA