A Unity rengeteg lehetőséget és szabaságot nyújt, így a legtöbb gondott nem is a játék megírása okozza, hanem annak a kitalálása, hogy hogy kezdjünk hozzá…
Kiskoromban rengeteg LEGO-szettem volt – imádtam építeni, mindig valami újat kitalálni. Jóformán meg is rökönyödtem, amikor két anyuka beszélgetését hallgattam a trolin:
– Ricsinek állandóan LEGO-t kell venni, alig bírjuk pénzzel… De legalább nagyon szereti: a múltkor egy kalózhajót épített át űrhajóvá.
– Petinek nem érdemes: egyszer kirakja az útmutató szerint, aztán porosodik a polcon. De hát nem is olyan jó matekból, mint a Ricsi…
Hogy lehet csak egyszer összeépíteni a LEGO-t? Mi köze a LEGO-nak a matekhoz? Bár lehet van benne valami… ☺
Építsünk világokat
A digitális LEGO annyiból jobb a valódinál, hogy végtelen építőkockánk van. Az már más, hogy itt ezeket a kockákat magunknak kell létrehozni.
Az előző posztban említettem, hogy a Unity elsősorban 3D-s játékmotor, de van lehetőség 2D-s játékok írására is. Ez a gyakorlatban azt jelenti, hogy minden játékelem a 3-dimenziós játéktérben helyezkedik el így is, úgy is, csak a kamera “tréfál meg” bennünket.
Perspektíva vs. ortografikus vetület
A perspektíva olyan ábrázolásmód, amely a tárgyak térbeliségét ábrázolja sík felületen: esetünkben a képernyőn. A távolabbi tárgyak kisebbnek, a közelebbiek pedig nagyobbnak tűnnek. Az ortografikus vetület teljesen elhagyja a mélységet (vagyis nem veszi figyelembe a perspektivikus ábrázolás során használt z-buffert), így az azonos méretű tárgyak ugyanakkorák akkor is, ha nagyon távol vannak, és akkor is, ha nagyon közel.

Ugyanannak a három kockának perspektivikus és ortografikus megjelenítése
Ha így nézzük, akkor az eredeti 1988-as játék is az ortografikus megjelenítést használja. Ezt szeretném én is elérni: csak nem majdnem-felülnézetből, hanem izometrikus nézetben.

A Soko-Ban két pályája
Izometrikus?
A 8-bites éra bővelkedik az izometrikus megjelenítésű játékokban. Néhány példa a teljesség igénye nélkül:

Syndicate, Commandos: Behind Enemy Lines, Fallout, SimCity 2000, Baldur’s Gate II: Shadows of Amn, Anno 1602, Age of Empires, Theme Hospital
Tehát a pályát kicsit felülről (kb. 30°-kal megdöntve), és kicsit elforgatva (általában 45°-kal) szemléljük.
3D
A 3-dimenziós motor miatt kézenfekvő, hogy 3-dimenziós elemeket is alkalmazzunk. Elég létrehozni a kis kockákat és lehet is építeni. Így akár létrehozhatjuk a következő Minecraftot is. ☺
Sajnos a Unity beépített kockáit nem lehet skinezni. Viszont rendelkeznek Box Colliderrel. Az egyetlen beépített komponens, aminél meg lehet változtatni natívan, hogy mit jelenítsen meg, az a Sprite. Nem tehetünk mást, magunknak kell egy skinezhető kockát kreálnunk:
- Hozzunk létre egy üres GameObjectet.
GameObject > Create Empty - Nevezzük át “Cube”-nak.
jobb klikk a GameObject-en > Rename - A Cube-on belül hozzunk létre három Sprite-ot. (Mivel csak egy irányból fogjuk látni, felesleges többet renderelni.)
GameObject > 2D Object > Sprite, majd húzzuk rá mindhárom Sprite objektumot a Cube-ra, hogy a gyerekei legyenek. - Méretezzük be a Sprite-okat.
- Igazítsuk őket egymáshoz úgy, hogy legyen egy közös csúcsuk, illetve páronként egy közös oldaluk, és páronként a lapjaik 90°-os szöget zárjanak be.
- Válasszuk ki, hogy milyen képet jelenítsenek meg.
- Végül adjunk a Cube-hoz egy Box Collider komponenst. Ezen fog a játékos később mászkálni.
A kész félkockából csináljunk Prefabot azzal, hogy behúzzuk az Assetek közé. Innentől kezdve kódból is hívható, beállítható lesz, és lehet is építeni.
2D
Mivel annyira tetszenek a régi 8-bites játékok, így azt szereném, hogy az én játékom is pixeles, retro hatású legyen. A 3D-s objektumokkal könnyű dolgunk volt, hisz azok mindenképp passzolni fognak egymáshoz. Nem úgy a 2D-seknél – pontosabban a kvázi 2D-seknél.
Hogy könnyű legyen a pályát kezelni és a játékost irányítani, ezért a pálya elemei továbbra is kockák lesznek. A különbség az, hogy most átlátszóak, és egy Sprite-tal fogjuk őket elfedni.
Persze ez nem is olyan könnyű, mint ahogy hangzik, de pár napos próbálgatás során sikerült a megfelelő beállításokat megtalálni.
Először érdemes azt a kamerabeállítást megtalálni, amit használni fogunk a játék során. Ne felejtsük el a Projectiont Orthographicra állítani.
- Hozzunk létre egy kockát.
GameObject > 3D Object > Cube - Adjunk hozzá gyermek elemként egy Sprite-ot, és állítsuk be rajta a grafikánkat.
- Igazítsuk a Sprite-ot úgy, hogy a grafikai elem teljesen eltakarja a kockát. Vegyük figyelembe a 30°-os kameradöntést. Ekkor a sprite középpontja a kocka egyik csúcsához van közel.
- Töröljük a kocka Mesh Renderer és a Mesh Filter komponenseit. Ekkor csak a Box Collider marad.
Végezetül a kész pixelkockából csináljunk Prefabot.
Automate
Kézzel egymás mellé rendezgetni a kockákat elég fárasztó dolog. Szerencsére írhatunk scriptet a pálya legenerálására.
A pályát véletlenszerűen szétszórt kockákból fogjuk összerakni. A Unity beépített véletlenszámgenerátorát fogjuk használni, ezért azt a using direktívák között specifikálnunk kell.
using Random = UnityEngine.Random;
Ahhoz, hogy változókat elérjük a Unity Inspectorjában, publicnak kell lenniük.
public int columns = 5; public int rows = 5;
A pixelkockák tárolására létrehozunk egy GameObject tömböt. Az Inspectorban ide húzzuk be a pixelkockák Prefabjait.
public GameObject[] tiles;
A pixelkockákat egy üres GameObject originjétől kezdve fogjuk tárolni: ez lesz a levelHolder.
private Transform levelHolder;
Létrehozzuk az új üres GameObjectet és eltároljuk a pozícióját. Ezek után létrehozunk a pixelkocka Prefabokból egy véletlen színű példányt és beállítjuk a Levelt szülőként. Az x és z változókat 0.32-vel be kell szorozni, mert ekkora méretűek a kockák oldalai. A kockákat az x és z tengelyen fogjuk elhelyezni, ezért az y koordináta mindig 0 lesz.
void LevelSetup() { levelHolder = new GameObject("Level").transform; for (int x = -1; x < columns + 1; x++) { for (int z = -1; z < rows + 1; z++) { GameObject toInstantiate = tiles[Random.Range(0,tiles.Length)]; GameObject instance = Instantiate(toInstantiate, new Vector3(x * 0.32f, 0f, z * 0.32f), Quaternion.identity) as GameObject; instance.transform.SetParent(levelHolder); } } }
Ezután már csak végre kell hajtani a korábban definiált metódust. Erre a Unity saját beépített metódusát használjuk: az Awake-et. Ez fog lefutni, amikor a Scene betöltődik a játékban.
void Awake() { LevelSetup(); } }
Unityben hozzunk létre egy üres GameObjectet és húzzuk rá a scriptet. A GameObjectre kattintva a scriptnél beállíthatjuk, hogy mekkora legyen a pályánk, illetve a felhasználandó pixelkockáinkat.
A kódot természetesen felhasználhatjuk a félkockák generálására is: