In questa lezione vedremo come operare sul componente che è forse il più importante di tutti, il Transform.
Possiamo manipolare il componente Transform esattamente come facciamo sulla sua versione grafica nella finestra Inspector dell'editor. Il componente racchiude in sé alcune informazioni molto importanti del GameObject a cui appartiene, tra cui:
- position, la posizione del gameObject (espressa con un Vector3);
- rotation, la rotazione (espressa come Quaternion);
- scale, il fattore di scala (sempre Vector3).
Per accedere al componente transform di un oggetto, Unity mette a disposizione la shortcut transform
, da usare come se fosse una proprietà del gameObject stesso, o degli script associati ad esso.
Una prima distinzione da fare (che altrimenti potrebbe portare a parecchi grattacapi) è che mentre nell'editor questi valori sono locali, relativi quindi all'oggetto che lo contiene, in programmazione sono di solito assoluti. Questo vuol dire che se prendiamo un oggetto A
, in posizione (0, 0, 0)
, ci mettiamo dentro un oggetto B
in posizione (0, 0, 0)
, e poi spostiamo A
di due unità sulla X
(quindi in 2, 0, 0
), selezionando B
nell'Inspector vedremo che è in posizione (0, 0, 0
), ovvero la sua posizione relativa è nulla. Se però in programmazione stampiamo la sua posizione mediante:
Debug.Log(objectB.transform.position);
La console restituirà (2, 0, 0)
, ovvero la sua posizione assoluta nella scena, indipendentemente dal suo parent. Per leggere la posizione relativa (ovvero quella visualizzata nell'Inspector), basterà usare la proprietà localPosition:
Debug.Log(objectB.transform.localPosition);
Muovere oggetti nella scena
Per spostare un oggetto, sarà sufficiente modificare la sua position
o localPosition
. È da notare però che Unity non ci fa modificare le singole componenti del Vector3 che contiene la position, quindi per muovere l'oggetto anche su un solo asse sarà necessario copiare la position in un Vector3 temporaneo, modificarla, e riassegnarla come nuova posizione:
Vector3 tempPos = transform.position;
tempPos.x = 2f;
transform.position = tempPos;
Questo farà scattare l'oggetto in posizione 2 sull'asse X, lasciando Y e Z immutate. Fortunatamente, esiste Translate un'utile funzione per traslare oggetti, utilizzabile in due modi:
transform.Translate(2f, 0f, 0f);
transform.Translate(new Vector3(2f, 0f, 0f));
che ci permette anche di spostare l'oggetto nello spazio di coordinate del suo parent, e non in quello globale:
transform.Translate(new Vector3(2f, 0f, 0f), Space.Self); //notare Space.Self
Una nota importante: la funzione Translate (così come impostare la position manualmente) non muove l'oggetto spostandolo fisicamente nello spazio istante per istante, ma lo "teletrasporta" nella nuova posizione. Chiaramente se l'oggetto si sposta di incrementi abbastanza piccoli, al giocatore apparirà come se si stesse muovendo. Questo va bene nel 99% dei casi, l'unica cosa da tenere a mente è che poiché l'oggetto non tiene conto di collisioni fisiche, compenetrerà gli altri oggetti fino a passare oltre.
Per ottenere un movimento che tenga conto di muri, ostacoli e collisioni, sarà necessario scomodare il componente Rigidbody in unione con un Collider, ma di questo parleremo in un'altra lezione dedicata alla fisica.
Gerarchie di oggetti
Come abbiamo visto parlando delle gerarchie di oggetti nell'editor, in Unity è possibile inserire un oggetto dentro l'altro, allo scopo di far muover i GameObject "figli" in relazione al "padre".
In programmazione, l'oggetto padre viene salvato nella proprietà parent
del Transform. Di contro, un oggetto che ne contenga altri possiedera una proprietà childCount (numero degli oggetti figli) ed alcuni metodi per operare su di essi, come Find o GetChild. Gli oggetti sono in pratica connessi attraverso i loro componenti Transform.
Ad esempio, se un oggetto cube1
contiene un riferimento a cube2
nel parent del suo Transfrom, diciamo che cube1
è figlio di cube2
. Per creare questa connessione, bisogna assegnare il Transform del padre come parent del Transform del figlio:
Debug.Log(cube2.transform.childCount); //stampa 0, perché cube2 non ha figli
cube1.transform.parent = cube2.transform;
Debug.Log(cube2.transform.childCount); //stampa 1, perché cube1 è stato appena connesso a cube2
Quando un oggetto è contenuto in un altro, la sua position
rimane comunque il valore della sua posizione assoluta nella scena. Per sapere la posizione relativa rispetto al parent, basterà consultare la proprietà transform.localPosition
.
Per rimuovere un figlio dal parent, è necessario impostare parent
a null
:
cube1.parent = null;
In questo modo, l'oggetto figlio sarà di nuovo sulla root della scena.