2010. február 12., péntek

...it burns, burns, burns, the ring of fire...

Lassan két hete nem írtunk semmit, ugyhogy gyorsan bepótolom a lemaradást. Az elmúlt napokban sikerült jobban haladni, emiatt sem volt időm, energiám eddig jelentkezni.
A mostani újdonságok - merthogy több területtel is foglalkoztam párhuzamosan - közül a részecskrendszerről szeretnék írni egy kicsit.
Ahogy a bejegyzés címe is utal rá, részecskékkel, pontosabban egy úgynevezett részecskerendszerrel fogunk megjeleníteni a játékban mindenféle effekteket, úgy mint füst, tűz, robbanások, stb. Valljuk meg, egy ilyen klasszikus akciójátékban, ami a Hind-ünk tervezett zsánere, bizony előfordul, hogy ezt-azt fel kell gyújtani, robbantani, stb. Hogy is fog működni ez a gyakorlatban? Ahogy a neve is utal rá, a részecskerendszer részecskékkel dolgozik. Mielőtt jobban belemélyednénk ebbe a témakörbe, érdemes egy kis kitérőt tenni a billboard-ok irányába. De mi is az a billboard? Abból induljunk ki, hogy a háromdimenziós motorunk feladata a játék "működtetése" valós idóben. A valós idejű képszintézis azonban, különösen összetett objektumok esetén, problémás. Néhány esetben kisebb trükkökkel csalhatunk. Ez alatt azt értem, hogy bizonyos objektumokat nem modellezünk le, hanem egyszerűen csak kétdimenziós képként (textúra) jelenítjük meg őket. Az elgondolás abból ered, hogy egy kétdimenziós kép megjelenítése esetén teljesen mindegy, hogy bonyolultabb, vagy egyszerűbb objektumot ábrázol. A legkézenfekvőbb példa egy fa lombkoronájának megjelenítése. A levelek nagy száma miatt azok egyenkénti lemodellezése és megjelenítése rendkívül drága lenne, viszont egy fényképpel elfogadhatóan és nagy sebességgel megjeleníthető tetszőleges számú levél. A trükk arra épít, hogy ezek a jelenségek közelítőleg szimetrikusok, azaz a fontos irányokból tekintve őket, hasonló képet mutatnak. Ezeket a fontos irányokat mindig az alkalmazás határozza meg. Például egy gyalogost szimuláló játékban elegendő a hengerszimmetria, hiszen egy fa esetén sem alá nem mászhatunk, se fölé nem repülhetünk. Ha ezekre a megjelenítési nézetekre is szükség lehet, gömbszimmetriát kell használni. Ha egy bonyolult geometriájú tárgyat a fényképével akarunk helyettesíteni, elegendő az összetett és bonyolult háromszögháló helyett csupán egy téglalapot kirajzolnunk, ami épp az adott fényképpel van megfelelően textúrázva. A képet tároló téglalap nem lehet a játéktérben rögzített, ugyanis ebben az esetben ha laposabb szögben tekintünk rá, akkor az észrevehetően elvékonyodik és máris lelepleződik a „csalás”. Sőt, ha a szem éppen a téglalap síkjában van, el is tűnhet a téglalap. Ez a módszer csak abban az esetben adna korrekt megoldást, ha a néző folyamatosan merőlegesen tekint a téglalapra, amire egy háromdimenziós játék esetén kevés az esély. Két megoldás adódik. Az egyik megoldás, hogy két egymásra merőleges képet használunk, a másik, hogy egyetlen képet forgatunk dinamikusan, azaz hogy mindig merőleges legyen a nézeti irányra. Ez így leírva kicsit száraznak tűnik, de aki játszott az első FPS-ként számontartott Wolfenstein3D-vel, vagy az azt követő forradalmi Doom sorozat játékaival, annak ismerős lehet a technológia. Ezekben a játékokban minden ellenfél, tárgy ezzel a módszerrel lett megjelenítve a raycasting render-el generált labirintusokban. Sőt, ha jól emlékszem az első Quake-ben, ami egyben az első full 3D FPS is, a robbanások, vér is billboard technikával jelent meg.
A játékunkban tehát a billboard egy olyan kétdimenziós kép, amely a háromdimenziós térben mindig a kamera felé van fordítva. Egy plakát kép elkészítésénél figyelembe kell venni, hogy a természeti jelenségek nem téglalap alakúak, a határuk általában szabálytalan. A megoldás, hogy a képeken átlátszó színeket is használunk és a megjelenítendő ábrán kívül minden pontot ezzel az átlátszó színnel definiálunk. A plakátokon általában csat teljesen átlátszatlan és teljesen átlátszó színek találhatók. Az a cél, hogy ahol a szín átlátszó, ott a rasztertár tartalmát a plakát ne változtassa meg, ahol pedig átlátszatlan ott pedig írja felül függetlenül az eredeti értékektől.
Lassan el is érkeztünk a részecskerendszer témakörhöz. Egy billboard nem csak állóképet, hanem akár "mozgást" is megjeleníthet, ha nem csak egyetlen képet, hanem egy képsorozatot rendelünk hozzá. Ha ezeket a képeket időben változtatjuk, animációt hozhatunk létre. Másik megoldás - és ezt használjuk a Hind-ban jelenleg -, hogy a plakát négyszög méretét, színét, pozícióját változtatjuk időben és ezzel egy részecskét hozunk létre. Sok ilyen részecske pedig egy részecskerendszert alkot. Egy részecskét egy textúrázott téglalappal reprezentáltam, mivel az még közelről is elfogadható látványt nyújt. Egy részecskét megadó textúra szinte mindig tartalmaz átlátszó képelemeket, mivel a részecskék a legritkább esetben téglalapok, ráadásul többnyire maguk is átlátszók (egy lángnyelven keresztül általában látható a háttér is).
Egy részecskeobjektum tehát rendelkezik néhány tulajdonsággal, úgymint pozíció, gyorsulás, sebesség, tömeg, tömegváltozás, élettartam, szín, színváltozás és méret. Ezekkel az értékeket állítgatva nagyon sokféle, és nagyon látványos effekteket hozhatunk létre. Hú, megint elég sokat írtam, de még meg akarom említeni a részecskerendszer emitter fogalmát. Az emitter használatával tudunk részecskéket generálni és kibocsájtani valamilyen irányba. Úgy kell elképlezni, mint egy ágyú, ami a megadott irányba lövöldöz adott tulajdonságú részecskéket. Természetesen ezzel az iránnyal is trükközhetünk. Véletlen generált irányvektorokkal ugyanis nagyszámú részecske esetén akár egy tüzijátékszerű "gömböt", azonos irányvektorral pedig például rakéta "kondenzcsíkot" is rajzolhatunk.
Egy teljes részecskerendszer tehát sok részecskeobjektum halmaza. Ezek dinamikusan születnek meg, majd tűnnek el haláluk után. Mindenesetre azért érdemes a részecskéket óvatosan használni, egy-két látványos effekt ugyanis akár több 1000 részecskéből állhat, ami máris több ezer négyszöget, illetve háromszöget jelent.

Lássuk, hogy néz ki mindez a játékunkban jelenleg:



Végül mai címadónk digitális avatárja:

2010. január 30., szombat

Mozdulj! Mozdulj! Mintha élnél ember...

Nem, nem állt le a fejlesztés. A ritkán megjelenő bejegyzések oka csupán az, hogy a játékot csak és kizárólag szabadidőnkben - ami az én esetemben sajnos a családtól vonódik el - van lehetőségünk fejleszteni. Az pedig nincs sok...
Sebaj, azért haladtunk egy kicsit az elmúlt bejegyzés óta. Szokásunkhoz híven próbálunk madárnyelven írni, hogy a laikusok is - mint mi - nagyjából értsék miről van szó, szóval minden expert-től elnézést kérünk, ha valami irgalmatlan nagy blődséget hordok itt össze a következő fejezetekben.
A legkomolyabb fejlődés az animált modellek támogatása az engine-ben. Röviden arról van szó, hogy találkozni fogunk olyan szereplőkkel is a Hind Action-ben, amelyek geometriája a mozgás során változik, pl. felbőszült modern kori janicsárokkal, akik bizony minden szerénységüket félretéve, RPG-vel próbálnak galambvadászatra invitálni minket. Igen, mi leszünk a galambok.
Az ilyen, animációval rendelkez szereplők leírásához ismernünk kell az összes lehetséges mozgásfázist. Ehhez valami olyan formátumot kellett keresni, ami tárolja mozgásfázisokat. Mivel anno 2004-2005-ben a szakdogámhoz a Quake2-ben prezentált MD2 fájlformátumhoz volt már szerencsém, azt gondoltam, hogy itt is ezt fogjuk használni. Maga a játék - leírni is szörnyű - 13 éve jelent meg, szóval nem mai csirke már ez az MD2 formátum sem, de első körben talán pont megfelelő lesz.
Egy kicsit magyarázom a bizonyítványomat:
Kétség kívül vannak már sokkal jobb formátumok is, ha csak azt vesszük figyelembe, hogy a Quake sorozat ötödik részét heggesztik valahol most is éppen valahol az Id Software-es fiúk. Arról nem is beszélve, hogy egy mai modern játék hasonló modelleinek már a hajszálai több poligonból állnak, mint az MD2 formátum által meghatározott 4096 poly-s maximum. Ez a hátrány kétségkívül a mi esetünkben inkább előny, hiszen madártávlatból nem nagyon fogjuk ezt hiányosságnak érezni - legalabbis remélem. :)
Az MD2 tehát egy bináris fájlformátum, ami, mint ahogy azt fentebb említettem egy karakter geometriáján kívül a mozgási lehetőségeket is képes tárolni. Mint a képleíró, illetve geometriai fájlok általában, ez a fájl is egy header résszel kezdődik. Pontosan most nem fogom felsorolni, mit tartalmaz a fejrész (részletes definíció és infók a formátumról itt), röviden egy leírást ad a karakter jellemzőiről, pl. vertex-ek száma, poly-k száma, textúra koordináták száma, illetve, hogy az adatrészben hol tárolódik a háromszögháló, a keretek definíciói, stb. Lehetőség van a háromszögháló értelmezéséhez használható OpenGL parancsok tárolására, valamint a modell festéséhez használható textúrafájlok (max. 32 féle skin) tárolására is. Előbbit nem használ(hat)juk, lévén a Quake2 eredetileg OpenGL-ben íródott, mi meg most XNA-ban akarjuk használni. A skin-ekről annyit írnék, hogy minden modellnek többféle textúrája volt, ezzel kívánták szemléltetni, hogy a találataink hatására hogyan amortizálódik az éppen hentelt ellenség (pl. vérfoltok).
A geometriai információk feldolgozására most nem térnék ki, ami minket jobban érdekelhet, az a mozgásfázisok kezelése. A karakter összes mozgása kulcskeretekben van definiálva, amelyeket több fázisra oszthatunk (pl. áldogál, fut, lő, szenved, meghal, stb.). Az animálás jelenthet egyszeri (várhatóan meghalni csak egyszer fog, azaz a halál fázist elég egyszer lejátszani), vagy ciklikus (fut) fázislejátszást. Minden fázisnak van kezdete, vége és lejátszási sebessége. Ezeket az információkat összevetve a modellidővel meghatározható, hogy pontosan melyik keretet kell bemutatnunk. Mivel a kulcskeretek egész számokhoz kapcsolódnak, valahogy fel kell dolgoznunk azokat az kereteket is, amelyek azonositója nem egész szám. Ellenkező esetben azt tapasztalnánk, hogy az animáció "akadozik", mivel nem kezeljük le a két kulcskeret közötti állapotokat. Ezt elkerülendő a két kulcskeretet jelölő egész szám közti keretet interpolálni kell, így folyamatos mozgást kapunk.
Az XNA framework természetesen alapból nem támogatja az ilyen típusú modellek betöltését, megjelenítését. Ahogy korábban említettük, fejlesztés közben folyamatosan szem előtt szeretnénk tartani a cross-platform futtatás lehetőségét, azaz, hogy PC mellett XBOX360-on is futtatható legyen a játék. Jelenlegi ismereteim szerint a konzolon mindenféle file-ok beolvasása nem kimondottan szerencsés, lehetőleg kerülendő. Mi akkor a megoldás? Szerencsére itt van nekünk a content-pipeline.
A content-pipeline teszi lehetővé, hogy mindenféle content-et (hangok, képek, modellek, stb.) be tudjunk tölteni a játékunkba. Természetesen számos ismertebb formátum (képformátumok, directx modellformátum, xml, stb.) alapból betölthető, azaz a framework fejlesztői leimplementálták a megfelelő importer, processor logikákat, úgyhogy ezek betöltésével nem kell bajlódnunk. Más a helyzet az MD2-vel. Ha szeretnénk MD2 formátumú fájlt betölteni a content-pipeline-ba (és mivel az XBOX360 támogatás miatt ez számunkra elengedhetetlen), akkor saját importert kell implementálnunk ehhez a fájltípushoz. Szerencsére erre is kínál lehetőséget az XNA framework.
Ádámot megkértem, hogy készítsen egy kis pilot version-t (ezt használtam fel később az MD2 importerhez), ezt fogom most bemutatni:

Röviden arról van szó, hogy van egy sima text fájlunk, ami leír egy háromszöget. Ezt szeretnénk betölteni a content-pipeline-ba, majd a képernyőn megjeleníteni.
A fájl tartalma:

v -0.500000 -0.500000 0.000000
v 0.000000 0.500000 0.000000
v 0.500000 -0.500000 0.000000

Vat tehát három v sor, ami megadja a háromszög három csúcsának (vertex-ének) koordinátáit.
Szükségünk lesz egy osztályra, ami majd tartalmazza ezeket a vertex-eket:

public class Triangle
{
public Vector3 v0;
public Vector3 v1;
public Vector3 v2;
}

A célunk az, hogy a txt fájlunkból legyen egy xnb fájl, amit majd konzolon is betudunk később olvasni. Ehhez írnunk kell egy saját importer osztályt:

[ContentImporter]
public class Importer : ContentImporter<Triangle>

A neve tehát Importer lesz, ezt fogjuk látni később a Visual Studio-ban, amikor a txt fájl felfűzzük a Content fára és beállítjuk a kívánt importert. Amint látjuk, az Importer osztály a ContentImporter template osztályból származik, ahol a template éppen a mi Triangle osztályunk. Az első dolgunk, hogy valamilyen, a .NET által adott módon beolvassuk, feldolgozzuk az információkat a txt fájlból. Nézzük, hogy csinálta Ádám:

public override Triangle Import(string filename, ContentImporterContext context)
{
List<Vector3> vectors = new List<Vector3>();

foreach (string[] line in GetLines(filename))
{
if (line[0] == "v")
vectors.Add(ParseVector3(line));
}

Triangle triangle = new Triangle();

triangle.v0 = vectors[0];
triangle.v1 = vectors[1];
triangle.v2 = vectors[2];

//majd visszadobjuk, es vegeztunk is.
return triangle;
}

Van tehát egy Import metódusunk, ami bejövő paraméterként megkapja a txt fájlunk nevét, a visszatérési értéke pedig egy Triangle típusú objektum. Röviden annyit csinálunk, hogy beparsoljuk a vektorokat egy listába, majd létrehozunk egy tirangle objektummot, amit szépen feltöltünk a három vertex-el, majd visszaadjuk. A GetLines() és ParseVector3() metódusok most nem lényegesek.
Most eljutottunk tehát odáig, hogy be van töltve a memóriába egy triangle objektum, amibe belepakoltuk a txt fájlból kiolvasott vertex koordinátákat. Mind a hármat.
Az ContentImporter-el beolvasott fájlokat az XNA framework egy úgynevezett XNB kiterjesztésű fájlba konvertálja, ez azt jelenti, hogy futásidőben már csak erre a titkosított XNB fájlra lesz szükségünk, a release tehát nem kell, hogy tartalmazza az eredeti txt fájlt.
Természetesen az XNA framework most még nem tudja, hogyan kellene ezt a txt fájlt XNB formátumba konvertálni, ehhez még kicsit dolgoznunk kell. Két osztályt kell még létrehoznunk:

[ContentTypeWriter]
public class Writer : ContentTypeWriter<Triangle>

{
protected override void Write(ContentWriter output, Triangle value)
{
output.Write(value.v0);
output.Write(value.v1);
output.Write(value.v2);
}

public override string GetRuntimeReader(TargetPlatform targetPlatform)
{
return typeof(Reader).AssemblyQualifiedName;
}
}

Először szükségünk lesz egy ContentTypeWriter osztályra. Ez nagyjából annyit definiál, hogy a kívánt adatok milyen sorrendben kerüljenek bele az XNB fájlba. A Write metódus két bejövő paraméterét felhasználva írhatunk a ContentReader-be. Amint látható, szépen beleírjuk a három vertex-ünket. A GetRuntimeReader() metódusban definiálhatjuk a Writer-hez a megfelelő Reader-t.
Nézzük most meg a beolvasási oldalt. Ezt hajtuk végre az XNB fájl beolvasásakor:

[ContentTypeReader]
public class Reader : ContentTypeReader<Triangle>

{
protected override Triangle Read(ContentReader input, Triangle existingInstance)
{
Triangle triangle = new Triangle();

triangle.v0 = input.ReadVector3();
triangle.v1 = input.ReadVector3();
triangle.v2 = input.ReadVector3();

return triangle;
}
}

Amint látható a Read metódusunk visszaad egy Triangle típusú osztályt, amit a ContentReader típusú input objektum segítségével töltünk fel. Arra kell csupán figyelnünk, hogy a kiírt, majd beolvasott adatok sorrendje, típusa és mérete szinkronban legyen.

Ezzel meg is volnánk az Importer-el. Semmi más dolgunk nincs, mint a Game osztályban a Content.Load(assetName) utasítással betöltsük, majd megjelenítsük az immár content-pipeline ready háromszögünket:

Triangle triangle = Content<Triangle>.Load("asd");

Ahol az 'asd' a felfűzött txt fájlunk Asset Name értéke.

Lássuk az eredményt:
















És végül egy videó, hogy is néz ki mindez a játékban jelenleg:

2010. január 12., kedd

Megjelenítés

Most akkor írnék egy kicsit a kirajzolásról. A részletekbe nem mennék túlságosan bele, inkább csak felületes áttekintőt mutatnék a különböző technikákról. A technika itt a különböző megjelenítési típusokat jelenti (egy modellen belül akár több is).

Kis kitérő:
Az objektumok ún. vertexekből (nagyjából háromdimenziós pontot jelent) állnak. A shaderrel történő renderelésnek (megjelenítés/kirajzolás) alapvetően két lépését különböztetjük meg: Vertex shader és Pixel shader. Ahogy a nevük is mutatja, az előbbi csak annyiszor fut le egy képkocka létrehozása közben, ahány vertex látható éppen a képernyőn, az utóbbi viszont azokra a pixelekre (képpont), ahol látható az adott object. Tehát például egy 30 vertexet tartalmazó, egész képernyőt befedő objektum 800x600-as felbontáson történő kirajzolása közben a vertex shader 30x fut le, míg a pixel shader 480000x (Természetesen ez az egyszerű eset, hiszen akár többször is lefuthat a pixel shader, ha például először kirajzolunk egy teáskannát, majd elé egy falat. Lefut a teáskannára is először, majd a falra. Erre kitaláltak többféle gyorsító eljárást is, esetleg későbbi bejegyzésben írok róluk).
Ezért is szoktak ún. lowpoly objektumokat használni. Pontosabb lenne a lowtriangle elnevezés, hiszen játékoknál háromszögekkel számlunk (három vertex foglal be egy háromszöget).

Nézzük akkor sorban őket (a számításokba nem mennék bele, inkább csak bemutató) :

- Alapvetően az ún. Normal mapping-et használjuk, ami nagyjából azt jelenti, hogy a felületen kis "buckákat" szimulálunk. Igen, szimuláljuk, hiszen "igazából" nincs ott annyi vertex, mint amennyinek látszik. Ez is felfogható valamilyen szinten gyorsító eljárásnak, hiszen nem kell lowpoly helyett highpoly modelleket kirajzolni.


- Most következzen a Cubemap (environment) reflection. Visszatükrözi az adott "dobozra" ráfeszített textúrákat. Ez nem "igazi" visszatükrözés, ahhoz raytracingre (sugárkövetés) lenne szükség (a kabin üvegén látszik).


- Végül az Alpha mapping: Ha van a diffuse (szín) textúránk mellé egy fekete-fehér alpha/opacity (átlátszóság) textúránk, akkor meg tudjuk oldani, hogy például a faág levelei ne modellek legyenek, hanem egy egyszerű plane (~lap) levél kinézetű átlátszósági textúrával. Erre mutatok példát:


Végül annyit tennék hozzá, hogy mindegyikkel képesek vagyunk valós idejű (real-time) árnyékot számolni. Talán későbbi postban erről is bővebben.
Ennyi fért most ebbe a rövid kis áttekintőbe. Alant látható egy összefoglaló videó az egészről.



2010. január 8., péntek

Miért Action?

Igérem ez az utolsó post, ami a miért kérdőszóval kezdődik... :)
Habár ha jobban belegondolok jobb megszokni ezeket a mondatokat, mert a 2 éves cserfes kislányom egyre nagyobb elánnal veti bele magát a témakörbe... azaz lassan minden mondata miértel kezdődik... :)
Gondolom többen vagyunk így, akik a tanuláson, munkán kívül hobbi szinten játékfejlesztgetéssel foglalkozunk, hogy a winchesterünk tele van jobbnál jobb, grandiózusnál grandiózusabb világmegváltó játékötletekkel. Így van ez velem is. A D:\ meghajóm works könyvtára telis tele van az elmúlás ködébe vesző játékkezdemények, doksik, content-ek kiszáradt porhüvelyével.
Ennek most vége - legalabbis remélem.
A blogban tárgyalt játékkal ugyanis megpróbálunk végre egy olyan célt kitűzni magunknak, amire talán van is esély, hogy befejezzük, de legalábbis demo állapotig eljuttatjuk.
A Hind tehát egy ízig-vérig shot 'em up akciójáték lesz. Valahogy úgy tessék elképzelni mint annak idején az Amiga 500-on debütáló és méltán sikereket elérő Desert Strike (később ha jól emlékszem megért egy Jungle Strike, majd Urban Strike folytatást is) című remek kis lövöldét, ahol is ál 3D-s (izometrikus) nézetben kellett a Comanche helikopterünkel operálva felrobbantani ezt-azt, lelőni néhány gyanús irakinak látszó tárgyat (személyt), kimenteni néhány MIA cimkéjű egyént.
A sikerek küldetések után mindenféle jutalmakat kaphatunk, amit később javításra, egyéb javadalmak vásárlására fordíthatunk. Elég elcsépelten hangzik, de nagyon jó lesz... :)
Terveink szerint bár a játék valós 3D-ben fog hasítani, bizonyos megkötések azonban lesznek. A helikoptert szigorúan felső nézetből láthatjuk majd, valahol a képernyő középső-alsó táján egy fix pontban. Ez olyan érzést kelt majd, hogy a táj mozog-forog alattunk.
Még a 90-es évek idején a DOS fénykorában volt egy játék, amit nagyon kedveltem. A címe Seek and Destroy volt.



Innen tehát az alapötlet.
A sztori, illetve a helyszín még erősen kidolgozás alatt áll, ötletek már vannak, történet író még nincs (lelki füleimmel hallom, hogy a gyengébb idegzetű olvasók közül néhányan már el is ájultak - természetesen van már tippünk).
Még azt sem tartom kizártnak, hogy Magyarország lesz a hadszintér és végre revansot vehetünk a 150 éves török megszállásért ;)
Terveink szerint PC-n és XBOX360 konzolon tehetjük majd meg ezt. Hogy mikor? Hogy egy remek példaképet idézzek: "When it's done!" (John Carmack) :)

2009. november 29., vasárnap

Miért XNA?

Most pedig írnék arról, hogy miért az XNA-t választottuk, és egyáltalán mi az.
Többen máshogy definiálják, de én maradnék annál, hogy egy framework.

Mit is jelent ez?
A 'framework' szóra rákeresve az angol-magyar szótárban, többek között a 'keret', 'váz' szót találjuk. Tehát az XNA egy keretrendszer, ami röviden, tömören annyit tesz, hogy rengeteg alap dolgot tartalmaz, amit saját magunknak kellene megírni mondjuk c++ DirectX kombóval (de akár c# MDX (= Managed DirectX) kombóval is). Magát a keretrendszert c#-al lehet használni, ebből adódott, adódik, és adódni is fog vita. A teljesítményt és a memóriakezelést hozzák fel a vita tárgyaként, mondván, hogy míg c++ esetén teljesen a mi kezünkben van a memóriakezelés (érsd: akkor foglalsz le és szabadítasz fel memóriát, amikor csak akarsz - meg nyilván amikor értelme is van -), addig a c# esetén az ún. GC (= Garbage Collector) irányítja ezeket, amire érkezik a sok támadás, miszerint nem látja el jól a feladatát (természetesen már sikerült bebizonyítani, hogy teljesen jól működik, talán a későbbiekben csinálok is erről egy felmérést, ha nagyon unatkoznék :)). Van néhány pontatlanság a wiki-s cikkben. Csak egyetlen példát írnék:
"Minden objektum törlődni fog, de nem tudni mikor." - Én pontosan tudom, hogy mikor fog törlődni: Akkor, amikor megszűnik rá minden hivatkozás. Csak egy példa a content kezelésre (XNA-s lebutított kódrészlet: )



/*Létrehozunk egy lokális content managert minden egyes pályához.*/
ContentManager content;

/*Amikor betöltjük a pályát*/
public void Load(...)
{
/*Elkészítjük a lokális content managert*/
content = new ContentManager(game.Services, game.Content.RootDirectory);

/*content betöltés...*/
}

/*Amikor kilépünk a pályáról, illene törölni mindent, amit erre a pályára betöltöttünk*/
public void Unload()
{
/*Itt a lényeg csupán annyi lenne, hogy minden egyes Model-t, Texture2D-t, és egyéb betöltött dolgokat 'null'-ra kell állítani. Ezzel tudjuk jelezni a GC-nek, hogy már nincs rá szükségünk*/

/*Miután mindent null-ra állítottunk, amit törölni szeretnénk:*/
content.Unload();
content = null; /*Megszűntetjük a hivatkozást a helyi content managgerre*/

GC.Collect(); /*Majd szólunk a GC-nek, hogy ideje takarítani :)*/
}



És lám, minden eltűnt, aminek kell. (én pl. úgy csináltam, hogy több 4048-as bmp-t betöltöttem (~12mb volt egy), majd töröltem őket, és ezt többször egymás után)

A másik, amit támadni szoktak az a JIT (= Just In Time) fordítás, ami azt a feladatot látja el, hogy futásidőben optimalizálja az adott gépre a kódot, szemben a c++ fordítókkal, amelyek natív kódot fordítanak, és éppen arra a gépre van optimalizálva, amelyikre "beállították" a fordítót. Az előbbi nyilván valamekkora teljesítményt igényel, ezért valamilyen szinten van is igazság abban, amit mondanak: nagy teljesítményigényes programok esetén a c#ban készültek lassabban futnak, mint a c++os változatuk.

De hát akkor kinek jó ez?
A casual/indie fejlesztőknek, illetve olyan embereknek, akik játékot szeretnének készíteni, és nem azzal akarnak foglalkozni, hogy az utolsó cseppig optimalizálják a saját (vagy egy ingyenesen letölthető / megvásárolt) engine-t. Emellett fontos megemlíteni a Multiplatform támogatást. Ezek közül is (számomra) mérhetetlenül fontos az Xbox360-ra való fordítás lehetősége. Ha a c++os játékunkat akarnánk Xbox360-ra fordítani, akkor ahhoz meg kellene vennünk a DevKit-et (= Developer Kit), amiről nincs információm, hogy mennyibe kerül, de amit félfüllel hallottam, az magánembernek (hacsak nem milliomos) szerintem megfizethetetlen. Természetesen XNA-val sem tudunk ingyen Xbox-ra fordítani, meg kell venni az éves díjú ún. Premium Account-ot (~20.000Ft/év); bővebb infó itt.
Természetesen, ha valakinek nem elégséges a rendszer által nyújtott teljesítmény, akkor szabadon átírhat nagyjából mindent, de nem hiszem, hogy egy garázsprojekt számára nem lenne elegendő.

Tehát senki sem fog tudni XNA-val Crysis 4-et fejleszteni, de nem is erre találták ki.

2009. november 28., szombat

Miért Hind?

Akkor lassan nézzünk a dolgok mögé: mit jelent a játék címe?
Hind. Angol-Magyar szótárban rákeresve (többek között) a szarvastehén kifejezést találhatjuk. :)
Játék szarvastehenekkel? Lelki szemeink előtt talán azonnal megjelenik egy vadász szimulátor vagy esetleg egy szarvas család tamagochi rémképe, de szerencsére ennek a szónak van egy további értelmezése is: NATO-kód.
A NATO-kód kifejezést a tagországok hozták létre a kínai és szovjet haditechnikai eszközök megnevezésére, mivel az eredeti típusnevekről esetenként nem is volt pontos információjuk. A kódnevek minden esetben angol főnevek, megkönnyítve ezzel is a azonosítást, illetve a kommunikációban való használatot. A kódnév első karaktere az eszköz jellegére utal, pl. a Tu-134-es szállítórepülő kódja Crusty, ahol a kezdőbetű az angol cargo(=szállító) szóból jön.
Ezzel el is érkeztünk mai témánkhoz. A H betűvel kezdődő kódok ugyanis minden esetben helikopterekre utalnak. Eszerint egy NATO-kód szótárban rákeresve a Hind szóra, (többek között) a Mi-24-es helikoptertípust találjuk. :)
Innen már nem nehéz kitalálni, hogy a fejlesztés alatt álló játékunk (és játékosa) ezzel a helikopterrel fog operálni.
Mit érdemes tudni erről a remek konstrukcióról?
Gondban lennénk, ha egyetlen kifejezéssel megpróbálnánk leírni, mi is pontosan a Mi-24. Repülő harckocsi, repülő erőd, esetleg felfegyverzett csapatszállító? Röviden: mindhárom egyben. Magát a gépet (talán indokolatlanul is) felfegyverzett csapatszállító helikopternek tervezték, továbblépve a Mi-8 (Hip) típus által kijelölt nyomvonalon.
A szovjetek elemezve az amerikaik vietnámi tapasztalatait (az már egy másik kérdés, hogyan jutottak ezekhez hozzá), arra jutottak, hogy szükség lenne egy olyan csapatszállítóra, amely képes a leszállási területét saját fedezőtűzzel biztosítani.
Az első Mi-24 A verzió így erős páncélt és fegyverzetet kapott. A személyzet 3 főt számlált, a pilóta mellett foglalt helyet a lövész másodpilóta, illetve mögöttük a fedélzeti technikus. A pilótafülke mögötti rakodótérben pedig 8 teljes fegyverzetű katonát (egy lövészraj) volt képes szállítani. Mindezek következtében ez a típus meglehetősen nagyra sikerült, az elvártnál sebezhetőbb lett a földi tűztől.
A Mi-8 helikoptereken is használt két TV2-117A gázturbinát a gép tetejére, a pilótafülke mögé építették, a főrotorlapátok átmérője azonban kisebb lett. A farokrotort a zajcsökkentés érdekében a függőleges vezérsík bal oldalán helyezték el. A hárompontos futómű minden eleme egyenként behúzható, a gép törzsébe rejthető. A törzs két oldalán rövid szárnyakat helyeztek el. Ezek a szárnyak amellett, hogy a teljes felhajtóerő mintegy negyedét biztosítják, lehetőséget adnak többféle fegyver felfüggesztésére is.
A Mi-24 A típust 1974-től az NDK-ban állomásozó szovjet csapatok a határvidék felügyelésére használták, de az igazi megmérettetés Afganisztánban következett.
A bevetéseken szerzett tapasztalatok bizonyos módosításokat, korszerűsítéseket tettek szükségessé. Ezek a módosítások eredményezték a Hind-D típus megjelenését. A hajtómű nagyobb teljesítménye mellett a legfontosabb módosítás a harckocsi elleni alkalmazást segítő pilótafülke-elrendezés kialakítása. A korábbi egymás melletti elhelyezést felváltotta a tandem-változat. A fegyverrendszer-operátor fölött és mögött ül a pilóta. Jelentősen javult a pilótafülkék elektronikája, illetve páncélozottsága. A legjelentősebb fegyverzeti módosítás a gép orra alatt elhelyezett 12,7 mm-es Gatling rendszerű elforgatható négycsöves géppuska.
Később az E, illetve F jelzésű típusok további elektronikai, optikai, illetve fegyverzeti módosítást eredményeztek.
A különböző típusokból 2400-nál is többet gyártottak, számos országban - így Magyarországon is - a mai napig hadrendben áll.

A játékban főszereplő Mil Mi-24 Hind-D főbb jellemzői:

Főrotorátmérő: 17,00 m
Farokrotor-átmérő: 3,90 m
Hosszúság: 17,40 m
Szélesség: ~2,00 m
Magasság: 6,50 m
Maximális felszálló tömeg: 11000 kg
Utazósebesség: 295 km/h
Repülési csúcsmagasság: 4500 m
Hatótávolság: 320 km
Első repülés: 1972

Végül egy videó...


... és egy nyugdíjas a Szolnoki Repülőmúzeumból (Fotó: Kis Dávid)


2009. november 24., kedd

Hát akkor kezdjük...

Játékfejlesztés.
Gondolom mindenkinek az életében van olyan szó, kifejezés, amit ha valahol meghall, azonnal megdobban a szíve. Hát valahogy így vagyok ezzel én is.
Probálkoztam már sok mindennel, egyetemen a szakdolgozatom témája 3D FPS játékfejlesztés OpenGL-ben, 2007-ben nehány szentesi barátommal garázs projectet kezdtünk először több, majd egyre kevesebb sikerrel. Jelentkeztem több magyar céghez is, de a BlackHole-on kívül sehova sem sikerült eljutni még interjúra sem.
Sebaj, újjult erővel az eddigi tapasztalatokat feldolgozva most újra belevágok.
A célplatform XNA lesz, a játék címe pedig Hind Action. Itt fogok rendszeresen beszámolni, hogy is haladunk. Igen haladunk, ugyanis egy volt BitBanditás (korábbi garázs csapat) cimborámmal Csiszár Ádámmal együtt fejlesztünk majd. Remelem Ő is posztol majd rendszeresen. Ezúttal nem fogjuk feladni, kívánom, hogy találkozzunk belátható időn belül az XBLA-n.