1.2. Kuidas toimib Unity?

Unity Editori kasutamine ja C#-iga skriptimine

NB! Esimesel vaatusel võib see peatükk tunduda liiga informatiivne ja uuest teabest ülevohav. Seega palun mitte liiga kaua aega kulutada selle peatüki teksti kinnistamisele ning pigem soovitan siia tagasi tulla peale järgmisi kokkupuuteid Unity kasutamisega ja C# skriptimisega järgmiste peatükkide raames, mil võib tekkida küsimusi, millele võib saada vastuse just siit. Ka võib saada praegu tekkivatele võimalikele arusaamatustele vastuseid pigem järgnevates hands-on peatükkidest. Soovitan otsida ka võimalikele küsimustele vastuseid või niisama juurde uurida Unity API kohta kas kursusel olevate hüpiklinkide kaudu (allajoonitud värviline tekst on tavaliselt hüpiklink!), otse docs.unity3d.com (Manual ja/või Scripting API) lehelt või mujalt.

Unity kasutamine

Unity mängumootoris on palju asju mänguarendaja eest ära tehtud, nagu kaadrite joonistamine,  tekstuuride renderdamine, Rigidbody ehk füüsikaliste liikumiste ja kokkupõrgete süsteem, UI Canvas ehk kasutajaliidese süsteem jpt. Unity kasutajal jääb üle vaid kasutada neid Unity etteehitatud süsteeme oma projektis C# skriptide kirjutamise abil ning Unity redaktoris stseenide ülesseadmisel ja ilustamisel kunstilise vabavara (assets) ja animatsioonidega.

Skriptimine Unitys

Skriptimine ehk skriptide kirjutamine on Unity mängude loomises oluline koostisosa. Enamus Unity aplikatsioone vajavad skripte, et vastata mängija nupule vajutustele ning teostada kindlaid sündmusi ja käitumisi. Lisaks saab skriptide programmeerimisega luua graafilisi effekte ja mesh-objekte, kontrollida objektide füüsikalisi käitumisi või isegi rakendada tehisintellekti (AI) mingite objektide käitumiste kohandamisel (vt).

https://docs.unity3d.com/Manual/ScriptingSection.html

Unity Editor

Olulisim Unity Editorist

Olen kuvatõmmisel (vt 1. joonist) märkinud olulisemad kohad värviliste kastidega. 

Hierarchy - Kõik stseenis olevad objektid on asetatud hierarhiasse. Antud näites hiearhiline aspekt sellel puudub, aga on võimalik, nagu OOP-s, üks objekt 'panna külge' teisele objektile. Sel juhul muutuvad esimese objekti koordinaadid teise omadega lokaalseks ehk esimese koordinaadid (0,0,0) vastaksid teise asukohale ruumis ning esimese rotatsioon kraadides (0,0,0) vastaks teise objekti vaatesuunale. Neid objekte, mille külge tekitatakse hierarhia nimetatakse vanemobjektideks või vanemateks ja hierarhia alumisi osi lasteks (nagu OOP-s). Unitys avaldub hierarhiline liikumine nii, et kui vanemobjekti küljes on liigutav skript siis liigub kogu tema küljes olev hierarhia ning vanema ja lapse vaheline distants ei muutu, aga kui panna see skript lapse külge, siis liigub laps ja vanemat see ei mõjuta.

Scene View - Stseenivaadet kasutatakse stseenis olevate asjade liigutamiseks ja skaleerimiseks roosas kastis asuvate vahenditega.  Game View, mis pole näites valitud, näitab seda, milline näeb mäng läbi kaamera silma välja mängija jaoks. Kaamera asukoht on praeguses näites Scene View kaadris kaamera ikooni juures. Scene view's orienteerumise juhtnupud on hiirel (vasak klikk, rullik, rullikunupp) ning orienteerumine on analoogne teiste 3D programmide kasutamisega.

Edit Tools - Selles kastis asuvad Move tool, Rotate Tool, Scale Tool, Rect Tool jt. Praegu on valitud Move Tool, millega saab valitud objekti liigutada x-y-z-telgedel. 

Project ja Console - Projecti alt saab sirvida kaustas, kus praeguses näites pole midagi, peale skriptide ja materjalide. Suuremas projektis sirvitakse sealt asseteid ja muid väliseid failisid, mis tõstetud Assets kausta või muud moodi projekti imporditud. Console ehk konsooliaken on koht, kuhu tulevad sõnumid vigade (errors) ja testimise kohta. Debug.Log("Tekst..."); on koodilõik, millega skriptis teksti konsooliaknale väljastatakse. 

Inspector- Inspektor-menüüd kasutatakse objektil olevate komponentide (skriptid, asukoht,  põrgutid (colliders) jpt.) seadistamiseks ja parameetrite väärtuste muutmiseks. Selleks, et teha objektil oleva skripti muutujad inspektoris nähtavaks, tuleb skriptis muutuja defineerimisel panna muutuja tüübi ette võtmesõna public (public int täisarv = 2; public Vector3 vektorSuurus;). Neile "avalikele" muutujatele ei pea enam skriptis suurust andma, kui seda tehakse inspektoris. See võtmesõna muudab selle muutuja nähtavaks ka teistele komponentidele, mistõttu kui on soov, et seda poleks ja et see oleks lihtsalt "public", siis tuleb panna võtmesõna [HideInInspector] defineeritud muutujale eelnevale reale. 

Skriptide kirjutamine

Unity protsessid töötavad kindla järjekorra põhjal (vt joonist 2). Näiteks, kohe peale initseerimist või iga kaadri alguses algavad füüsikaliste protsesside arvutamised peale mida toimub sisendi fikseerimine, stseeni renderimine jpm. 

Skriptidega täiendatakse neid protsesse väljendamaks mingeid soovitud mängule kohaseid käitumisi, nagu liikumine, animatsioonid ja muud efektid.

Event functions

void Start()

Meetodit* Start() viiakse täide ühel korral - esimese kaadri jooksul. Start() meetodit läheb vaja näiteks mingite objektide initsialiseerimiseks või konstantsete väärtuste (objekti algpositsioon, algne suurus) salvestamiseks.

* Meetod ja funktsioon on C#-kontekstis siin õppematerjalis põhimõtteliselt sünonüümsed.

void Update()

Meetodit Update() viiakse täide kord kaadri jooksul. Update() meetodi sisse programmeeritakse kõik mängu liikumised, tegevused ja loogika.

Teised meetodid, mida ei ole skriptimallis

void Awake()

Awake() viiakse täide enne Start() meetodit juba Unity redaktoris.

void FixedUpdate()

Erinevalt Update() meetodist, viiakse FixedUpdate() täide kord fikseeritud ajaintervalli tagant, mis ei ole sõltuv kaadrisagedusest. FixedUpdate()-i soovitatakse kasutada füüsikaliste protsesside programmeerimiseks (Rigidbody class) ja Update()-i muude loogikat nõudvate ja sisendit jäädvustavate protsesside programmeerimiseks.

void LateUpdate()

LateUpdate is called after all Update functions have been called. This is useful to order script execution. For example a follow camera should always be implemented in LateUpdate because it tracks objects that might have moved inside Update. Link.

Skriptimises vajaminevaid märksõnu ja klasse

Vector2 ja Vector3

Vector2 ja Vector3 on andmetüübid, mis hoiavad vastavalt kahe-ja kolmekohalist järjendit. Vt lähemalt vektoritele pühendatud peatükki.

GameObject

GameObject - Base class for all entities in Unity Scenes.

Transform

Transform on klass, mis salvestab stseenis oleva objekti suuruse (scale) (Transform.localScale), asukoha ehk positsiooni (position) (Transform.position), pöörde ehk rotatsiooni (rotation) (Transform.rotation), jpm. Kõik peale rotatsiooni on Vector3 väärtused, mis on kolmekohalised float-tüüpi arvudest koosnevad järjendid. Rotatsioon avaldub Quaternion klassina kvaternioon-tüüpi muutuja (üks kompleksne viis väljendamaks pööret), mida saab Quaternion.eulerAngles abil väljendada Euleri nurkades ehk kolme arvuna, mis määravad nurga kraadides. 

Objekti külge aheldatud skriptis Transformile ja selle omadustele ligi pääseda alljärgnevalt: 

// selguse nimel kasutan võtmesõna this viitamaks SELLELE objektile, mille küljes on käesolev skript (this. on transformi vaikimisi kirjutamata)

Vector3 positsioon = this.transform.position; //annab Vector3 muutujale "positsioon" objekti (praegused) koordinaadid

float positisoon_x = this.transform.position.x; //annab float muutujale "positsioon_x" objekti (praeguse) x koordinaadi

Vector3 skaala = this.transform.localScale; //annab maailma (Space.World) või vanem-objekti suhtes, mille külge on käesolev objekt kinnitatud, objekti lineaarmõõtmed

Quaternion rotatsioonKvaternionites = this.transform.rotation; //objekti rotatsioon kvaternionites

Vector3 rotatsioonEuleriNurkades = this.transform.rotation.eulerAngles; //tagastab objekti rotatsiooni euleri nurkades (kuni 180 kraadi, ka negatiivsed nurgad)

Rigidbody ja RigidBody2D

Rigidbody ja Rigidbody2D on klass, mis kontrollib objekti asukohta läbi füüsikalise simulatsiooni. Kokkupõrked ja hõõrdejõud toimuvad Unitys enamasti tänu Rigidbody ja Collider komponentidele. On võimalik ka ise läbi nutika ja põhjaliku skriptimise programmeerida oma füüsikasüsteem, aga seda enamasti pole vaja, sest see oleks nagu ratta leiutamine.

3. Näide

skriptimallist (script template) VS Code'i redaktoris. Skriptimall tekib iga kord kui Unity redaktoris luuakse uus skriptifail. 

Enne sektsiooni public class, kuhu tekib kogu kood, on namespace-idele viitamise koht. Sinna on vaikimisi pandud peamised teegid, kuid sinna saab lisada oma namespace-e või Unity endi namespace-e, mida pole sinna lisatud nagu näiteks UnityEngine.UI (kasutajaliidese programmeerimiseks) või UnityEngine.Tilemaps jpt.

4. Näide

2D platformeri mängija liikumise skriptist. Event functionites kasutatavaid muutujaid, mida tahetakse salvestada, defineeritakse juba enne start funktsiooni need skripti on kõige laiema skoobiga muutujad, mida saab kasutada kõigis meetodites/event functionites. Praeguses näites Start funktsioonis deklareeritakse ujukomaarvust muutuja varasemalt defineeritud float-tüüpi väärtus xScale, ja antakse väärtus transform.localScale.x, mis on objekti (Game Objecti), mille külge see skript on ühendatud Transformi property ehk omadus scale ehk suuruse lineaarmõõde, mis avaldub vektorsuurusena Vector3 klassis;  .x on vektorklassi esimene muutuja, mis antud kontekstis vastab objekti x-teljelisele lineaarmõõtmele ja on float-tüüpi väärtus. Seda väärtust on antud juhul vaja karakteri ümberpööramisel Update funktsioonis korrutatakse see ümber "-1"-ga ja pannakse uueks suuruseks x-suuruseks skaala vektoris. Lisaks Start ja Update funktsioonile on selles näites ka FixedUpdate funktsioon ja paar funktsiooni/meetodit, milles olev sisu avaldub põrgutite (colliderite) põrgete korral (OnCollision..) või ülekattumisel (OnTrigger..) (vt joonist 1; millal toimuvad need ).