• Rezultati Niso Bili Najdeni

Skripta za interakcijo kamere z objekti - CameraCollision.cs

4.2 Kamera v tretji osebi

4.2.2 Skripta za interakcijo kamere z objekti - CameraCollision.cs

Če želimo izdelati kvalitetno kamero v tretji osebi, moramo nujno pomisliti na situacije, ko drugi predmeti kameri prekrižajo pot. Tak dogodek imenujemo "camera-collision", saj govorimo o trku kamere s predmeti v virtualnem svetu. V prikazani situaciji bomo trke kamere zaznali s pomočjo nevidnih vektorjev okoli kamere. Ob trku katerega koli od teh vektorjev z objektom, ki ima dodano collider komponento (preko katere lahko trk zaznamo), bomo ta trk zabeležili v pripravljeno spremenljivko. Zabeležen trk bo hranil podatek o točki trka in razdaljo od izhodišča vektorja do točke trka. Tako lahko kamero približamo na razdaljo točke trka in še nekoliko bližje, da se gotovo izognemo prekrivanju vidnega polja ter objekta (angleško clipping).

Na začetku skripte CameraCollision.cs deklariramo spremenljivke ter sklice do komponent, ki jih bomo kasneje uporabili (slika 13).

public class CameraCollision : MonoBehaviour {

[Header("Cam collision layerMask and radius")]

public LayerMask layers;

[Header("Cam direction & distance parameters")]

private Vector3 vectDir;

private float vectLen;

private float minDist = 1f;

private float maxDist = 4f;

[Header("Cam collision offsets")]

private Vector3 offsetDown = new Vector3(0, -0.3f, -0.4f);

private Vector3 offsetLeft = new Vector3(-0.3f, 0, -0.4f);

private Vector3 offsetRight = new Vector3(0.3f, 0, -0.4f);

private void Start() {

vectDirection = transform.localPosition.normalized;

vectLenght = transform.localPosition.magnitude;

Cursor.lockState = CursorLockMode.Locked;

Cursor.visible = false;

}

Slika 13: Deklaracija spremenljivk v skripti CameraCollision.cs.

V vrstici "public LayerMask layers;" deklariramo javno spremenljivko tipa "LayerMask"

imenovano "layers". S pomočjo dane spremenljivke bomo v oknu "Inspector" nastavili plasti, ki

15

jih bo skripta upoštevala pri zaznavanju trkov. To nam omogoča, da določimo, od katerih trkalnikov (colliders) se bo kamera odbijala.

V vrstici "public float scrollSens = 0.25;" deklariramo javno spremenljivko tipa plavajoče vejice imenovano "scrollSens". Z vrednostjo "scrollSens" bomo določili velikosti korakov približevanja (oziroma oddaljevanja) kamere proti glavnemu liku (oziroma stran od njega). Če zavrtimo miškino kolo za en korak, se bo v danem primeru kamera premaknila za 0.25f enote.

S kodo "public float smoothCam = 6f;" v naslednji vrstici, deklariramo javno spremenljivko tipa plavajoče vejice, ki smo jo poimenovali "smoothCam". Z vrednostjo spremenljivke določimo, kako hitro se bo kamera približala razdalji, ki jo določa spremenljivka "maxDist". Če je vrednost

"smoothCam" majhna (npr. 3), se bo kamera počasi in gladko približala oz. oddaljila od glavnega lika, če pa je vrednost večja (npr. 15), se bo kamera premaknila sunkovito.

V vrstici "private Vector3 vectDir;" deklariramo privatno spremenljivko tipa "Vector3" imenovano

"vectDir". Na mesto spremenljivke v metodi "void Start()" shranimo enotski vektor lokalne pozicije transforma objekta, na katerega je skripta pripeta. Lokalna pozicija ima vrednosti določene glede na starša. Te pridobimo v vrstici "vectDir = transform.localPosition.normalized;", kjer najprej poiščemo lokalno pozicijo, nato pa jo z metodo "normalized" pretvorimo v enotski vektor.

Preprosteje povedano, v "vectDir" shranimo vrednost 1 na mestih, kjer vrednost ni bila enaka 0, sicer pa pustimo 0.

V vrstici "private float vectLen;" deklariramo privatno spremenljivko imenovano "vectLen". V metodi "void Start()" v vrstici " vectLenght = transform.localPosition.magnitude;" na mesto spremenljivke shranimo oddaljenost kamere. Oddaljenost kamere pridobimo tako, da najprej poiščemo lokalni pozicijski vektor, nato pa z metodo "magnitude" pridobimo dolžino vektorja.

V vrsticah "private float minDist = 1f;" ter "private float maxDist = 4f;" deklariramo privatni spremenljivki tipa plavajoče vejice. V spremenljivki shranimo najmanjšo ("minDist") oz. največjo ("maxDist") razdaljo oddaljenosti kamere. Vrednosti bosta upoštevani v primeru, ko spreminjamo oddaljenost kamere z miškinim kolescem oz. kadar je zaznan trk kamere in se ta zaradi tega približa.

V vrsticah pod naslovom [Header("Cam collision offsets")] deklariramo privatne spremenljivke tipa "Vector3", v katere shranimo vektorje z vrednostmi odmikov, ki bodo vplivali na žarke, s katerimi bomo preverjali trke kamere. Spremenljivke so deklarirane po ključu kode

"private Vector3 imeOdmika = new Vector3(x, y, z);". Z vrednostjo "x" določimo zamik žarka levo (x < 0) oz. desno (x > 0), z vrednostjo "y" določimo odmik dol (y < 0) oz. gor (y > 0), z vrednostjo "z" pa določimo odmik bližje (z > 0) ali dlje stran (z < 0). Odmike uporabimo v metodi

"camCollisionUpdate()".

Če želimo skriti kurzor ter njegovo pozicijo zakleniti na sredino igralnega polja, dodamo v metodo

"void Start()" vrstici "Cursor.visible = false;" in "Cursor.lockState = CursorLockMode.Locked;".

Prva nastavi vidnost kurzorja na "false", druga pa nastavi zaklenjenost kurzorja na način

"zaklenjen".

16

Sledi metoda void Update(), v kateri dodamo kodo, ki omogoča približevanje in oddaljevanje kamere s premikom miškinega kolesca (slika 14).

void Update() {

float mouseWheel = Input.GetAxis("Mouse ScrollWheel");

if (mouseWheel != 0) {

maxDistance = Mathf.Clamp(maxDistance + (mouseWheel*scrollSens), 1f, 4f);

} }

Slika 14: Metoda Update v skripti CameraCollision.cs.

V vrstici "float mouseWheel = Input.GetAxis("Mouse ScrollWheel");" najprej deklariramo spremenljivko mouseWheel, v katero shranimo vrednost virtualne osi z imenom "Mouse ScrollWheel" (miškino kolesce).

Nato v pogojnem stavku "if (mouseWheel != 0)" preverimo, ali smo zavrteli miškino kolesce (to drži, kadar vrednost osi ni enaka nič). Kadar ta pogoj velja, se izvede vrstica

"maxDist = Mathf.Clamp(maxDist + (mouseWheel*scrollSens), 1f, 4f);", kjer spremenljivki

"maxDist" določimo novo vrednost. Novo vrednost pridobimo s prištevanjem vrednosti

"mouseWheel" spremenljivki "maxDist". Pri tem vrednost "mouseWheel" pomnožimo še s konstanto "scrollSens", ki vpliva na velikost pomikov kamere. Na ta način bi lahko odmik kamere povečevali v neskončnost, zato oddaljenost kamere omejimo s pomočjo metode "Mathf.Clamp()".

V danem primeru smo uporabili vrednosti 1f in 4f, ki omogočata približevanje kamere do vrednosti 1f in oddaljitev kamere do vrednosti 4f. Seveda je vrednosti smiselno prilagoditi vsaki igri posebej.

17

Na koncu skripte, znotraj bloka metode "LateUpdate()" (slika 15), izvedemo še preverjanje trkov in premik kamere na določeno razdaljo.

private void LateUpdate() {

RaycastHit hit;

#region directional vectors

Vector3 parentPos = transform.parent.position;

Vector3 desiredDown = transform.parent.TransformPoint(

vectDir * vectLen + offsetDown) - parentPos;

Vector3 desiredLeft = transform.parent.TransformPoint(

vectDir * vectLen + offsetLeft) - parentPos;

Vector3 desiredRight = transform.parent.TransformPoint(

vectDir * vectLen + offsetRight) - parentPos;

#endregion

#region Debug draw ray

Debug.DrawRay(parentPos, desiredDown, Color.green);

Debug.DrawRay(parentPos, desiredLeft, Color.red);

Debug.DrawRay(parentPos, desiredRight, Color.blue);

#endregion

if (Physics.Raycast(parentPos, desiredLeft, out hit, desiredLeft.magnitude, layers)||

Physics.Raycast(parentPos, desiredRight, out hit, desiredRight.magnitude, layers)||

Physics.Raycast(parentPos, desiredDown, out hit, desiredDown.magnitude, layers)) {

Slika 15: Metoda LateUpdate v skripti CameraCollision.cs.

Najprej deklariramo novo spremenljivko "RaycastHit hit;". Za spremenljivko "hit" izberemo podatkovni tip RaycastHit , ki nam omogoča hranjenje podatkov o presečišču (ali več presečiščih) žarka in trkalnikov. V spremenljivko bomo kasneje shranili zaznano presečišče in iz njega prebrali razdaljo.

Znotraj regije "#region directional vectors" deklariramo več spremenljivk tipa "Vector3". Prvo poimenujemo "parentPos", vanjo pa shranimo globalni vektor pozicije transforma starša (starša objekta, na katerem je pripeta skripta – torej pozicija "CamBase"). Sledijo spremenljivke

"desiredDown", "desiredLeft" in "desiredRight", v katere shranimo vektorje, ki kažejo v smer, kamor želimo "izstreliti" žarek, ki bo preveril trk kamere. Vektorje s pravilno usmeritvijo dobimo

18

po ključu kode "Vector3 imeVektorja = transform.parent.TransformPoint(vectDir * vectLen + offset) - parentPos;". V deklarirani vektor shranimo vektor pozicije starša, na katerem izvedemo metodo "TransformPoint". Kot argument vstavimo vektor sestavljen iz "vectDir" (lokalna usmerjenost pozicije kamere) pomnožen z "vectLen" (magnituda lokalnega pozicijskega vektorja kamere), temu pa prištejemo še odmik (offset). Vse skupaj metoda pretvori v globalne koordiante.

Na koncu pretvorjenemu vektorju odštejemo še vektor "parentPos", da ga usmerimo v pravilno smer.

Znotraj regije "#region Debug draw ray" so dodani t.i. debug žarki, ki so namenjeni odkrivanju napak. Omogočijo nam vizualizacijo vektorjev, s katerimi bomo preverjali trke kamere. Metoda

"Debug.DrawRay(parentPos, desiredDown, Color.green);" sprejme začetno pozicijo žarka ("parentPos") ter usmerjenost z magnitudo izraženo kot vektor (v katero smer in kako daleč). Po želji lahko določimo še barvo žarka. Izris žarkov prikazuje slika 16Napaka! Vira sklicevanja ni bilo mogoče najti., iz katere je razvidno, da žarki izhajajo iz pozicije starša ("parentPos") v smer kamere, zaradi prištetih odmikov (offsets) pa se razpršijo navzven.

Slika 16: Prikaz Debug.DrawRay() žarkov.

V bloku pogojnega stavka preverimo, ali kateri od žarkov trči v trkalnik (collider) iz okolice. Prvi pogoj "Physics.Raycast(parentPos, desiredLeft,out hit, desiredLeft.magnitude, layers" je koda z zamikom v levo. Kot začetno stanje vstavimo pozicijo starša, kot usmeritev vstavimo vektor

"desiredLeft", v spremenljivko "hit" se shranijo podatki o morebitnem trku, dolžino žarka določimo z magnitudo vektorja "desiredLeft", plasti, ki jih bo žarek zaznal, pa določimo s spremenljivko

"layers". Pogojni stavek vsebuje tri pogoje ločene z operatorjem ALI, s čemer zagotovimo, da se

19

vsebina pogojnega stavka izvede, kadar drži vsaj en od pogojev. V primeru, ko kateri od žarkov (levo, desno, dol) vrne vrednost "true", se podatek o točki trka shrani v spremenljivko "hit", nato pa se izvede blok.

Znotraj bloka, v vrstici "vectLen = Mathf.Clamp(hit.distance * 0.99f, minDist, maxDist);", spremenljivki "vectLen" najprej določimo novo vrednost. Vrednost nastavimo na razdaljo od izhodišča žarka do točke trka, nato razdaljo pomnožimo še s številom 0.99f. To storimo zato, da razdaljo malenkost skrajšamo. S tem dosežemo, da se kamera premakne pred objekt, v katerega je žarek trčil (če trči na razdalji 5, se kamera premakne na razdaljo 4.95, kar je bližje od 5). Razdaljo do točke trka pridobimo iz objekta "hit" s klicem "hit.distance". Z metodo "Mathf.Clamp()"

omejimo novo vrednost med "minDist" in "maxDist", saj ne želimo, da se kamera približa ali oddalji v neskončnost.

Nato moramo kamero še premakniti na novo pridobljeno razdaljo. To naredimo v vrstici

"transform.localPosition = Vector3.Lerp(transform.localPosition, vectDir * vectLen, 20 * Time.d eltaTime);", kjer lokalno pozicijo kamere premaknemo na novo točko z uporabo metode

"Vector3.Lerp(…)". V metodo vstavimo vektor začetne pozicije, vektor želene končne pozicije (to je "vectDir" pomnožen z novo razdaljo "vectDir") ter hitrost premika. Vrednost hitrosti nastavimo relativno visoko, saj želimo, da se kamera hitro odmakne stran od ovir (po želji lahko vrednost znižamo).

Če noben od pogojev v pogojnem stavku ni izpolnjen, se izvede koda v bloku "else{}". Najprej s kodo "vectLen = maxDist;" vrednost spremenljivke "vectLen" nastavimo na maksimalno dopuščeno vrednost – "maxDist". Za tem pozicijo kamere premaknemo s klicem metode "Lerp"

(tako kot v predhodnih opisih). Tokrat za hitrost premika vzamemo vrednost "smoothCam", ki jo lahko nastavimo v oknu "Inspector". Pri testiranju se je vrednost 3f izkazala za najprimernejšo vrednost spremenljivke "smoothCam".

20