XNA

Az XNA működése

Erőforrások

Az XNA-nak nagy erőssége abban rejlik, hogy hogyan kezeli a különböző erőforrásokat. Minden olyan külső adatot erőforrásnak („art asset” vagy röviden „asset”) nevezünk, melyet valamikor,valahol felhasználunk a programunk futása során. Ezek lehetnek különböző 3D-s modellek, textúrák a modellekhez, shaderek, más 2D-s képek, betűtípusok vagy akár hanganyagok is.

Content Pipeline

A content pipeline segítségével tudunk beolvasni különböző erőforrásokat és azokat felhasználni a programunkban. Amikor létrehozásra kerül egy új XNA-s projekt észrevehetjük, hogy nem egy, hanem két projekt jelenik meg a Solution Explorerben. AZ első projekt maga a játék, míg a második a content, ahova beszúrhatjuk a különböző erőforrásainkat. Ezt követően valamely erőforrás betöltése a következőképpen történik:

Model model = Content.Load("aModel");

A fenti kódrészlet egy Model típusú változóba tölti be az aModel névre hallgató fájlt. Az erőforrások kitörléséhez a következő parancsot kell kiadni:

Content.Unload();

A content pipeline a következő formátumú fájlokat képes beolvasni:

Erőforrás típus Fájl típus
3D Modellek .x, .fbx
Textúrák/Képek .bmp, .dds, .dib, .hdr, .jpg, .pfm, .png, .ppm, .tga
Hangfájlok .xap (an XACT audio project), .wma, .mp3, .wav
Betűtípusok .spritefont
Effektek .fx

Egy fájl hozzáadásakor egy importáló komponens olvassa be magát a fájlt és adja tovább egy erőforrás feldolgozó egységnek. Ez alakítja át a nyers formátumú adatot valamely az eredeti fájl kiterjesztésétől függő objektumra, ezáltal létrehozva az úgynevezett feldolgozott adatot. Ez után a content pipeline végén elhelyezkedő „erőforrás fordító” az adatot egy ideiglenes fájlba helyezi, mely egy bináris, .xnb kiterjesztésű fájl. Valamely erőforrás betöltésekor az XNA ebből a fájlból olvassa ki az adatot és hoz létre belőle a memóriában valamilyen objektumot.

2D-s világ

Alapok

Az XNA megjelenítésének egyik módja a 2D-s megjelenítés, mely erősen különbözik a 3D-s megjelenítéstől. Míg az utóbbiban a koordináta rendszerünk egy világot ír le (erről lesz később szó), addig az előbbiben a képernyő pixeleit írja le. Emiatt fontos dolog, hogy az egész megjelenítés nem relatív, így például, ha a képernyő feléhez szeretnénk valamit kirajzolni, akkor bizony ki kell számolnunk, hogy hol is van a képernyő közepe.

Az XNA-s világban a megszokottól eltérő módon a koordinátarendszer origója a bal felső sarokban van. Az x tengely itt kezdődik és a jobb irányba tart, míg az y tengely lefelé növekszik.

2 dimenziós koordinátarendszer

Egy másik nagyon fontos dolog, a spiretok ismerete. Itt természetesen nem a citromízű italra gondolok, hanem 2 dimenziós képek, melyek általában egyszerű alakzatokat ábrázolnak. Legtöbbször egy alak, vagy valamilyen tárgy mozgásának különböző fázisai ábrázolják, melyeket egymás után játszunk le.

Egy sprite képsorozat

Spritebatch

A Spritebatchek a legfontosabb (tán az egyetlen fontos) összetevői a 2 dimenziós rajzolásnak. Ez az osztály több metódust is tartalmaz spriteok megjelenítésére. Egy spritebatch osztályt a következőképpen, pofonegyszerűen lehet példányosítani:

spriteBatch = new SpriteBatch(GraphicsDevice);

A spritebatch konstruktorának át kell adnunk egy Graphics Device-t melyre végül is a rajzolást végzi. Ettől kezdve megkezdhetjük a rajzolást. Fontos megjegyezni, hogy az alakzatok tényleges kirajzolását meg kell, hogy előzze egy BeginDraw() és követnie kell egy EndDraw() függvényhívásnak. Ezekkel készítjük fel a rendszert arra, hogy a következőkben kirajzolás fog történni. A rajzolást a Draw(…) metódus meghívásával tehetjük meg, melynek több túlterhelt verziója is van, itt csak egyre fogok kitérni.

spriteBatch.Begin(); spriteBatch.Draw(background, new Rectangle(0, 0, 800, 480), Color.White); spriteBatch.End();

A fenti kódrészletben közöljük a rendszerrel, hogy rajzolni szeretnénk. Ezt követően egy a background változóba betöltött (jelen esetben) 2 dimenziós képet szeretnénk kirajzolni. Ahhoz hogy ezt megtegyük meg kell határoznunk, hogy a képernyő mely részén jelenjen meg. Ezt egy négyszög létrehozásával tehetjük meg, mely négy paramétert vár: az első két paraméter a kezdőpontot határozza meg, míg a másik kettő rendre a szélességet és a magasságot. Ezt követően csak a kirajzolás színét kell beállítanunk (azért fehér, hogy normál színében jelenjen meg a textúra).

A Draw függvény egy másik, túlterhelt verziójában azt is megadhatjuk, hogy a textúránk hány fokkal legyen elfordítva.

De hogy is működik?

A kirajzolás működése pofonegyszerű, mint az az alábbi képen is látszódik.

Egy XNA alkalmazás életciklusai

Egy XNA-s játék elindulásakor az első feladat mindig maga a játék inicializálása, a különböző osztályok, managerek létrehozása. Ezt követi a később majd használatos erőforrások betöltése. Innentől kezdve a játék tulajdonképpen egy végtelen ciklus, míg ki nem lépünk belőle valamilyen kívánt vagy nem kívánt módon. Először kirajzoljuk a bufferben (Graphics Device) levő dolgokat a képernyőre, majd frissítjük a játék állását. Ezt a két állapotot iteráljuk, majd a játékból kilépéskor az összes felhasznált erőforrást töröljük a memóriából.

3D-s világ

Alapok

Ahhoz, hogy meg tudjunk valamit jeleníteni 3 dimenzióban az objektumot el kell helyeznünk a világban. Ezt a világot három mátrixszal tudjuk leírni. A három mátrix a világ -, nézet – és projekciós mátrix. Ezek nélkül a játékunkban semmi sem jelenne meg.

Egy XNA alkalmazás életciklusai

Világ mátrix

A világ mátrixok segítségével tudjuk leírni, hogy a modellünk hol helyezkedik el a világban a többi modellhez képest. Ezeket a mátrixokat a „legnehezebb” létrehozni. Első körben tranformálni akarjuk a modellünk pontjait (elmozdítani, elcsúsztatni) egyik pontból a másikba.

Matrix.CreateTranslation(Vector3 position);

Ez után esetlegesen el akarjuk valamelyik tengelye mentén, majd vagy kicsinyíteni, vagy nagyítani szeretnénk rajta.

Matrix.CreateRotationX(float angleInRadians); Matrix.CreateRotationY(float angleInRadians); Matrix.CreateRotationZ(float angleInRadians); Matrix.CreateFromAxisAngle(Vector3 axis, float angleInRadians);

A mátrixokat összeszorozva (nem mindegy a sorrend!) kapjuk meg a végső világ mátrixot, melyet alkalmaznunk kell majd.

Matrix result = Matrix.CreateRotationX(MathHelper.ToRadians(45)) * Matrix.CreateTranslation(new Vector3(10, 0, 0));

Nézet mátrix

A nézet mátrix létrehozása sokkal egyszerűbb:

Matrix.CreateLookAt(Vector3 cameraPosition, Vector3 cameraTarget, Vector3 cameraUpVector);

A cameraPosition leírja, hogy a kamera hol helyezkedik el a világban, a cameraTarget azt, hogy mely pontba néz a kamera és végül a cameraUpVector meghatározza, hogy a kamerának merre van a „fel irány”. Abban az esetben, ha a felfelé irány egybe esik a kamera nézési irányával, akkor semmi sem kerül kirajzolásra.

Projekciós mátrix

Két féle projekciós mátrixot különböztetünk meg; ortogonális és perspektív projekció. A fő különbség a kettő között, hogy az ortogonális projekció esetén minden tárgy azonos méretű, míg perspektív esetben a távolabbi objektumok kisebbek.

Ortogonális projekció

Egy XNA alkalmazás életciklusai

Matrix.CreateOrthographic(float width, float height, float zNearPlane, float zFarPlane);

Ahol a paraméterek rendre: a projekció szélessége, magassága, a közeli és a távoli vágósík. Több függvény is kínálkozik e mátrix létrehozására, például eltolt középpontú.

Perspektív projekció

Egy XNA alkalmazás életciklusai

Matrix.CreatePerspectiveFieldOfView(float fieldOfView, float aspectRatio, float nearPlaneDistance, float farPlaneDistance);

Ahol a paraméterek rendre a látószög, a képernyő aránya, a közeli és a távoli vágósík.