Bejegyzés

Objektum mozgatás Unity-ben

Nem lenne játék a játék mozgó objektumok nélkül. Azt hihetnénk, hogy ez egy nagyon egyszerű dolog: csak arrébb kell tenni az adott objektumot minden képkockában. A gyakorlat egy kicsit más, több mozgatási módszer is létezik. Ez a leírás minimális programozási ismereteket feltételez, de a kezdők is el fognak tudni igazodni a szkriptekben.

Az alapok

Van egy objektumunk és egy 2D-s felületen, az X tengelyen szeretnénk jobbra/balra mozogni a nyíl gombokkal:

Objektum

    using UnityEngine;
    public class PlayerController : MonoBehaviour {
        Rigidbody rb;
        public float speed = 10.0f;
        void Start () {
            rb = GetComponent();
        }
      void Update () {
            if (Input.GetKey(KeyCode.RightArrow))
            {
                rb.velocity = transform.right * speed;
            }
        }
    }

Így mozog, ha megnyomjuk a jobbra nyilat:

Jobbra mozgatás

Valami nincs rendben! Ha jobbra akarunk menni, miért indul el balra egy idő után a golyó? Ennek az az oka, hogy a golyó vektorai együtt forognak az objektummal. Egy idő után a golyó átfordul, és a jobbra irányszámunkra máris balt jelent.

Rögzíthetjük a golyót, hogy ne forogjon, ha befagyasztjuk a forgását:

    rb.freezeRotation = true;

Miután a sebességet 2.0f-re változtattuk, és a fenti sort hozzáadtuk, ilyesmi eredményt kapunk:

Jobbra mozgatás

Ez már jobban néz ki, de még mindig javíthatunk rajta.

Balra is szeretnénk menni, ehhez kicsit módosítani kell a kódon:

    using UnityEngine;
    public class PlayerController : MonoBehaviour {
        Rigidbody rb;
        public float speed = 2.0f;
        void Start () {
            rb = GetComponent();
            rb.freezeRotation = true;
        }
      void Update () {
            if (Input.GetKey(KeyCode.RightArrow))
            {
                rb.velocity = transform.right * speed;
            }
            if (Input.GetKey(KeyCode.LeftArrow))
            {
                rb.velocity = -transform.right * speed;
            }
        }
    }

Mivel nincs transform.left funkció, ezért a transform.right funckiót kell tükrözni, azzal hogy elé teszünk egy mínusz jelet.

A módosítások után már tudunk jobbra és balra is mozogni a golyóval. Amennyiben további dimenziókat szeretnénk hozzáadni a mozgáshoz, akkor a Z tengelyen történő elmozdulást kell kezelnünk, hogy a talaj mentén tudjunk közlekedni.

Az előre történő mozgáshoz a következő sort kell használnunk:

    rb.velocity = new Vector3(0, 0, 1) * speed;

Ez azt eredményezi, mint a fenti példa, de egy 3D-s vektort hív ehhez segítségül.

A teljes kód:

    using UnityEngine;
    public class PlayerController : MonoBehaviour {
        Rigidbody rb;
        public float speed = 2.0f;
        void Start () {
            rb = GetComponent();
            rb.freezeRotation = true;
        }
      void Update () {
            if (Input.GetKey(KeyCode.RightArrow))
            {
                rb.velocity = transform.right * speed;
            }
            if (Input.GetKey(KeyCode.LeftArrow))
            {
                rb.velocity = -transform.right * speed;
            }
            if (Input.GetKey(KeyCode.UpArrow))
            {
                rb.velocity = new Vector3(0, 0, 1) * speed;
            }
            if (Input.GetKey(KeyCode.DownArrow))
            {
                rb.velocity = new Vector3(0, 0, -1) * speed;
            }
        }
    }

Mozgás minden irányban

A második módszer

Létezik alternatív megoldás is arra, hogy a golyót mozgassuk. Eddig a transform funkciókat használtuk, ami nem ad túl realisztikus mozgást. Az Input.GetAxis() használatával lehetőségünk van realisztikusabban mozgtani az objektumokat, mivel a nyers, “tedd odébb” parancsok helyett fizikai erővel hatunk az objektumokra, így idézve elő a mozgást.

    using UnityEngine;
    public class PlayerController : MonoBehaviour {
        Rigidbody rb;
        public float speed = 2.0f;
        void Start () {
            rb = GetComponent();
        }
      void Update () {
            float moveHorizontal = Input.GetAxis("Horizontal");
            float moveVertical = Input.GetAxis("Vertical");
            rb.AddForce(new Vector3(moveHorizontal, 0.0f, moveVertical) * speed);
        }
    }

Görgetés

A mozgatás RigidBody alapú, így ha módosítjuk a tömeget, a súrlódást, az hatással lesz a mozgatási képességre is.

A harmadik módszer

Egy másik lehetőség, hogy sebességet adunk a golyónak a fel/le nyilakkal, és forgatjuk a balra/jobbra nyilakkal:

    using UnityEngine;
    public class PlayerController : MonoBehaviour {
        public float movementSpeed = 5.0f;
        public float rotationSpeed = 200.0f;
        void Update () {
            transform.Rotate(0, Input.GetAxis("Horizontal") * Time.deltaTime * rotationSpeed, 0);
            transform.Translate(0, 0, Input.GetAxis("Vertical") * Time.deltaTime * movementSpeed);
        }
    }

Mozgó mosolygó labda

Két lehetséges megoldást kombináltunk, így kaptuk meg a harmadikat. A transform funciókat és a GetAxis()-t használtuk, amely kiszámíthatóbb mozgást tesz lehetővé, ezért ez jól használható például versenyzős játékok esetében.

A Unity-nek van egy beépített karaktervezérlője is, erre is érdemes egy pillantást vetnünk:

Karakter kontroller

A kód, amellyel WASD gombokkal tudunk mozogni:

    using UnityEngine;
    public class PlayerController : MonoBehaviour {
        CharacterController characterController;
        public float movementSpeed = 5.0f;
        private Vector3 moveDirection = Vector3.zero;
        void Start()
        {
            characterController = GetComponent();
        }
        void Update () {
            if (characterController.isGrounded)
            {
                moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
                moveDirection = moveDirection * movementSpeed;
            }
            //Gravity
            moveDirection.y -= 10f * Time.deltaTime;
            characterController.Move(moveDirection * Time.deltaTime);
        }
    }

 

Ebben a megoldásban nem használjuk a RigidBody-t, így a gravitációt magunknak kell megírnunk.

Összegzés

A helyzettől függ, hogy melyik megoldást érdemes alkalmaznunk. Olyan esetben, amikor valaminek X idő alatt pontosan Y távolságot kell megtennie, kerüljük a fizikai erőkkel történő mozgatást, és inkább a transform paraméterek módosításával mozgassunk. A realisztikusabb mozgáshoz, amelyben a fizikát is alkalmazni akarjuk, az AddForce funcióval érdemes dolgoznunk.

Természetesen ezek nem kőbe vésett szabályok, lehetnek egy játékban olyan események is, amikor az AddForce alapú mozgatás a normál, míg bizonyos eseményeknél a velocity-vel kell operálni.

Forrás: Noob Programmer

Skeldar

Kezdők bevezetés a Unity-be (4. rész)

Az előző részekben megismerkedhettünk a környezettel, ahol a játékprogramozás zajlik, most viszont eljött az idő, hogy valóban elkészítsünk egy játékot. A gyakorlás céljából elkészítendő játék egy nagyon egyszerű, űrhajós-lövöldözős játék lesz. A játékkészítés során a következő dolgokat fogjuk elsajátítani:

  • Project ablak használata, asset-ek importálása és rendezgetése
  • Különbség a GameObject-ek és a Prefab-ok között
  • Unity fizika
  • Kamerák működése, a nézetek típusai
  • A Unity-ben lévő anyagok alapjai

A játék előre elkészített asset-ekből fog felépülni, de a későbbiekben a saját asset-ek készítésével és szkriptek írásával is megismerkedünk. Ha majd mindennel elkészültünk, akkor valami ilyesmi eredményt kapunk:

Game nézet

Kezdjünk neki

Töltsük le innen a sample-files fájlokat. Három mappát tartalmaz a példa: asset-ek, modellek és induló projekt. Az előző részekben megismert módon megnyithatjuk a projektet.

Megjegyzés: A Unity-ben a projektek megnyitása kicsit másabb, mint a többi programban. Kattinthatunk a scene fájlon, vagy kiválaszthatjuk a projekt mappáját is a Unity böngészőjében.

Open project

Open project

A fájlrendszerben keressük meg a game assets mappát, és válasszuk ki a benne lévő összes fájlt, vagy húzzuk őket az Assets mappába a Project ablakon belül:

Importálás

Megjegyzés: Ha esetleg nem látszódik a Project ablak, akkor válasszuk ki a Window\Layouts\2 by 3 opciót.

Ha a Unity végzett az importálással, akkor valami hasonló ablakot kell látnunk:

Asset mappa

A Unity alapértelmezetten nagy előnézeti képeket használ, de ezen változtathatunk az alul lévő csúszka segítségével . Ez jól jön, ha sok asset-tel kell dolgoznunk:

Asset ikon méretezés

Észrevehetjük, hogy az összes asset egy helyre van ömlesztve. A nagyobb projektek esetén elengedhetetlen, hogy jól szét legyenek válogatva a különböző elemek, mellyel nagyon sok időt megspórolhatunk a fejlesztés során. A lényeg az, hogy a játék tényleges fejlesztésére minél több idő maradjon, és ne keresgéléssel töltsük azt.

A Project ablakon belül a Create-re kattintva, és a Folder opciót kiválasztva új mappát hozhatunk létre.

Mappa létrehozása

Nevezzük el az új mappát Materials-nak:

Mappa átnevezése

Készítsük el még a következő mappákat is, amelyek az asset-einket fogják tárolni:

  • Models
  • Prefabs
  • Scripts
  • Sounds
  • Textures

A Unity-ben lévő mappák úgy működnek, mint a fájlrendszer mappái. A fájlrendszer követi a Unity-ben lévő rendszert, így a Unity-n kívül is ugyanazon a helyen fogunk megtalálni mindent. E működés miatt érdemes a Unity-ben, nem pedig fájlrendszerben rendezgetni .

Ideje rendezgetni! Válasszuk ki a Bullet, Debris, GameManager, IonCannon, RendererFade, ScreenWrap és a ShipController szkripteket és húzzuk őket a Script mappába.

A background-music, explosion és shoot hangokat húzzuk a Sound mappába.

Végezetül a flint_like_rock_4787 textúrát mozgassuk a Textures mappába. Ha mindezzel megvagyunk, akkor a Project ablakunk hasonlóképpen néz ki:

Asset rendezés

Még mielőtt nekiesnénk a munkának, fontos megszokni, hogy rendszeresen mentsünk, mivel a Unity nem tartalmaz automata mentési funkciót.

A Unity a munkákat scene-ekbe menti. A scene lehet egy szintje a játéknak, de akár az egész játék is lehet egy scene. Ebben a lövöldözős játékban az utóbbi fog megvalósulni: minden egy scene lesz.

Mentsük el a játékunkat. Nevezzük el a scene-t Main-nek. A Save Scene ablak így néz ki:

Scene mentése

GameObject-ekkel és Prefab-okkal való munka Unity-ben

Mit ér a játékprogramozás játékos nélkül? Nézzünk bele a models/player mappába. Itt FBX fájlokat fogunk találni néhány képpel egyetemben.

Az FBX fájl tartalmaz minden adatot, ami a 3D-s modell elkészítéséhez kell. Ilyen például az animáció. A játékos fájlt, melyet a leírásban használunk, ComboMash készítette a Hextraction játékához.

Válasszunk ki minden fájlt a player mappából, és húzzuk őket az Assets mappa tetejére, a Project ablakba. Ezután valami ilyesmit kell lássunk:

NormalMap settings

Néhány képformátum extra információt hordoz, habár szokványos formátumúak. A p_pod_normal.jpg például tartalmazza a felület mélységét, amely felszíni világításhoz nyújt információt anélkül, hogy bármilyen más geometriát kelljen ehhez létrehozni. Ezt normal map-nak nevezzük.

A Unity azonban azt hiheti, hogy normál képpel dolgozik. A Fix Now gombra kattintva beállíthatjuk, hogy a Unity ezt normal map fájlként kezelje.

Miután importáltuk a játékos fájlokat, húzzuk a hextraction_pod asset-et a Scene nézetbe az alábbi módon:

Ship hozzáadása a Scene-hez

El is készült a modell első példánya. A Unity helyesen importálta a textúrát és helyezte rá a modellre.

A Hierarchy nézetben pedig megjelent egy új GameObject:

Ship Hiererchy

Ahogyan az előző részekben olvasható volt, a Hierarchy nézetben minden elem egy adott típusú GameObject. A GameObject maga tartalmaz egy transform adatot, amely a pozíciót, méretet, forgási adatot foglalja magába:

Transform

A GameObject-et úgy tudjuk testreszabni, hogy Components-et adunk hozzá. A komponensek képviselik a GameObject viselkedését és megjelenítését.

A világítási komponens hozzáadásával például -nem meglepően- fénybe boríthatjuk a GameObject-et. Az Audio Source komponens segítségével a GameObject hangot bocsájthat ki. Saját komponenseket is írhatunk és adhatunk a GameObject-ekhez, ha nagyon egyedi dolgot szeretnénk.

A GameObject-ek tárolóként is funkcionálnak. Az Alt nyomva tartásával, a kis háromszögre kattintva a hextraction_pod-on kinyitjuk az objektumot:

Hierarchy fa

Legtöbbjük üres GameObject, amely a modell struktúráját képviseli. A Unity készíti el ezeket a GameObject-eket, amikor egy modellt importálunk. A többi GameObject, mint például a pod_mesh gyerekei, tartalmaz egy Skinned Mesh Renderers komponenst, amely egy geometriát jelenít meg a képernyőn.

Azt is észrevehetjük, hogy némely GameObject a Hierarchy nézetben feketén, némely pedig kéken van jelölve:

Ship Hiererchy

A fekete jelölés a normál GameObject-et jelöli, míg a kék azt mutatja, hogy a GameObject egy Prefab-bal a többi objektumhoz kapcsolódik. Amennyiben a GameObject barna színűre vált, az azt jelenti, hogy elvesztette a Prefabbal való kapcsolatot.

A Prefab lehetővé teszi, hogy úgy mentsük le a GameObject-eket, hogy azok  kódból vagy a Scene nézetbe való behúzással könnyen duplikálhatóak legyenek. Hasonlóak a sablonokhoz, azzal a különbséggel, hogy a Prefab-ok kapcsolódnak egymáshoz. Ha módosítjuka Prefab-ot, akkor minden példány módosul.

Ha van egy Prefab példányunk a Scene nézetben, akkor bárhogyan testreszabhatjuk. Lesz olyan, amikor a módosításokat a már létező Prefab-okon akarjuk elvégezni, és lesz olyan is, amikor mindent vissza akarunk állítani az eredeti állapotára, mert nem jöttek be a változtatások.

Válasszuk ki a hextraction_pod-ot a Hierarchy nézetben. Az Inspector ablakban három gombot láthatunk: Select-et, Revert-et és Open-t:

Prefab vezérlők

A Select lokalizálja a Prefab-ot a Project ablakon belül. Ez különösen hasznos, ha az elemet egy komplex mappastruktúrában nem a megfelelő helyre tettük le.

Ha változtatunk egy Prefab-on, akkor az Apply gombbal azonnal módosíthatjuk az összes példányt. A Revert gomb visszavonja az egy példányon eszközölt változtatásokat, visszaállítja az eredeti állapotot. Az Open pedig megnyit egy modell fájlt, amit valamilyen szerkesztőben készítettek (például Maya vagy Blender).

Jelenleg a játékos hajója alatt egy rácsozat van, ami furán néz ki. Válasszuk ki tile_reference GameObject-et a Hierarchy nézetből. Ez a közvetlen leszármazottja a hextraction_pod GameObject-nek.

Megjegyzés: A gyorskeresőbe beírva a GameObject nevét, villámgyorsan megtalálhatjuk az objektumunkat.

Prefab keresés

A tile_reference-et kiválasztva töröljük a rácsozatot. A Unity egy figyelmeztetést fog feldobni:

Unity figyelmeztetés

A Unity minden olyan esetben jelezni fog, amikor egy változtatás megtöri a Prefab-ok kapcsolatát. Mivel pontosan ezt akarjuk tenni, ezért kattintsunk arra, hogy Continue. A hextraction_pod feketére fog váltani, jelezve, hogy az elemből egy hagyományos GameObject lett:

Prefab

A hextraction_pod-on történő jobb kattintás után válasszuk ki a Rename opciót, és nevezzük át a GameObject-et Spaceship-re.

Húzzuk a Spaceship-et a Prefab mappába a Project ablakon belül:

Prefab létrehozása

Behúzva a GameObject-et a Project ablakba, az automatikusan átkonvertálódik Prefab-bá. Annyi űrhajót tehetünk így a játékba, amennyit csak szeretnénk, úgy, hogy csak behúzzuk őket a Scene nézetbe. Jelenleg ez csak lemásolja a modellt, de a későbbiekben tartalmaz majd szkripteket, hangokat és még sok mást is. Amint azt láthajtjuk, a Prefab-ok nagyon hasznosak:

Prefab duplikálás

Már csak egy kis időt kell szánnunk arra, hogy a Project ablak átlátható maradjon. Az Assets mappán való kattintással megjeleníthetjük annak tartalmát. Tegyük a hextraction_pod-ot a Models mappába, a p_pod_ fájlokat pedig a Textures mappába. Végezetül ne felejtsünk el menteni!

A továbbiakról

A játékprogramozás bemutatását szolgáló sorozat következő részében egy másik izgalmas elemmel, a kamera beállításával fogunk megismerkedni. Hiszen mit ér egy játék, ha nem látunk belőle semmit?

Skeldar