16. CLASE TRANSFORM (y VII)









TransformPoint:

function TransformPoint (position : Vector3) : Vector3

function TransformPoint (x : float, y : float, z : float) : Vector3


A diferencia de TransformDirection, lo que esta función transforma de local en global es la posición y no la dirección. Esto es, esta función no versa sobre si un transform se desplaza a su derecha o a la derecha de las coordenadas globales, sino de si las coordenadas en que se encuentra el transform son globales (respecto al mundo) o locales (respecto al padre de dicho transform). Con esto entendido, como decimos, esta función acepta como parámetro las coordenadas locales de un transform (su ubicación respecto de la de su padre) y devuelve dichas coordenadas traducidas a coordenadas globales.


Lo veremos más claron con un ejemplo. Con el cubo en position 0,0,0 y rotation en 0,0,0 (si no,no funcionará) arrastramos el cubo dentro de la cápsula en la Jerarquía, para convertir a cubo en hijo de la cápsula. Si seleccionamos el cubo, vemos en el inspector que sus coordenadas de posición han pasado a ser locales respecto de su padre. Abrimos MiPrimerScript (que debería seguir siendo parte del cubo) y escribimos el siguiente script:

var coordenadasLocales : Vector3;
var coordenadasGlobales: Vector3;
var coordenadasTransformadas: Vector3;

coordenadasLocales = transform.localPosition;
coordenadasGlobales = transform.position;
coordenadasTransformadas = transform.position = 
transform.TransformPoint(transform.localPosition);

Debug.Log("El cubo tiene las coordenadas locales " + coordenadasLocales.ToString() + 
" las globales " + coordenadasGlobales.ToString() + " y las transformadas " +
coordenadasTransformadas.ToString());


El ejemplo parece más complicado de lo que es. Declaramos tres variables de tipo Vector3 para que contengan las tres coordenadas que imprimiremos para nuestro cubo (los nombres de las variables son lo suficientemente explicativos). Acto seguido inicializamos las dos primeras variables con la posición global y local del transform, y la tercera con las coordenadas que tendrá el transform cuando convirtamos sus coordinadas locales (respecto de la cápsula) en globales.

Salvamos y le damos al play. Observamos que por un lado el cubo se desplaza en dirección y distancia opuesta al cilindro, ya que el -3,-4,-2 que constituían sus coordenadas locales ahora ha pasado a ser su posición en coordenadas globales.


InverseTransformPoint:

function InverseTransformPoint (position : Vector3) : Vector3

function InverseTransformPoint (x : float, y : float, z : float) : Vector3


Función inversa a la precedente, que por tanto transforma la posición de un transform dado del espacio global al espacio local.


DetachChildren:

function DetachChildren () : void


Es una función muy sencilla que sirve para desparentar los hijos. Para probarla debemos eliminar el script vinculado al cubo, y posteriormente hacer doble click en MiPrimerScript en el Proyecto para teclear lo siguiente:

transform.DetachChildren();


Salvamos y lo arrastramos a la cápsula, que es el transform que tiene hijos. Le damos al play y observaremos cómo en la Jerarquía el cubo deja de aparecer como hijo de la cápsula.

Esta función es útil, entre otras cosas, cuando por alguna razón queramos destruir al objeto padre sin destruir a sus hijos:

transform.DetachChildren();
Destroy(gameObject);



Find:

function Find (name : String) : Transform


Con esta función podemos buscar por su nombre -y en su caso acceder- a un transform hijo de nuestro transform. La función devuelve dicho transform hijo, si lo encuentra. Si no lo encuentra, retorna null.

Si tenemos que buscar a varios niveles, esto es, hijos de los hijos de nuestros hijos, podemos utilizar un slash o barra inclinada (“/”) para recrear la jerarquía donde queremos buscar (p ej. "Cuerpo/Brazo/Mano/Indice")

Dado que deberíamos tener el cubo aún dentro de la cápsula, y MiPrimerScript vinculado a ésta, lo aprovecharemos para realizar un ejemplo:

var aquiMiHijo : Transform;

function Update() {
aquiMiHijo = transform.Find("Cubo");
aquiMiHijo.Rotate(Time.deltaTime*60, 0, 0);
}


Como podemos comprobar al darle al play, la función Find encuentra un transform hijo llamado "Cubo" (recordemos que, por un lado hemos de suministrarle un string, esto es, no nos debemos olvidar de las comillas, y por otro lado que todos los componentes de un gameobject comparten por defecto el mismo nombre que éste, así que el transform del Cubo se llama Cubo), y almacena ese transform que encuentra dentro de la variable aquiMiHijo. A partir de ahí, podemos utilizar esa variable como si fuera un alias del propio transform.


IsChildOf:

function IsChildOf (parent : Transform) : boolean


Esta función casi no requiere explicación. Devuelve true si el transform que hace la pregunta es hijo, "nieto" o incluso idéntico al transform parent que pasamos como parámetro. En otro caso, devuelve false.


Y con esto acabamos la clase transform, que como decía al inicio es una de las diez clases más importantes de la API de Unity.

Nos vemos.

POSTED BY UnityScripts
POSTED IN
DISCUSSION 0 Comments

15. CLASE TRANSFORM (VI)









TransformDirection:

function TransformDirection (direction : Vector3) : Vector3


Esta función toma como único parámetro la dirección local de un transform almacenada en un Vector3 y la convierte en dirección global, devolviéndola en otro Vector3.

La utilidad de esta función puede resultar un poco confusa al principio. Pensemos, para intentar aproximarnos al concepto, que quisiéramos hacer nuestra propia versión del FIFA 2011. Modelamos un campo de futbol y, para darle más realismo y emoción al juego, colocamos varias cámaras en los laterales del campo, cámaras que mediante LookAt irían siguiendo los lances del juego. El problema que nos encontraríamos es que cuando Messi (por poner un caso) está avanzando hacia delante (en las coordenadas globales), en cambio en nuestra cámara lateral pareciera que lo está haciento -por ejemplo- hacia la izquierda. Y en consecuencia, cuando intentamos que nuestro defensa lo ataje moviéndolo hacia atrás (según la perspectiva que nos da la cámara lateral) veremos consternados que el defensa en lugar de retroceder se desplaza hacia la derecha.

Esto no nos pasaría si, gracias a esta función, convertimos la coordenada "hacia detrás" de nuestra cámara en su equivalente en coordenadas globales. Si esa función se la aplicamos a todas las cámaras, no tendremos que estar pensando "Ojo, que esta cámara está en el gol norte, por lo que si me baso en ella cuando haga un movimiento, he de recordar que arriba es abajo y viceversa y la derecha es la izquierda y bla, bla, bla".

Veámoslo en un ejemplo.

En Unity borramos el script MiSegundoScript de la cámara. Colocamos en el inspector a nuestro cubo en las coordenadas 0.0.0. con una rotación igualmente de 0,0,0. Asimismo, la cámara debería estar en las coordenadas de posición 0,1,-5 con los tres ejes de rotación a 0.

Abrimos MiPrimerScript. Tecleamos esto:


var miCamara : Transform;
var estaEsMiDerecha : Vector3;

estaEsMiDerecha = miCamara.TransformDirection(Vector3.right);
transform.Translate(estaEsMiDerecha * 3);


Arrastramos la cámara a miCamara. Le damos al play. El cubo se moverá 10 unidades a la derecha. Pero, ¿a la derecha de quién?. Si observamos, la derecha del cubo es también la derecha de la cámara.

Para averiguarlo, vamos a recolocar la cámara en estas coordenadas:
Position: -10, 1, -0.5
Rotation: 0, 90, 0

Y de nuevo le damos al play. Obviamente, el cubo se mueve a la derecha de la cámara. Visto desde la ventana game, coincidirá ahora "nuestra" derecha (entendiendo como tal la que nos muestra la pantalla) con el sentido el movimiento.



El script no necesita mucha explicación. Inicializamos una variable con el transform de la cámara que hemos arrastrado. La derecha de esa cámara la almacenamos en una variable de tipo Vector3, la cual luego pasamos como parámetro a nuestra función TransformDirection para que nos convierta la derecha de nuestra cámara en la derecha de las coordenadas globales. A partir de ahí, todo lo que le suceda a la derecha de nuestra cámara (por así decirlo) le estará pasando a la derecha del mundo.

function TransformDirection (x : float, y : float, z : float) : Vector3

Es la misma función, pero aplicando como parámetros 3 floats para cada eje en lugar de un Vector3.


InverseTransformDirection:

function InverseTransformDirection (direction : Vector3) : Vector3

o bien

function InverseTransformDirection (x : float, y : float, z : float) : Vector3



Se trata obviamente de la función inversa a la anterior, y por consiguiente transforma una dirección global en dirección local.

Veamos un ejemplo:

Devolvemos antes que nada a nuestra cámara a su lugar y rotación originales:
Position: 0,1,-5
Rotation: 0,0,0

La posición y rotación de nuestro cubo, por su parte, está totalmente a 0.

Abrimos MiPrimerScipt, y tecleamos:


var estaEsLaDerechaDelMundo : Vector3;

estaEsLaDerechaDelMundo = transform.InverseTransformDirection(Vector3.right);

transform.Translate(estaEsLaDerechaDelMundo * 2);


Como vemos, declaramos una variable de tipo Vector3 que luego inicializamos de la siguiente forma: le pasamos a la función InverseTransformDirection el parámetro Vector3.right, que en esta función representa la derecha en coordenadas globales (no la derecha de ningún transform). Esa derecha del mundo, global, es "traducida" por la función en una coordenada local susceptible de usar por cualquier transform y es asignada,como decíamos, a nuestra variable estaEsLaDerechaDelMundo. Dicha variable, por último, es pasada como parámetro de movimiento al transform del gameobject que tiene vinculado el script (en este caso el cubo).

¿La probamos?

El cubo se desplaza a la derecha. Pero, para saber si la derecha es la derecha del cubo o la derecha global, podemos en el inspector darle un valor al rotation.Y del cubo de 45 grados, por ejemplo. Y probamos de nuevo.



Definitivamente, el cubo se mueve ahora siguiendo el eje X global, y no el suyo local.


Animo, que en un par de lecciones acabamos ya con esta clase.

POSTED BY UnityScripts
POSTED IN
DISCUSSION 0 Comments

14. CLASE TRANSFORM (V)










RotateAround:

function RotateAround (point : Vector3, axis : Vector3, angle : float) : void


Esta función nos permite que nuestro transform rote alrededor de un punto (u objeto situado en ese punto), como si orbitara.

El parámetro point sería el punto, descrito por un Vector3, alrededor del cual queremos hacer girar nuestro transform. Axis nos servirá para indicar sobre qué eje queremos girar, y angle el número de grados por frame (si está dentro de la función update) o por segundo (si implicamos la variable de clase Time.deltaTime) que queremos que gire. Obviamente, aquí estamos variando tanto la rotación como la posición de nuestro transform.

si por ejemplo quiriéramos que nuestro cubo girara sobre su eje Y alrededor del centro exacto del espacio global, a razón de 20 grados por segundo, escribiríamos este script:

 
function Update() {
transform.RotateAround (Vector3.zero, Vector3.up, 20 * Time.deltaTime);
}


Dado que el cubo se hallaba ya en las coordenadas globales 0,0,0 el script anterior lo único que consigue es que el cubo parezca girar sobre sí mismo. Vamos a hace lo siguiente: colocamos en el inspector a nuestro cubo en position.x = -1, y volvemos a darle al play.

Y vemos ya más claramente cómo orbita alrededor del punto dado, cambiando simultáneamente de posición y de rotación.

Podemos hacer también con esta función que un objeto orbite alrededor de otro. Escribimos:


var centroDeGravedad: Transform;

function Update() {
transform.RotateAround (centroDeGravedad.position, Vector3.up, 20 * Time.deltaTime);
}


Acto seguido, arrastramos el objeto sobre el que queremos que orbite nuestro cubo, en este caso la cápsula. Le damos al play y comprobamos.

Observemos que aunque arrastramos un gameobject, lo que está esperando nuestro scrips es un transform. Lo que sucede es que -tal como vimos en las primeras lecciones- todos los componentes de nuestro gameobject comparten nombre, de tal manera que cuando en casos como este Unity detecta que uno de los componentes del gameobject que le estamos arrastrando tiene el nombre y el tipo del que está esperando para cumplimentar una variable, automáticamente selecciona -en este caso- el transform homónimo y no el gameobject.

Ese transform, no obstante, no es del tipo Vector3 que espera nuestra función. Sí que lo es la variable position del mismo, que además contiene las coordenadas globales del transform sobre el que queremos orbitar.

Podéis probar a sustituir en el segundo parámetro Vector3.up por Vector3.right (o Vector3.forward), y comprobar qué es lo que sucede.


LookAt:

function LookAt (target : Transform, worldUp : Vector3 = Vector3.up) : void


El nombre de esta función se podría traducir al castellano como "mira a", y es exactamente eso lo que hace: Rotar nuestro transform hacia un objetivo -parámetro target- que es asimismo de tipo transform (y no Vector3, como en el caso de la función anterior). Esa rotación se efectúa sobre un eje global, y por defecto éste será el eje Y. Ello implicará que nuestro transform, si no le indicamos lo contrario, girará hacia la derecha y la izquierda "mirando" al transform que hayamos designado como objetivo.

Huelga decir que esta función se usa mucho para cámaras, cuando pretendemos que éstas sigan en todo momento a un determinado personaje.

Es importante avisar de que para que el transform gire sobre el eje que le indiquemos, ha de estar totalmente perpendicular a dicho eje global.

Vamos a la práctica. En el Proyecto, colocamos el ratón sobre la carpeta Mis Scripts y le damos al botón derecho=>create=>javascript. Al nuevo script lo renombramos como MiSegundoScript y le damos doble click para se se nos abra el editor.

Desplazamos un poco hacia abajo la función Update, y la dejamos como sigue:


var sigueme : Transform;

function Update () {
transform.LookAt(sigueme);
}


Salvamos, y la arrastramos hasta nuestra cámara en la jerarquía. Seleccionamos entonces la cámara y arrastramos ahora hasta la variable sigueme nuestro cubo.

Previamente a darle al play nos aseguramos de que el otro script (MiPrimerScript) que tenemos vinculado al cubo, contenga lo siguiente:


var centroDeGravedad: Transform;

function Update() {
transform.RotateAround (centroDeGravedad.position, Vector3.up, 20 * Time.deltaTime);
}


Y ahora sí, ya podemos darle al play y perseguir a nuestro cubo.

function LookAt (worldPosition : Vector3, worldUp : Vector3 = Vector3.up) : void

Este segundo prototipo se diferencia del primero en que el objetivo que ha de seguir nuestro transform no es otro transform, sino un Vector3. Esto tiene sentido, siguiendo con el ejemplo de la cámara, si quisiéramos que ésta enfocara un punto concreto de la escena (en coordenadas globales)

Por ejemplo, si queremos que una cámara enfoque al centro de la escena, le vinculamos este script:


transform.LookAt(Vector3.zero);


Otra posibilidad que nos permite esta función es que sea nuestro jugador, desde su teclado, quien se encargue de decidir dónde ha de enfocar la cámara. Para ello tendremos que recurrir a una clase que aún no hemos visto, la clase input.

Abrimos el script MiSegundoScript, y tecleamos lo que sigue:


function Update () {
transform.LookAt(Vector3(Input.GetAxis("Horizontal") * 10.0,0,0));
}


Le damos al play y movemos la cámara con las flechas de desplazamiento horizontal. Quizás notemos que el resultado es un poco basto, pero meramente quería que tuviérais una idea de las utilidades de esta función. También podríamos controlar la cámara desde el ratón y no desde el teclado. Veremos todo esto en profundidad cuando estudiemos la clase input.

Nos vemos en el siguiente capítulo.

POSTED BY UnityScripts
POSTED IN
DISCUSSION 2 Comments
Con la tecnología de Blogger.