24. CLASE RIGIDBODY (y VIII)
Sleep:
Function Sleep () : void
Fuerza al rigidbody a dormir al menos un frame. Un uso común es llamar esta función al principio del juego para que el rigidbody no consuma recursos hasta que sea activado.
IsSleeping:
Function IsSleeping () : Boolean
Booleano que devuelve true si el rigidbody está durmiendo.
WakeUp:
Function WakeUp () : void
Fuerza al rigidbody a despertarse.
SweepTest:
Function SweepTest (direction : Vector3, hitInfo : RaycastHit, distance : float = Mathf.Infinity) : Boolean
Devuelve true cuando un barrido del rigidbody intercepta algún collider. Esto funciona de la siguiente manera: nuestro rigidbody lanza en una dirección (parámetro direction de tipo Vector3) un rayo (pensemos hasta que no estudiemos la clase RaycastHit en una especie de láser o sonar de presencia, con la salvedad de que en este caso el rayo devolverá información de aquéllo con lo que ha chocado) hasta una determinada distancia (distance, de tipo float, que por defecto es infinito) y si el rayo tropieza con un collider, la función devuelve true.
Obviamente, esto es de gran utilidad para, por ejemplo, que nuestro personaje tenga información para evitar colisiones.
Veamos un pequeño ejemplo:
var rayo : RaycastHit;
function Update () {
if (rigidbody.SweepTest (-transform.right, rayo, 10)) {
Debug.Log("Hay un obstaculo a " + rayo.distance + " metros a la izquierda");
}
}
El script funciona como sigue: primero declaramos una variable de tipo RaycastHit para que recoja toda la información del collider que nuestra función pueda detectar en su barrido. Acto seguido lanzamos a través de la función SweepTest un rayo en dirección izquierda (-transform.right) hasta una distancia de diez metros. Caso de topar con un collider, distinta información del mismo será almacenada en la variable rayo y la función devolverá true, con lo cual se imprimirá la información tecleada, indicando la distancia del collider hallado.
Si le damos al play, observamos que nuestra función ha hallado un collider a la izquierda de nuestro cubo.
SweepTestAll:
Function SweepTestAll (direction : Vector3, distance : float = Mathf.Infinity) : RaycastHit[]
Es parecida a la anterior, pero devolviendo un array de tipo RaycastHit con toda la información de todos los colliders hallados en el camino
Además de las funciones tradicionales contenidas en la clase Rigidbody, ésta también tiene un tipo de función específica, que se disparan cuando acontece un evento. Unity las trata como "mensajes que envía la clase". Son tres:
OnCollisionEnter:
function OnCollisionEnter (collisionInfo : Collision) : void
OnCollisionEnter es llamada cuando nuestro rigidbody/collider toca otro rigidbody/collider.
En contraste con la función OnTriggerEnter, a OnCollisionEnter se le pasa como parámetro una instancia de la clase Collision, la cual contiene información sobre puntos de contacto, velocidad de impacto, etc.
OnCollisionExit:
function OnCollisionExit (collisionInfo : Collision) : void
OnCollisionExit es llamada cuando nuestro collider/rigidbody deja de tocar otro rigidbody/collider.
OnCollisionStay:
function OnCollisionStay (collisionInfo : Collision) : void
OnCollisionStay es llamada una vez cada frame para cada collider/rigidbody que esté tocando nuestro rigidbody/collider.
Y con esto acabamos la clase Rigidbody.
23. CLASE RIGIDBODY (VII)
AddTorque:
function AddTorque (torque : Vector3, mode : ForceMode = ForceMode.Force) : void
function AddTorque (x : float, y : float, z : float, mode : ForceMode = ForceMode.Force) : void
Esta función añade una torsión (no he podido encontrar una traducción mejor para torque) al rigidbody. Como resultado el rigidbody empezará a girar alrededor del eje de torsión.
Así, si al eje Y de rotación de nuestro cubo le reintegramos su valor de 0 y luego modificamos de la siguiente manera nuestro script del último ejemplo...
rigidbody.centerOfMass = Vector3(0,-0.3,0);
function FixedUpdate(){
rigidbody.AddTorque (Vector3.right * 15);
}
...vemos que efectivamente se le ha añadido a nuestro cubo una fuerza de torsión/rotación sobre el eje X. Recordemos que cuando hablamos de rotación, hemos de considerar a cada eje como si se tratara de una línea rígida alrededor de la cual nuestro objeto gira. Esto es, si quisiéramos que el cubo se moviera como una peonza, tendriamos que hacerlo rotar sobre su eje Y. Probad a cambiar "Vector.right * 15" por "Vector.up * 25". (Y si queremos que rote en dirección opuesta, le anteponemos un signo - al Vector.)
AddRelativeTorque:
function AddRelativeTorque (torque : Vector3, mode : ForceMode = ForceMode.Force) : void
function AddRelativeTorque (x : float, y : float, z : float, mode : ForceMode = ForceMode.Force) : void
Como podréis suponer, esta función añade una fuerza de torsión relativa a las coordenadas locales/propias del rigidbody. Es a AddTorque lo mismo que AddRelativeForce a AddForce.
AddForceAtPosition:
Function AddForceAtPosition (force : Vector3, position : Vector3, mode : ForceMode = ForceMode.Force) : void
Aplica fuerza a un rigidbody en una posición determinada.
AddExplosionForce:
Function AddExplosionForce (explosionForce : float, explosionPosition : Vector3, explosionRadius : float, upwardsModifier : float = 0.0F, mode : ForceMode = ForceMode.Force) : void
Aplica una fuerza al rigidbody que simula el efecto de una explosión. La fuerza de la explosión decaerá de manera lineal con la distancia del rigidbody.
Esta función también funciona bien con objetos inertes. Si el radio es 0, la fuerza plena será aplicada sin importar cuan lejos se produzda la explosión del rigidbody. UpwardsModifier aplica la fuerza como si fuera aplicada desde debajo del objeto.
MovePosition:
Function MovePosition (position : Vector3) : void
Mueve el rigidbody de posición. Por ejemplo:
private var velocidad : Vector3 = Vector3 (3, 0, 0);
function FixedUpdate () {
rigidbody.MovePosition(rigidbody.position + velocidad * Time.deltaTime);
}
En este script declaramos primero una variable de tipo Vector3. Le anteponemos la palabra clave "private", que implica que dicha variable no será accesible desde el inspector (no quedará expuesta). Se declara como privada una variable que no queremos que se modifique desde la interface.
El resto del script no merece mucha explicación. Se suma el Vector3 con la velociadd a la posición del rigidbody, y para que el desplazamiento se produzca en segundos y no en porciones de frames, lo multiplicamos por Time.deltaTime.
MoveRotation:
function MoveRotation (rot : Quaternion) : void
Rota el rididbody.
Si observamos el prototipo de la función, vemos que hemos de pasarle a la misma un parámetro de tipo Quaternion. Ya hemos dicho en otras ocasiones que resulta bastante complejo para los humanos trabajar con cuaterniones, razón por la cual por norma general trabajaremos en grados Euler se los pasaremos a la función convenientemente traducidos.
Un ejemplo:
private var velocidadEnAngulos : Vector3 = Vector3 (0, 100, 0);
function FixedUpdate () {
var velocidadEnCuaternionesPorTiempo : Quaternion =
Quaternion.Euler(velocidadEnAngulos * Time.deltaTime);
rigidbody.MoveRotation(rigidbody.rotation * velocidadEnCuaternionesPorTiempo);
}
Como podemos comprobar, meramente tenemos que usar la función Quaternion.Euler, que recibe grados euler como parámetro y devuelve cuaterniones. El resto es sencillo.
Y aquí hacemos una parada.
22. CLASE RIGIDBODY (VI)
FUNCIONES:
SetDensity:
Function SetDensity (density : float) : void
Nos permite asignar una masa en base al collider vinculado, lo cual es útil para asignar una masa en unos valores acordes al tamaño de los colliders.
Podemos aplicar un ejemplo similar al que realizamos con la variable mass. Abrimos nuestro script habitual y tecleamos:
function FixedUpdate () {
if (Input.GetButtonDown ("Horizontal")) {
rigidbody.velocity = Vector3(6,0,0);
rigidbody.SetDensity(6.0);
}
}
Salvamos. Play. Presionamos la flecha de desplazamiento horizontal y comprobamos que la masa de la esfera le permite literalmente arrastrar al cubo.
AddForce:
function AddForce (force : Vector3, mode : ForceMode = ForceMode.Force) : void
Esta función (una de las más importantes de la API de Unity) añade una fuerza al rigidbody. Como resultado de esto el rigidbody comenzará a moverse.
El primer parámetro es un Vector3, que nos servirá para indicar la potencia y dirección de la fuerza que aplicamos. Por ejemplo, podemos teclear en nuestro script de cabecera:
function FixedUpdate () {
rigidbody.AddForce (Vector3.up * 10);
}
Y al darle al play nuestra esfera ascenderá, fruto de una fuerza constante (aplicada en cada actualización de la función FixedUpdate). Obviamente, la velocidad de movimiento dependerá -además de la fuerza aplicada - de la masa del rigidbody y de la resistencia, esto es, varios rigidbodies diferentes tendrán reaccione diferentes cuando les es aplicada la misma fuerza.
function AddForce (x : float, y : float, z : float, mode : ForceMode = ForceMode.Force) : void
Este segundo prototipo de la función, como ya viene siendo habitual, meramente sustituye el parámetro de tipo Vector3 por 3 de tipo float.
//Equivale al script anterior
function FixedUpdate () {
rigidbody.AddForce (0, 10, 0);
}
El segundo parámetro observamos que es de tipo ForceMode, que como posiblemente sospechéis es una nueva enumeración made in Unity, que tiene los siguientes valores:
Force Añade una fuerza contínua al rigidbody, dependiendo de su masa. Es
el valor por defecto y que obtiene resultados más realistas, ya que
como decíamos costará más esfuerzo mover objetos más pesados que
más livianos.
Acceleration Añade una aceleración contínua al rigidbody, ignorando su masa. A
diferencia de ForceMode.Force, Acceleration moverá cualquier
rigidbody de la misma forma sin tener en cuenta su masa, lo que es
útil si sólo queremos controlar la aceleración de un objeto sin
preocuparnos de la fuerza que debíeramos aplicarle para obtenerla
teniendo en cuenta su masa y resistencia.
Impulse Añade un impulso puntual de fuerza al rigidbody, teniendo en cuenta
su masa. Hay que tener la precaución de no incluir este modo dentro
de una función que se actualice a menudo (como FixedUpdate). Este
modo es útil para aplicar fuerzas que acontecen de repente, como
explosiones o colisiones.
VelocityChange Añade un cambio de velocidad instantáneo al rigidbody, ignorando su
masa. Con esa salvedad (una misma fuerza tendrá los mismos
resultados con rigidbodies de diferente masa), le es aplicable lo
mismo que al modo precedente.
Podemos ver la diferencia entre fuerzas aplicadas en el mismo script de arriba. Lo modificamos para que quede así:
function FixedUpdate () {
rigidbody.AddForce (Vector3.up * 10, ForceMode.Impulse);
}
Podéis ver que la esfera sale disparada. No retorna porque como la tenemos dentro de la función FixedUpdate está recibiendo un impulso periódico. Vamos a liberarla:
rigidbody.AddForce (Vector3.up * 10, ForceMode.Impulse);
Supongo que queda demostrada la diferencia entre fuerza constante e impulso.
AddRelativeForce
function AddRelativeForce (force : Vector3, mode : ForceMode = ForceMode.Force) : void
Añade una fuerza al rigidbody relativa al sistema local de coordenadas de dicho rigidbody.
Para explicar qué quiere decir esto, vamos a preparar un ejemplo que requerirá varias fases: Para empezar, eliminamos el script que tenemos vinculado a la esfera. Nos colocamos en la vista vertical en la ventana Scene, haciendo click en la Y del gizmo. En Proyecto hacemos doble click en MiPrimer Script para abrir el editor, y tecleamos:
function FixedUpdate(){
rigidbody.AddForce (Vector3.right * 15);
}
Salvamos, arrastramos el script al cubo y le damos al play. Tal como era de esperar, se aplica una fuerza lateral al cubo, pero éste da demasiadas vueltas sobre sí como para hacer una demostración respecto a las coordenadas de desplazamiento, así que vamos a completar el script con una de esas variables que cuando uno las estudia cree que no las usará nunca.
rigidbody.centerOfMass = Vector3(0,-0.3,0);
function FixedUpdate(){
rigidbody.AddForce (Vector3.right * 15);
}
Exacto. Le bajamos el centro de gravedad al cubo y en principio deberíamos ahora poderlo arrastrar como un mueble. Probemos si esto funciona en la práctica.
Lo suficiente para poder realizar la explicación. Ahora giremos en el inspector el cubo 35 grados sobre el eje Y. Volvamos a darle al play.
Vemos que la fuerza que aplica la función AddForce lo es en relación a las coordenadas globales, y no a las del objeto.
Sustituimos en el script AddForce por AddRelativeForce y probemos de nuevo.
Ahora la fuerza no es aplicada a la derecha del mundo, sino a la derecha relativa del cubo.
Seguiremos.
Bye.
21. CLASE RIGIDBODY (V)
centerOfMass:
CenterOfMass : Vector3
Representa el centro de masa relativo al origen del transform. El centro del transform se corresponde a las coordenadas locales 0,0,0, y si no reubicamos vía un script el centro de masa, Unity lo calcula automáticamente (suele coincidir con el centro del transform)
Si bien no es una variable con demasiada utilidad, sí que a veces puede servirnos para, por ejemplo, hacer más estable y menos propenso a los vuelcos a un coche. Un coche con un centro de masa/gravedad bajo es menos propenso a volcar.
rigidbody.centerOfMass = Vector3 (0, -2, 0);
worldCenterOfMass:
var worldCenterOfMass : Vector3
Esta variable nos indica el centro de masa/gravedad de un rigidbody en el espacio global. Tengamos presente que a diferencia de la anterior esta variable es de solo lectura.
detectCollisions:
Var detectCollisions : Boolean
Indica si la detección de colisiones está habilitada (por defecto, sí). Deshabilitar esta variable es util si tenemos un objeto que es kinemático y queremos evitar que el sistema realice cálculos inútiles de detección de colisiones para él.
interpolation:
Var interpolation : RigidbodyInterpolation
La interpolación nos permite suavizar el efecto de correr físicas en un framerate fijo. Por defecto la interpolación está off. Comunmente se usa la interpolación de rigidbodies en los personajes de los jugadores. Las físicas suelen transcurrir en pasos fijos (FixedUpdate), mientras los gráficos son renderizados en framerates variables. Esto puede llevar a que los objetos parezcan temblorosos, porque físicas y gráficos no están completamente sincronizados. El efecto es sutil pero perceptible, y sobre todo afecta a los personajes principales que son seguidos por alguna cámara. Es recomentable poner en on la interpolación para el personaje principal pero deshabilitarla para los demás.
La enumeración RigidbodyInterpolation tiene los siguientes valores:
None Significa que no hay interpolación. Es la opción por defecto.
Interpolate La interpolación irá con un poco de retraso, pero puede ser un
poco más suave que la extrapolación.
Extrapolate La extrapolación predecirá la posición del rigidbody en base a la
velocidad actual.
sleepVelocity:
var sleepVelocity : float
La velocidad lineal, por debajo de la cual los objetos empiezan a dormir (por defecto 0.14) en un rango que va de 0 a infinity. La hecho de que los objetos duerman es una optimización que permite que el engine de físicas deje de procesar para estor rigidbodies. Así, cuando el objeto se duerme deja de detectar colisiones o realizar simulaciones, por ejemplo.
sleepAngularVelocity:
var sleepAngularVelocity : float
La velocidad angular, por debajo de los cuales los objetos empiezan a dormirse (por defecto 0.14)
maxAngularVelocity:
Var maxAngularVelocity : float
Representa la maxima velocidad angular del rigidbody (por defecto 7) en un rango que va de 0 a infinity.
Se tiene que fijar una velocidad angular máxima para evitar inestabilidades numéricas con objetos rotando demasiado rápido.
Bueno, y hasta aquí las variables de la clase Rigidbody. He omitido la explicación de unas cuantas que me han parecido poco importantes, de poco uso.
La próxima lección empezamos con las funciones.
20. CLASE RIGIDBODY (IV)
isKinematic:
Var isKinematic : boolean
Es un booleano que controla si las físicas afectan al rigidbody. Si isKinematic está habilitado (es true), a nuestro rigidbody no le afectarán ni fuerzas, ni colisiones ni junturas (joints). Ello quiere decir que no podemos esperar que frente -por ejemplo- a una colisión ese rigidbody kinemático se comporte de la manera lógica que por su masa, resistencia y gravedad debiera comportarse. Sus movimientos, reacciones y respuestas, por tanto, deberemos marcárselos específicamente mediante scripts o animaciones.
Los cuerpos kinemáticos, por el contrario y a su vez, sí afectan el movimiento de otros rigidbodies no kinemáticos a través de colisiones o joints.
Quisiera aprovechar para recordar que las variables "expuestas" de tipo booleano son mostradas por el inspector como un checkbox, donde el cuadro marcado se corresponde a true y el desmarcado al false.
freezeRotation:
Var freezeRotation : Boolean
Esta variable vendría a ser una especialización de la anterior. freezeRotation controla si las físicas cambiarán la rotación del objeto. Si esta variable está habilitada (true), la rotación no será mofificada por la simulación de físicas, y en todo caso tendremos que establecerla nosotros manualmente mediante scripts o animaciones.
constraints:
Var constraints : RigidbodyConstraints
Controla qué grados de libertad están permitidos para la simulación de nuestro rigidbody. Por defecto esta variable tiene el valor RigidbodyConstraints.FreezeNone, permitiendo rotación y movimiento en todos los ejes.
En algunos casos, puedes querer constreñir un rigidbody para que sólo se mueva o rote sobre algunos ejes, como por ejemplo cuando desarrolles juegos en 2D. Puedes usar el operador de bits OR ('||') para combinar múltiples constraints.
Vamos a probar con un sencillo ejemplo la utilidad de esta variable. En Unity alejamos un poco la cámara para que se vea tanto la esfera como el lateral izquierdo (según se mira) del plano. Abrimos nuestro script habitual:
function FixedUpdate () {
if (Input.GetButtonDown ("Horizontal")) {
rigidbody.velocity = Vector3(-6,0,0);
}
}
Salvamos, play, flecha desplazamiento lateral. La esfera sobrepasa la superficie del plano y arrastrada por la gravedad cae.
Podríamos solucionar esta eventualidad quitándole la gravedad a la esfera, pero tenemos una solución más elegante: no permitir que nuestra esfera se mueva en el eje Y (arriba/abajo).
Así que modificamos nuestro script:
function FixedUpdate () {
if (Input.GetButtonDown ("Horizontal")) {
rigidbody.velocity = Vector3(-6,0,0);
rigidbody.constraints = RigidbodyConstraints.FreezePositionY;
}
}
Y volvemos a probar. Dado que le hemos congelado ("freeze") a nuestra esfera la posibilidad de alterar el valor de su eje de posición Y, la esfera no puede ni ascender ni caer, razón por la cual continúa rodando allende el plano.
Observamos que esta variable es de tipo RigidbodyConstraints, lo cual en el fondo es una enumeración que nos permite elegir entre una serie de valores, a saber:
None Sin limitaciones de posición ni de rotación
FreezePositionX Congela la posición en el eje X.
FreezePositionY Congela la posición en el eje Y.
FreezePositionZ Congela la posición en el eje Z.
FreezeRotationX Congela la rotación sobre el eje X.
FreezeRotationY Congela la rotación sobre el eje Y.
FreezeRotationZ Congela la rotación sobre el eje Z.
FreezePosition Congela la posición sobre todos los ejes.
FreezeRotation Congela la rotación sobre todos los ejes
FreezeAll Congela rotación y posición de todos los ejes
collisionDetectionMode:
var collisionDetectionMode : CollisionDetectionMode
Esta variable nos permite establecer el modo de detección de colisiones del rigidbody. Como podemos observar, es de tipo CollisionDetectionMode, tratándose ésta al igual que en el caso anterior de una enumeración que admite tres tipos de valores, que pasamos a desarrollar:
Distrete: Este es el modo de detección de colisiones por defecto. Es el que menos recursos consume, pero no garantiza que nuestro rigidbody detecte un conjunto de colisiones, sobre todo si estas acontencen a gran velocidad. En modo discrete Unity comprueba si el rigidbody ha sido colisionado cada vez que se llama a la función fixedUpdate, que como ya explicamos es llamada un número fijo de veces por segundo. Si la colisión se produce en el impass entre una llamada a fixedupdate y la siguiente, nuestro rigidbody no la captará.
Continuous: Con este modo on, nuestro rigidbody detectará las colisiones con cualquier malla geométrica estática que se tropiece en su camino, incluso si la colisión ocurre entre dos llamadas a FixedUpdate. Por malla geométrica estática Unity entiende cualquier MeshCollider (no tardaremos en estudiarlo) que no tenga un rigidbody vinculado.
ContinuousDinamic: Si establecemos este sistema de detección de colisiones para nuestro rigigbody, éste detectará colisiones tanto con mallas geométricas estáticas como con otros rigidbodies que tengan a su vez activado el modo continous collision detection. Este sistema consume bastantes recursos y debe ser sólo usado para prevenir movimientos muy rápidos de objetos. Sólo es soportado, además, por rigidbodies con sphere o box collider.
A efectos de sintaxis, para colocar el sistema de detección de un rigidbody en modo ContinuousDinamic, por ejemplo, lo escribiríamos así:
rigidbody.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
19. CLASE RIGIDBODY (III)
drag:
Var drag : float
Indica la resistencia al movimiento de un objeto y por lo tanto se usa para enlentecer dicho objeto. Cuando más algo el valor, mayor resistencia.
Veámoslo añadiendo un tercer if a nuestro script, de tal forma que quede así:
function FixedUpdate () {
if (Input.GetButtonDown ("Jump")) {
rigidbody.velocity = Vector3(0,6,0);
}
if (Input.GetButtonDown ("Horizontal")) {
rigidbody.angularVelocity = Vector3(7,0,0);
}
if (Input.GetKeyDown ("z")) {
rigidbody.drag = 10;
}
}
Salvamos. La función GetKeyDown de la clase input dispara un evento cuando el user presiona una determinada tecla, en nuestro ejemplo la zeta. Le damos al play y lanzamos al aire nuestro cubo presionando la barra espaciadora, y cuando esté en el aire presionamos la z. Observaremos cómo los movimientos del cubo se enlentecen. Si a continuación volvemos a presionar la barra espaciadora o la flecha horizontal, comprobaremos que la resistencia al movimiento de nuestro cubo es mucho mayor.
angularDrag:
rigidbody.angularDrag = 10;
Indica la resistencia angular del objeto. Puede ser usado para enlentecer la rotación de un objeto.
mass:
Var mass : float
Variable que representa la masa del rigidbody, su peso. Recomienda el manual de referencia que el valor de la masa debería estar entre 0.1 y 10. Masas grandes -según el manual- hacen las simulaciones físicas inestables.
Obviamente, los objetos con mayor masa proyectan a los que tienen menos masa cuando chocan. Pensemos en un camión grande golpeando un coche pequeño.
Vamos a verlo con un ejemplo sencillo. Para llevarlo a cabo eliminamos el script que tiene vinculado nuestro cubo. Luego seleccionamos la esfera, y la ubicamos en las coordenadas -3,0,0. Acto seguido hacemos doble click en MiPrimerScript para abrir el editor y tecleamos lo que sigue:
function FixedUpdate () {
if (Input.GetButtonDown ("Horizontal")) {
rigidbody.velocity = Vector3(9,0,0);
}
}
Salvamos y arrastramos el script a la esfera. Este no tiene mucho misterio: al presionar la flecha horizontal del teclado, nuestra esfera debería tomar una velocidad de aceleración hacia su derecha, por lo que en principio debería impactar con el cubo. Probémoslo. Play.
Observamos que efectivamente al pulsar la flecha de desplazamiento horizontal, la esfera golpea contra el cubo con la suficiente fuerza como para incluso volcarlo.
Si nos fijamos, en los respectivos rigidbodies del cubo y la esfera que aparecen en el inspector, ambos tienen una mass de 1. Debido a ello, a raiz del impacto no hay un objeto que parezca "salir victorioso" de este (el cubo gira una cara y la esfera retrocede lentamente tras el impacto).
¿Que pasaría, no obstante, si uno de los dos rigidbodies tuviera una masa sensiblemente distinta del otro?
Probémoslo añadiendo una expresión más a nuestro script:
function FixedUpdate () {
if (Input.GetButtonDown ("Horizontal")) {
rigidbody.velocity = Vector3(9,0,0);
rigidbody.mass = 0.1;
}
}
Ahora nuestra esfera tendrá una masa de 0.1, esto es, una décima parte de la masa del cubo. Salvamos, play, flecha lateral...
Casi ni mueve el cubo.
Podéis probar a la inversa, si queréis, darle más masa a la esfera (sin pasar de 10, recordad). Comprobad que una vez pulsais la flecha de desplazamiento horizontal, la masa de la esfera (si es que la tenéis seleccionada) cambia en el inspector y se convierte en la que habéis asignado en el script.
Para acabar, advertiros de que un error común es asumir que objetos pesados caen más rápido que los ligeros. Esto no es verdad, ya que la velocidad depende de la gravedad y la resistencia (drag), y no de la masa.
useGravity:
Var useGravity : boolean
Booleano que controla si la gravedad afecta a este rigidbody. Si está en false el rigidbody se comportará como si estuviera en el espacio.
Probamos. Rehacemos MiPrimerScript:
function FixedUpdate () {
if (Input.GetButtonDown ("Jump")) {
rigidbody.velocity = Vector3(0,7,0);
}
if (Input.GetButtonDown ("Horizontal")) {
rigidbody.useGravity = false;
}
if (Input.GetButtonDown ("Vertical")) {
rigidbody.useGravity = true;
}
}
Salvamos, y le damos impulso hacia arriba a nuestra esfera. Alternad las flechas de desplazamiento horizontal y vertical para comprobar la diferencia de movimientos sin y con gravedad.
Bueno, pues creo que por esta lección es suficiente.
Hasta pronto.
18. CLASE RIGIDBODY (II)

De un mero vistazo a este gráfico podréis sin duda deducir dos cosas:
1.- La clase Rigidbody es "hermana" de la clase Transform. Están al mismo nivel y heredan de las mismas clases.
2.- Nos va a ocupar un buen número de lecciones estudiarla. Pero el esfuerzo veréis que merece la pena, ya que dominando las clases Transform, Rigidbody (y Collider con sus dos clases hijas, que estudiaremos tras Rigidbody) tendremos controlado en gran parte el tema del movimiento y reacción ante el movimiento ajeno de nuestros gameobjects.
Y sin más dilación, vamos allá.
VARIABLES:
velocity:
Var velocity : Vector3
Representa a través de un vector la velocidad del rigidbody.
No es aconsejable en la mayoría de casos modificar esta variable directamente, ya que derivaría en un comportamiento poco realista (no habría una transición entre la velocidad (o incluso inactividad) anterior y la nueva velocidad. Sí está justificado en cambio su uso para aquellos cambios de velocidad que provienen de un impulso, como por ejemplo un salto.
function FixedUpdate () {
if (Input.GetButtonDown ("Jump")) {
rigidbody.velocity = Vector3(0,6,0);
}
}
Tecleamos este script en MiPrimerScript, lo salvamos y lo arrastramos al cubo.
Hay varias cosas del mismo que necesitarán una explicación. Para empezar, vemos que se está usando una función llamada FixedUpdate. Esta función es parecida a la función Update, de la que ya habíamos hablado, pero a diferencia de ésta, FixedUpdate es llamada (actualizada) a intervalos regulares (fijos). Por lo tanto, así como en la función Update la actualización depende del framerate de cada ordenador, en la función FixedUpdate la actualización se produce en intervalos fijos, iguales para todos los ordenadores. Por esa razón, cuando tratamos con cuestiones relacionadas con la física (y toda la clase Rigidbody está relacionada con la física) habremos de usar la función FixedUpdate y no la función Update (salvo que queramos que las caídas, colisiones y velocidad de los objetos de nuestro juego sean diferentes en función del ordenador con el que juguemos o que, yendo aún más allá, en un juego online multijugador el personaje de cada user vaya a una velocidad distinta, por ejemplo.)
Lo segundo nuevo del script es una referencia a la clase input. La clase input (otra de las clases que ocupan el top ten de importancia en Unity) es la que controla los eventos, esto es, qué tiene que hacer el usuario para disparar, qué tecla hace qué cosa, qué tipo de colisiones provocan que pase otra cosa distinta, etc. En este caso, Input.GetButtomDown(string) dispara un evento cuando el usuario pulsa la tecla que le pasamos a la función como un string. En nuestro Script le pasamos el string "Jump", que por defecto se corresponde a la barra espaciadora.
¿Y qué sucede cuando le damos a la barra espaciadora?. Pues que al rigidbody que en el capítulo anterior le añadimos a nuestro cubo le será aumentada de golpe la velocidad en el vector Y (arriba/abajo). Para comprobarlo, dale al play y cuando el juego esté corriendo presiona la barra espaciadora.
angularVelocity:
Var angularVelocity : Vector3
Vector que representa la velocidad angular del rigidbody. Por velocidad angular nos referimos a la velocidad de rotación. Al igual que con velocity, en la mayoría de casos no cambiaremos la velocidad directamente, pues salvo casos en que precisamos un impulso súbito de la velocidad, no queda realista.
Para entender bien la diferencia entre velocidad y velocidad angular, vamos a completar el script anterior, permitiéndonos aplicar una u otra velocidad, o incluso ambas a la par. MiPrimerScript quedará así:
function FixedUpdate () {
if (Input.GetButtonDown ("Jump")) {
rigidbody.velocity = Vector3(0,6,0);
}
if (Input.GetButtonDown ("Horizontal")) {
rigidbody.angularVelocity = Vector3(7,0,0);
}
}
Como podemos observar, hemos añadido un segundo if de tal manera de que si el jugador en lugar de presionar la barra espaciadora (jump) presiona cualquiera de las dos flechas horizontales de dirección del teclado, la velocidad que se aplique al cubo será velocidad angular.
Salvamos, le damos al play y pulsamos cualquiera de las flechas horizontales. Probablemente observaremos que el cubo hace intención de girarse, pero no tiene la fuerza suficiente para hacerlo. Si, en cambio, pulsamos la barra espaciadora y mientras el cubo está en el aire presionamos la flecha horizontal, asistiremos seguramente a una bonita pirueta de nuestro cubo.
Esto es todo de momento. Bye.
17. CLASE RIGIDBODY (I)
Nos disponemos a estudiar otra de las clases vitales para entender el funcionamiento de Unity. Es raro en juego en el que no interviene de alguna manera la física (un enemigo se cae, un personaje salta, y coche choca contra un muro...)
La clase Rigidbody controla la posición de un objeto a través de simulación de física. El componente Rigidbody, al ser añadido a un gameobject, toma el control sobre la posición de un objeto, haciendo que caiga bajo la influencia de la gravedad, y puede calcular cómo los objetos responderán a las colisiones.
Vamos a inspeccionar unas cosas en Unity: antes que nada, si estáis siguiendo por orden estas lecciones tendréis (como yo) emparentado el cubo dentro de la cápsula, así que lo arrastramos fuera para desemparentarlo. Luego, con el cubo seleccionado, echamos un vistazo al inspector. Vemos en él diferentes apartados (su transform, su malla, un collider y elementos de renderizado) pero no un rigidbody. Lo mismo nos pasaría si examinamos la cápsula. Ambos objetos, por lo tanto, no están sometidos a leyes físicas, y en consecuencia es como si carecieran de masa y por ende fueran ajenos a la gravedad.
Vamos a regalarles un rigidbody a nuestros objetos. Para hacer eso nos vamos -con uno de los obtetos seleccionado- al menú superior, y le damos a Component=>Physics=>Rigidbody. El gameobject que teníamos selecionado tiene ahora un componente nuevo:
Hacemos lo mismo con el otro gameobject. Acto seguido, en la ventana Escena pulsamos la X de nuestro gizmo,para tener una visión de los objetos desde el eje horizontal, y comprobar mejor lo que pasará ahora. Le damos al play...
y los objetos caen, porque ya no son inmunes a la gravedad.
Lo que procede ahora, para evitar que nuestros objetos abandonen la escena a la primera de cambio, es colocar un suelo. Vamos a ello.
Antes que nada, vamos a eliminar a nuestra vieja amiga la cápsula (conocida por los más veteranos por Origen). La razón es que por su forma específica no es demasiado estable para nuestros ejemplos una vez se ve afectada por la gravedad. Así que adiós, cápsula.
Y como a rey muerto, rey puesto, nos vamos al menú y le damos a GameObject=>Create other=>Sphere. La renombramos como "Esfera".
A continuación vamos a colocar a nuestros dos objetos a ras de suelo (antes no importaba que estuvieran flotando por ahí, pero ahora no querremos empezar el juego con un objeto pegándose un tortazo contra el suelo). Colocamos, como decimos, nuestros objetos en las siguientes coordenadas de posición (las rotaciones deben estar a 0):
Cubo: 0,0,0.
Esfera: 2,0,2.
Nos vamos ahora al menú=>Gameobject=>Create Other=>Plane. Lo renombramos antes que nada como "Suelo". Luego colocamos nuestra ventana de escena en vista superior (click en eje Y del gizmo), y para acabar, en la coordenada Y de su transform.position escribimos -0.5.
Esto último supongo que merece una explicación. Veamos, tanto el cubo como la esfera tienen una altura de una unidad y su origen (el 0,0,0) de dichos objetos se halla en su centro geométrico. Esto quiere decir que cuando un cubo está en el valor 0 de su eje Y, la mitad del cubo (0,5) se halla por debajo del nivel 0 (que es donde hemos colocado el suelo). En definitiva, si tanto el cubo como la esfera y el suelo los dejáramos con sus respectivos ejes Y a cero, los dos primeros aparecerían semienterrados en el tercero. Para evitarlo, o bien levantamos todos los objetos o bien bajamos el suelo, que es lo que hemos hecho.
Démosle al play. Observamos que los objetos ya no se caen, aunque a decir verdad y siendo todos los elementos de nuestra escena del mismo color, quizás nos interesaría ponerle a nuestro suelo un color que los hiciera resaltar.
Con el mouse situado sobre la carpeta Mis Scripts, pulsamos el botón derecho y creamos otro script (javascript, recordemos). Lo llamaremos ColorSuelo, y dice así:
function Start() {
renderer.material.color=Color.red;
}
La función Start es llamada por Unity, como su nombre indica, cuando se inicia el juego. Sólo es llamada una vez, a diferencia de Update, y en este caso nos interesa que sea así ya que vamos a dejar el color de nuestro suelo fijo durante todo el juego. Salvamos y arrastramos el script a Suelo. Le damos al play.
Y voilá, el suelo se nos vuelve de color rojo y los objetos contrastan algo más. Aún y todo, la escena continúa un poco oscura, así que mejor iluminarla un poco, ¿no?
Introducimos en la escena desde el menú gameobject una luz direccional, que renombraremos como "Luz" y ubicaremos/rotaremos en las siguientes coordenadas:
Posición: -5,15,-10
Rotación: 20,0,0
Si le damos al play, deberíamos ver algo parecido a esto:
Y más o menos con esto tendríamos ya la escena "preparada" para empezar a trabajar con la clase Rigidbody.
Con la tecnología de Blogger.
BUSCADOR
PÁSATE POR EL FORO
API DE UNITY
TEMAS
- 00_INTRODUCCION (3)
- 01_CLASE OBJECT (3)
- 02_ESTRUCTURA VECTOR3 (4)
- 03_CLASE TRANSFORM (7)
- 04_CLASE RIGIDBODY (8)
- 05_CLASE COLLIDER (2)
- 06_CLASE MESHCOLLIDER (1)
- 07_CLASE CHARACTERCONTROLLER (3)
- 08_CLASE RENDERER (2)
- 09_CLASE MESHFILTER (1)
- 10_CLASE JOINT (2)
- 11_CLASE HINGEJOINT (2)
- 12_CLASE SPRINGJOINT (1)
- 13_CLASE CHARACTERJOINT (1)
- 14_CLASE BEHAVIOUR (1)
- 15_CLASE MONOBEHAVIOUR (9)
- 16_CLASE CAMERA (6)
- 17_CLASE LIGHT (3)
- 18_CLASE MATERIAL (3)
- 19_CLASE CUBEMAP (1)
- 20_CLASE RENDERTEXTURE (3)
- 21_CLASE PARTICLEEMITTER (3)
- 22_CLASE MESH (2)
- 23_CLASE GAMEOBJECT (6)
- 24_CLASE SHADER (1)
- 25_CLASE PHYSICMATERIAL (1)
- 26_CLASE COMPONENT (1)
- 27_CLASE GUIELEMENT (1)
- 28_CLASE GUITEXT (2)
- 29_CLASE GUITEXTURE (1)
- 30_CLASE GUI (8)
- 31_CLASE GUILAYOUT (4)
- 32_CLASE TEXTURE (1)
- 33_CLASE TEXTURE2D (2)
- 34_CLASE INPUT (4)
- 35_ESTRUCTURA BOUNDS (1)
- 36_CLASE COLLISION (1)
- 37_CLASE CONTROLLERCOLLIDERHIT (1)
- 38_CLASE DEBUG (1)
- 39_CLASE EVENT (3)
- 40_CLASE GIZMOS (1)
- 41_CLASE LIGHTMAPSETTINGS (1)
- 42_ESTRUCTURA MATHF (3)
- 43_CLASE PHYSICS (2)
- 44_ESTRUCTURA QUATERNION (1)
- 45_CLASE RANDOM (1)
- 46_ESTRUCTURA RAY (1)
- 47_ESTRUCTURA RAYCASTHIT (1)
- 48_ESTRUCTURA RECT (1)
- 49_CLASE RENDERSETTINGS (1)
- 50_CLASE SCREEN (1)
- 51_CLASE TIME (1)
- 52. CLASE YIELDINSTRUCTION (1)
- MONOGRAFICOS (2)



