116. ESTRUCTURA RAYCASTHIT
Estructura usada para obtener información de vuelta de un raycast (rayo proyectado).
VARIABLES:
point:
var point : Vector3
El punto de impacto en coordenadas globales donde el rayo golpea el collider
normal:
var normal : Vector3
El normal de la superficie que golpea el rayo.
baryentricCoordinate:
var barycentricCoordinate : Vector3
La coordenada baricéntrica del triángulo que golpeamos (baricentro = es un punto de una figura geométrica la recta que pasa por el cual divide la figura en dos partes iguales. )
Esto nos permite interpolar cualquiera de los datos de los vértices a lo largo de los tres ejes.
distance:
var distance : float
La distancia desde el origen del rayo hasta el punto de impacto.
triangleIndex:
var triangleIndex : int
el índice del triángulo que ha sido golpeado. El índice del triángulo es sólo válido si el colider que lo golpea es un MeshCollider.
textureCoord:
var textureCoord : Vector2
La coordenada de la textura UV en el punto de impacto. Esto puede ser usado para pinturas de textura 3d o impactos de bala dibujados. Si el collider no es una mesh collider, retorna un Vector2 a cero.
textureCoord2:
var textureCoord2 : Vector2
Las coordenadas de la textura uv secundaria.
lightmapCoord:
var lightmapCoord : Vector2
La coordinada del lightmap de uv en el punto de impacto.
colider:
var collider : Collider
El collider que fue golpeado. Esta propiedad es nula si no se golpea nada y no-nula si golpeas algo.
rigidbody:
var rigidbody : Rigidbody
El rigidbody del collider que ha sido golpeado. Si el collider no está vinculado a un rigidbody es null.
transform:
var transform : Transform
El Transform del rigidbody o collider que ha sido golpeado.
115. ESTRUCTURA RAY
Estructura que nos permite representar y modificar rayos. Un rayo es una linea infinita que empieza en un punto dado y va en alguna dirección.
VARIABLES:
origin:
var origin : Vector3
El punto de origen del rayo.
direction:
var direction : Vector3
La dirección del rayo. La dirección es siempre un vector normalizado(1,0,0 o 0,1,0 o 0,0,1. Si asignamos un vector de longitud distinta de la unidad, será normalizado.
FUNCIONES:
Ray:
static function Ray (origin : Vector3, direction : Vector3) : Ray
Crea un rayo que empieza en origin a lo largo de direction.
var ray = new Ray (transform.position, transform.forward);
En este ejemplo crearíamos un rayo que parte de la posición del transform al que está vinculado el script y que parte hasta el infinito a través del eje Z.
GetPoint:
function GetPoint (distance : float) : Vector3
Devuelve un punto tantas unidades como le pasemos en el parámetro a lo largo del rayo.
var r : Ray;
print( r.GetPoint (10) );
Este ejemplo imprime un punto situado 10 unidades a lo largo del rayo.
ToString:
function ToString () : String
function ToString (format : String) : String
Devuelve un string formateado para este rayo.
114. CLASE RANDOM
Clase para generar números aleatorios.
VARIABLES DE CLASE:
seed:
static var seed : int
Coloca la semilla para el generador de números aleatorios.
value:
static var value : float
Devuelve un número aleatorio entre 0.0 (inclusive) y 1.0 (inclusive).
for(var x: int =0; x<10; x++){
print(Random.value);
}
Podréis comprobar que los diez números que nos aparecerán en pantalla están entre ambos valores.
insideUnitSphere:
static var insideUnitSphere : Vector3
Devuelve un punto aleatorio dentro de una esfera con radio 1.
transform.position = Random.insideUnitSphere * 2;
Este ejemplo situaría nuestro cubo en un punto aleatorio dentro de una esfera (3 dimensiones) con un radio de 2 unidades.
insideUnitCircle:
static var insideUnitCircle : Vector2
Devuelve un punto aleatorio dentro de un círculo con radio 1.
var newPosition : Vector2 = Random.insideUnitCircle * 5;
transform.position.x = newPosition.x;
transform.position.y = newPosition.y;
en este caso nuestro cubo se movería dentro de un círculo (2D) con radio de 5 unidades.
onUnitSphere:
static var onUnitSphere : Vector3
Devuelve un punto aleatorio sobre la superficie de una esfera con radio 1.
function FixedUpdate(){
rigidbody.velocity = Random.onUnitSphere * 10;
}
Esta función mueve al rigidbody de nuestro cubo a una velocidad de 10 en una dirección aleatoria, por lo que no esperéis ver otra cosa al darle al play que un cubo volviéndose loco.
rotation:
static var rotation : Quaternion
Devuelve una rotación aleatoria (read only)
var prefab : GameObject;
Instantiate(prefab, Vector3.zero, Random.rotation);
Este ejemplo instanciaría un nuevo gameobject en el centro de la escena y con una rotación aleatoria.
FUNCIONES DE CLASE:
Range:
static function Range (min : float, max : float) : float
Devuelve un float aleatorio entre un min (inclusive) y max (inclusive).
var prefab : GameObject;
function Start () {
var position: Vector3 = Vector3(Random.Range(-5.0, 5.0), 0, Random.Range(-5.0, 5.0));
Instantiate(prefab, position, Quaternion.identity);
}
Si arrastramos la esfera a la variable expuesta prefab, al darle al play observaremos que se clona una instancia de la misma y aparece en un lugar aleatorio en un margen de 5 metros en los ejes X y Z.
static function Range (min : int, max : int) : int
La misma función, pero admite y devuelve integers.
113. ESTRUCTURA QUATERNION
Nuestros amigos los quaterniones son usados para representar rotaciones. Unity internamente usa Quaterniones para representar todas las rotaciones.
Sin embargo, los quaterniones están basados en números complejos y no son fáciles de entender intuitivamente, así que casi nunca accederemos o modificaremos los componentes individuales de un Quaternión (x,y,z,w). Lo que será más habitual es que queramos meramente tomar rotaciones ya existentes (por ej desde un Transform) y usarlas para construir nuevas rotaciones (por ej interpolando suavemente entre dos rotaciones).
Las funciones sobre Quaterniones que usaremos el 99% del tiempo (las otras funciones son para usos exóticos) son Quaternion.LookRotation, Quaternion.Angle, Quaternion.Euler, Quaternion.Slerp, Quaternion.FromToRotation y Quaternion.identity.
VARIABLES:
eulerAngles:
var eulerAngles : Vector3
Devuelve la representacion en ángulos euler de la rotacion.
FUNCIONES:
ToAngleAxis:
function ToAngleAxis (out angle : float, out axis : Vector3): void
Convierte una rotación en una representación de angle-axis (ángulo de eje)
SetFromToRotation:
function SetFromToRotation (fromDirection : Vector3, toDirection : Vector3) : void
Crea una rotación que rota desde fromDirection hasta toDirection.
ToString:
function ToString () : String
function ToString (format : String) : String
Devuelve un string formateado del Quaternion.
VARIABLES DE CLASE:
identity:
static var identity : Quaternion
Sería el equivalente a no rotation. El transform quedará perfectamente alineado con el mundo o con los ejes del padre.
FUNCIONES DE CLASE:
AngleAxis:
static function AngleAxis (angle : float, axis : Vector3) : Quaternion
Crea una rotación que rota los ángulos que le pasemos como primer parámetro con respecto al eje que le pasamos como segundo.
O sea, para girar nuestro cubo (previamente eliminadle el character controller que le añadimos el capítulo anterior), tecleamos:
transform.rotation = Quaternion.AngleAxis(30, Vector3.up);
De esta forma tan simple giramos el cubo 30 grados sobre el eje Y.
FromToRotation:
static function FromToRotation (fromDirection : Vector3, toDirection : Vector3) : Quaternion
Crea una rotación que rota desde el primer parámetro al segundo.
Normalmente usaremos esta función para rotar un transform uno de cuyos ejes sigue un objetivo en una dirección en coordenadas globales.
Slerp:
static function Slerp (from : Quaternion, to : Quaternion, t : float) : Quaternion
Interpola esfériamente del primer al segundo parámetro durante el tercero.
RotateTowards:
static function RotateTowards (from : Quaternion, to : Quaternion, maxDegreesDelta : float) : Quaternion
Efectúa una rotación entre el primer parámetro y el segundo. Esto es esencialmente lo mismo que Quaternion.Slerp, pero aquí la función se aregura de que la velocidad angular nunca exceda de la marcada en maxDegreesDelta. Si maxDegreesDelta tiene un valor negativo la rotación es empujada lejos del segundo parámetro (to).
Angle:
static function Angle (a : Quaternion, b : Quaternion) : float
Devuelve el ángulo en grados entre dos rotaciones dadas.
Veamos eso:
var objetivo : Transform;
function Update () {
var angulo : float = Quaternion.Angle(transform.rotation, objetivo.rotation);
Debug.Log(angulo);
}
Arrastramos la esfera a la variable expuesta objetivo. Si pulsamos play, observaremos que nos aparece un cero en pantalla, ya que (si teneis ambas figuras colocadas como yo) ambas tienen sus respectivas rotaciones a 0,0,0. Probad ahora a cambiar la rotación de una -o las dos- figuras.
Euler:
static function Euler (x : float, y : float, z : float) : Quaternion
static function Euler (euler : Vector3) : Quaternion
Devuelve en quaterniones una rotación pasada como parámetro en grados euler.
112. CLASE PHYSICS (y II)
CapsuleCast:
static function CapsuleCast (point1 : Vector3, point2 : Vector3, radius : float, direction : Vector3, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean
static function CapsuleCast (point1 : Vector3, point2 : Vector3, radius : float, direction : Vector3, out hitInfo : RaycastHit, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean
Lanza una cápsula contra todos los colliders de la escena y devuelve información de contra qué ha chocado. Devuelve true cuando el sweep (barrido) de la cápsula choca con algún collider.
Los parámetros de esta función son:
point1 El inicio de la cápsula.
point2 El fin de la cápsula.
radius El radio de la cápsula.
direction La dirección en la cual hace el barrido la cápsula.
hitInfo Si devuelve true, hitInfo contendrá más información sobre dónde golpeó
el collider.
distance La longitud del barrido.
layerMask Un Layer mask que se usa para ignorar selectivamente colliders cuando
se proyecte la cápsula.
La cápsula viene conformada por las dos esferas con radios alrededor del point1 y point2, que forman los dos finales de la cápsula. Esto es útil cuando un Raycast no tiene suficiente precisión para lo que queremos hacer, como por ejemplo asegurarnos de que un personaje podrá moverse a cualquier sitio sin colisionar con nada en el camino.
SphereCast:
static function SphereCast (origin : Vector3, radius : float, direction : Vector3, out hitInfo : RaycastHit, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean
Proyecta una esfera contra todos los colliders de la escena y proporciona información sobre los que colisionan. Devuelve true si topa con alguno en su barrido.
Cuenta con estos parámetros:
origin El centro de la esfera al principio del barrido.
radius El radio de la esfera.
direction La dirección en la cual hace el barrido la esfera.
hitInfo Si la función devuelve true, esta variable contendrá más información
acerca de dónde el collider colisionó (Para más información ver:
RaycastHit).
distance La longitud del barrido.
layerMask Un Layer mask que se usa para ignorar selectivamente colliders cuando
se proyecta la cápsula.
Esta función es útil cuando un Raycast no nos da suficiente precisión, como por ejemplo en el caso en que queramos averiguar si un objeto de un determinado tamaño, como un character, será capaz de de moverse a algún lado sin colisionar con algo por el camino. En casos como estos es preferible usar la función SphereCast.
Hemos de tener presente, eso sí, que la SphereCast no funcionará contra aquellos colliders configurados como triggers.
Probemos un ejemplo. Previamente hay que añadirle un character controller al cubo. Acto seguido tecleamos este script:
function Update () {
var hit : RaycastHit;
var charCtrl : CharacterController = GetComponent(CharacterController);
var p1 : Vector3 = transform.position + charCtrl.center;
if (Physics.SphereCast (p1, charCtrl.height /2, transform.right, hit, 10)) {
Debug.Log("Hay un obstáculo a " + hit.distance + " metros");
}
}
Lo que hemos hecho aquí es, a grandes rasgos, que nuestro cubo efectúe un barrido hacia la derecha en busca de obstáculos para un character con un radio equivalente a la mitad de la altura de nuestro character. Al topar con uno, se muestra un mensaje en pantalla junto con información suplementaria, como en este caso la distancia a que se halla dicho obstáculo. El ejemplo es un poco rupestre, pero nos permite intuir la utilidad de esta función para aplicársela a un personaje.
static function SphereCast (ray : Ray, radius : float, distance : float Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean
static function SphereCast (ray : Ray, radius : float, out hitInfo : RaycastHit, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean
CapsuleCastAll:
static function CapsuleCastAll (point1 : Vector3, point2 : Vector3, radius : float, direction : Vector3, distance : float = Mathf.Infinity, layermask : int = kDefaultRaycastLayers) : RaycastHit[]
Es como Physics.CapsuleCast, pero devolviendo todos los colliders que la cápsula intercepta en su barrido e información sobre los mismos. Devuelve un array con todos esos colliders.
Parámetros:
point1 El principio de la cápsula.
point2 El final de la cápsula.
radius El radio de la cápsula.
direction La dirección en la cual efectúa el barrido la cápsula.
distance La longitud del barrido.
layerMask Un Layer mask que se usa para ignorar selectivamente algunos
colliders cuando se proyecta la cápsula
La cápsula es definida por las dos esferas con su radio alrededor de point1 y point2, que forman los dos extremos de la cápsula. Son devueltos datos de todos los colliders contra los que nuestra cápsula proyectada choque en esa dirección.
Recordemos que esta función no funciona contra colliders configurados como triggers.
SphereCastAll:
static function SphereCastAll (origin : Vector3, radius : float, direction : Vector3, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : RaycastHit[]
static function SphereCastAll (ray : Ray, radius : float, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : RaycastHit[]
Como physics.SphereCast, pero devolviendo todos los colliders que colisionen.
CheckSphere:
static function CheckSphere (position : Vector3, radius : float, layerMask : int = kDefaultRaycastLayers) : boolean
Devuelve true si hay algún collider tocando la esfera definida por position y radius en coordenadas globales.
CheckCapsule:
static function CheckCapsule (start : Vector3, end : Vector3, radius : float, layermask : int = kDefaultRaycastLayers) : boolean
Devuelve true si hay algún collider tocando la cápsula definida por el eje que va de start a end y que tiene el radio radius, en coordenadas globales.
IgnoreCollision:
static function IgnoreCollision (collider1 : Collider, collider2 : Collider, ignore : boolean = true) : void
Hace que el sistema de detección de colisiones ignore todas las colisiones entre collider1 y collider2. Esto es muy útil por ejemplo para que los proyectiles no colisionen con el objeto que los dispara.
Esta función tiene algunas limitaciones:
1.- No es persistente. Esto significa que el estado de ignorar colisión no será almacenado en el editor cuando se salve la escena.
2.- Sólo puedes aplicar esta función a colliders en gameobjects activos. Cuando se desactiva el collider o el rigidbody vinculado se pierde el estado de IgnoreCollision y tendrás que llamar a esta función otra vez.
IgnoreLayerCollision:
static function IgnoreLayerCollision (layer1 : int, layer2 : int, ignore : boolean = true) : void
Hace que el sistema de detección de colisiones ignore todas las colisiones entre cualquier collider en layer1 y otros en layer2.
GetIgnoreLayerCollision:
static function GetIgnoreLayerCollision (layer1 : int, layer2 : int) : boolean
Booleano que indica si las colisiones entre layer1 y layer2 están siendo ignoradas.
111. CLASE PHYSICS (I)
Componen esta clase, al igual que la estructura Mathf anterior, propiedades globales y métodos de ayuda relacionados con las físicas.
VARIABLES DE CLASE:
gravity:
static var gravity : Vector3
La gravedad aplicada a todos los rigidbodies en la escena. Puede ser desconectada para un rigidbody individual usando su propiedad useGravity.
FUNCIONES DE CLASE:
Raycast:
static function Raycast (origin : Vector3, direction : Vector3, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean
Lanza un rayo contra todos los colliders en la escena. Devuelve true cuando el rayo intersecta algún collider.
Tiene los siguientes parámetros:
origin El punto inicial del rayo en coordenadas globales.
direction La dirección del rayo.
distance La longitud o fuerza del rayo.
layerMask Una máscara de distribución (Layer mask) que se usa para ignorar
selectivamente colliders cuando se proyecta un rayo.
Por ejemplo:
function Update () {
var derecha : Vector3 = transform.TransformDirection (Vector3.right);
if (Physics.Raycast (transform.position, derecha, 10)) {
print ("Hay algo a mi derecha");
}
}
Lo que hacemos aquí es primero tomar la dirección local de nuestro cubo y convertirla en dirección global, a través de la función TransformDirection. Dicha dirección global la almacenamos en la variable "derecha". Acto seguido, imprimimos un mensaje si desde la posición de nuestro cubo en una distancia no superior a diez metros hay a la derecha global del mismo otro objeto.
static function Raycast (origin : Vector3, direction : Vector3, out hitInfo : RaycastHit, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean
Proyecta un rayo contra todos los colliders en la escena y devuelve información detallada sobre qué golpeó.
Los parámetros de este segundo prototipo de función son:
origin El punto de inicio del rayo en coordenadas globales.
direction La dirección del rayo.
distance La fuerza o longitud del rayo.
hitInfo Si se devuelve true, esta variable contendrá más información sobre
donde colisionó el collider.
layerMask Un layer mask usado para ignorar colliders selectivamente cuando se
proyecte un rayo.
static function Raycast (ray : Ray, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean
static function Raycast (ray : Ray, out hitInfo : RaycastHit, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : boolean
Son similares a las funciones anteriores, sólo que usando ray.origin y ray.direction en vez de origen y dirección como sendos Vector3.
RaycastAll:
static function RaycastAll (ray : Ray, distance : float = Mathf.Infinity, layerMask : int = kDefaultRaycastLayers) : RaycastHit[]
static function RaycastAll (origin : Vector3, direction : Vector3, distance : float = Mathf.Infinity, layermask : int = kDefaultRaycastLayers) : RaycastHit[]
Lanza un rayo a través de la escena y devuelve todos los choques.
Vamos a adaptar un ejemplo del manual de referencia:
function Update () {
var choques : RaycastHit[];
choques = Physics.RaycastAll (transform.position, transform.right, 100.0);
for (var i = 0;i < choques.Length; i++) {
var miChoque : RaycastHit = choques[i];
var renderer = miChoque.collider.renderer;
if (renderer) {
renderer.material.shader = Shader.Find("Transparent/Diffuse");
renderer.material.color.a = 0.3;
}
}
}
Vamos paso a paso en la explicación. Primero declaramos una variable que contendrá un array de tipo RaycastHit, que es precisamente lo que hemos visto que devuelve la función RaycastAll. La inicializamos con todas aquellas colisiones que sufra nuestro rayo, el cual proyectamos desde el cubo 100 metros a la derecha.
Dado que puede haber más de una colisión, iteramos a través del array y el collider con el que se ha producido cada colisión le es asignado temporalmente a la variable miChoque, a través de la cual lo volvemos semitransparente.
Si pulsamos play vemos que nuestra esfera se torna semiinvisible.
LineCast:
static function Linecast (start : Vector3, end : Vector3, layerMask : int = kDefaultRaycastLayers) : boolean
Devuelve true si hay algún collider intersectando la línea entre start y end.
static function Linecast (start : Vector3, end : Vector3, out hitInfo : RaycastHit, layerMask : int = kDefaultRaycastLayers) : boolean
En este segundo prototipo, si se devuelve true, hitinfo contendrá más información sobre dónde colisionó el collider.
OverlapSphere:
static function OverlapSphere (position : Vector3, radius : float, layerMask : int = kAllLayers) : Collider[]
Devuelve un array con todos los colliders que toquen o estén dentro de la esfera cuya posición y radio pasamos como parámetros.
110. ESTRUCTURA MATHF (y III)
SmoothDamp:
static function SmoothDamp (current : float, target : float, ref currentVelocity : float, smoothTime : float, maxSpeed : float = Mathf.Infinity, deltaTime : float = Time.deltaTime) : float
Gradualmente cambia un valor hacia un objetivo en un determinado tiempo. La función se puede usar para suavizar la transición de valores, colores, posiciones, escalares….
Cuenta con los siguientes parámetros:
current La posición actual.
target La posición que estamos tratando de alcanzar.
currentVelocity La velocidad actual. Este valor es modificado por la función cada
vez que la llamamos.
smoothTime Aproximadamente el tiempo que tardaremos en alcanzar el objetivo.
Un valor pequeño hará que allcancemos el objetivo más rápido.
maxSpeed Opcionalmente nos permite fijar la velocidad máxima.
deltaTime El tiempo desde la última llamada a esta función. Por defecto
Time.deltaTime.
Un ejemplo:
var objetivo : Transform;
var tiempoEmpleado = 3;
private var yVelocity =4.0;
function Update () {
var newPosition : float = Mathf.SmoothDamp(transform.position.x,
objetivo.position.x, yVelocity, tiempoEmpleado);
transform.position = Vector3(newPosition, transform.position.y,
transform.position.z);
}
Salvamos y arrastramos el cubo a la variable expuesta "objetivo". Lo que aquí estamos haciendo es usar la función SmoothDamp para ir marcando la nueva posición de nuestro cubo. El punto de origen será la posición actual del cubo (en el eje x), el destino la posición actual en dicho eje del transform que marcamos como objetivo, le establecemos un tiempo para que el origen alcance al objetivo de 3 segundos y le limitamos la velocidad máxima que pueda alcanzar nuestro cubo a cuatro metros por segundo.
SmoothDampAngle:
static function SmoothDampAngle (current : float, target : float, ref currentVelocity : float, smoothTime : float, maxSpeed : float = Mathf.Infinity, deltaTime : float = Time.deltaTime) : float
Cambia gradualmente un ángulo dado en grados hacia el ángulo que constituye el objetivo en un tiempo determinado. El uso más común de esta función es para suavizar una cámara que esté siguiendo algún personaje o escena.
Repeat:
static function Repeat (t : float, length : float) : float
Introduce en un bucle el valor t, de tal manera que nunca sea más grande que length y nunca más pequeño que 0.
PingPong:
static function PingPong (t : float, length : float) : float
Hace rebotar el valor t, de tal manera que nunca sea mayor que length y nunca mayor que 0. El valor retornado se moverá atrás y adelante entre 0 y length.
InverseLerp:
static function InverseLerp (from : float, to : float, value : float) : float
Calcula el parámetro Lerp entre dos valores.
ClosestPowerOfTwo:
static function ClosestPowerOfTwo (value : int) : int
Retorna la potencia de dos más cercana.
IsPowerOfTwo:
static function IsPowerOfTwo (value : int) : boolean
Devuelve true si el valor es potencia de dos
NextPowerOfTwo:
static function NextPowerOfTwo (value : int) : int
Devuelve el valor de la siguiente potencia de dos.
DeltaAngle:
static function DeltaAngle (current : float, target : float) : float
Calcula la diferencia más corta entre dos ángulos dados.
109. ESTRUCTURA MATHF (II)
Ceil:
static function Ceil (f : float) : float
Devuelve el integer más pequeño igual o mayor que f.
Floor:
static function Floor (f : float) : float
Devuelve el mayor integer igual o más pequeño que f.
Round:
static function Round (f : float) : float
Devuelve f redondeado al integer más cercano. Si el número acaba en .5 y queda entre dos integers, uno de los cuales es par y el otro impar, se devolverá el numero par.
CeilToInt:
static function CeilToInt (f : float) : int
Devuelve el integer más pequeño igual o mayor que f.
FloorToInt:
static function FloorToInt (f : float) : int
Devuelve el mayor integer menor o igual que f.
RoundToInt:
static function RoundToInt (f : float) : int
Devuelve f rendondeada al integer más cercano. Si e número acaba en .5 y por lo tanto está a medio camino entre dos integers, uno impar y el otro par, se devuelve el número par.
Sign:
static function Sign (f : float) : float
Devuelve el signo de f. Devuelve 1 si es positivo o cero, y -1 si f es negativo.
Clamp:
static function Clamp (value : float, min : float, max : float) : float
static function Clamp (value : int, min : int, max : int) : int
Restringe un valor entre un mínimo y un máximo, sean floats o ints.
Vamos a verlo con un ejemplo:
for(var x : int = 0; x <= 10; x++) {
var numeroFijado : int = Mathf.Clamp(x, 1, 5);
Debug.Log(numeroFijado);
}
Mediante un bucle for le pasamos como primer parámetro a la función Clamp números del 10 al diez. Si desplegamos la consola tras probar este ejemplo veremos que cuando x vale 0, clamp devuelve el valor mínimo fijado (en este caso 1). Lo mismo pasa cuando x vale más de 5.
Clamp01:
static function Clamp01 (value : float) : float
Fija un valor entre 0 y 1 y lo devuelve.
Lerp:
static function Lerp (from : float, to : float, t : float) : float
Interpola a hacia b pasando por t. t queda fijada entre 0 y 1. Cuando t = 0 devuelve from. Cuando t = 1 devuelve to. Cuando t = 0.5 devuelve la media de a y b.
LerpAngle:
static function LerpAngle (a : float, b : float, t : float) : float
Lo mismo que lerp, pero asegurándonos de interpolar valores correctamente cuando dé un giro de 360 grados. Las variables a y b representan grados.
Para ilustrar esta función y la anterior vamos a apañar un pequeño ejemplo. Sería interesante que eliminárais el script vinculado a la esfera. Editamos:
var origen = -2.0;
var destino = 1.0;
var anguloInicial= 0.0;
var anguloFinal= 90.0;
function Update () {
transform.position = Vector3(Mathf.Lerp(origen, destino, Time.time * 0.1), 0, 0);
var angle : float = Mathf.LerpAngle(anguloInicial, anguloFinal, Time.time * 0.1);
transform.eulerAngles = Vector3(0, angle, 0);
}
Salvamos y vinculamos el script al cubo. A la función Lerp le pasamos el parámetro de situación inicial -2, que coincide con su posición actual en el eje x, y le indicamos un destino en 1. Tradicionalmente como tercer parámetro se coloca Time.time, que pasa de 0 a 1 en un segundo, pero como queremos que el trayecto sea más lento, multiplicamos Time.time por 0.1, de tal manera que el trayecto total dure 10 segundos.
Otro tanto hacemos con el angulo inicial y final. Como resultado, el cubo se moverá tres metros en el eje X y girará 90 grados sobre el eje Y en diez segundos.
MoveTowards:
static function MoveTowards (current : float, target : float, maxDelta : float) : float
Mueve el valor que indicamos en el parámetro current hacia el que indicamos en target. Hasta aquí la función sería parecida a Mathf.Lerp, pero aquí nos aseguramos de la que velocidad no exceda de maxDelta. Valores negativos para maxDelta empuja el valor lejos del objetivo.
MoveTowardsAngle:
static function MoveTowardsAngle (current : float, target : float, maxDelta : float) : float
Lo mismo que MoveTowards pero estando seguros de que los valores se interpolarán correctamente cuando gire 360 grados.
La diferencia de MoveTowards y MoveTowardsAngle con respecto de Lerp y LerpAngle la veremos más fácilmente rehaciendo el script anterior:
var origen = -2.0;
var destino = 1.0;
var minAngle = 0.0;
var maxAngle = 90.0;
function Update () {
transform.position = Vector3(Mathf.MoveTowards(origen, destino, Time.time * 1),
0,0);
var angle : float = Mathf.MoveTowardsAngle(minAngle, maxAngle, Time.time * 30);
transform.eulerAngles = Vector3(0, angle, 0);
}
La diferencia la tenemos que hallar en el tercer parámetro. En el caso de MoveTowards lo que le estamos pidiendo aquí al cubo es que se mueva en el eje x de la posición -2 a la 1 (3 metros, o sea) a razón de un metro por segundo. Y Para MoveTowardsAngle estamos indicándole al cubo que gire 90 grados a razón de 30 grados por segundo. De esta manera, en 3 segundos el cubo debería haber completado ambos movimientos. Probadlo.
SmoothStep:
static function SmoothStep (from : float, to : float, t : float) : float
Interpola entre mínimo y máximo y facilita entrada y salida de los límites. Sería como Lerp, pero con un impulso inicial. Si meramente sustituís em el último script MoveTowards por SmoothStep veréis a qué me refiero.
Approximately:
static function Approximately (a : float, b : float) : boolean
Compara si dos valores en punto flotante son similares. Debido a que los numeros en punto flotante son imprecisos no es recomendable compararlos usando el operador == (podría no devolver true), y es mejor utilizar esta función.
108. ESTRUCTURA MATHF (I)
Estructura que contiene una colección de funciones matemáticas que podemos usar para nuestros scripts.
VARIABLES DE CLASE:
PI:
static var PI : float
El famoso 3.141592. (sólo lectura)
Como pequeña anotación, observad que las variables de clase de Mathf comienzan por mayúscula, al contrario de las variables de clase del resto de clases y funciones en Unity. Tenedlo presente, ya que es una fuente importante de errores.
Infinity:
static var Infinity : float
Representación del infinito positivo (sólo lectura)
NegativeInfinity:
static var NegativeInfinity : float
Una representación del infinito negativo (sólo lectura)
Deg2Rad:
static var Deg2Rad : float
Conversión constante de grados a radianes (sólo lectura)
Rad2Deg:
static var Rad2Deg : float
Conversión constante de radianes a grados (sólo lectura)
Epsilon:
static var Epsilon : float
El valor más pequeño que un float puede tener diferente de cero (sólo lectura)
FUNCIONES DE CLASE:
Sin:
static function Sin (f : float) : float
Devuelve el seno del ángulo f en radianes.
Cos:
static function Cos (f : float) : float
Devuelve el coseno del ángulo f en radianes.
Tan:
static function Tan(f : float) : float
Devuelve la tangente del ángulo f en radianes.
Asin:
static function Asin (f : float) : float
Devuelve el arco seno de f menos el ángulo en radianes cuyo seno es f.
Acos:
static function Acos (f : float) : float
Devuelve el arco coseno de f menos el ángulo en radianes cuyo coseno es f.
Atan:
static function Atan (f : float) : float
Devuelve el arco tangente de f menos el ángulo en radianes cuya tangente es f.
Atan2:
static function Atan2 (y : float, x : float) : float
Devuelve el ángulo en radianes cuya tangente es y/x.
El valor retornado es el ángulo entre el eje X y un vector 2D que empieza en cero y acaba en (x,y)
Sqrt:
static function Sqrt (f : float) : float
Devuelve la raíz cuadrada de f.
Abs:
static function Abs (value : float) : float
static function Abs (value : int) : int
Devuelve el valor absoluto de value.
Min:
static function Min (a : float, b : float) : float
static function Min (params values : float[]) : float
static function Min (a : int, b : int) : int
static function Min (params values : int[]) : int
Devuelve el valor mínimo de dos o más valores dados.
Max:
static function Max (a : float, b : float) : float
static function Max (params values : float[]) : float
static function Max (a : int, b : int) : int
static function Max (params values : int[]) : int
Devuelve el valor máximo de dos o más valores.
Pow:
static function Pow (f : float, p : float) : float
Devuelve f elevado a la potencia p.
Exp:
static function Exp (power : float) : float
Devuelve la potencia natural de un determinado número.
Log:
static function Log (f : float, p : float) : float
static function Log (f : float) : float
Devuelve el logaritmo de un determinado número en una base especificada.
Log10:
static function Log10 (f : float) : float
Devuelve el logaritmo en base diez de un determinado número.
107. CLASE LIGHTMAPSETTINGS
Almacena los mapas de luces (lightmaps) de la escena.
Una escena puede tener varios lightmaps almacenados en ella, y suss componentes Renderer pueden usar esos lightmaps. Esto hace posible usar el mismo material en múltiples objetos, mientras cada objeto puede referirse a diferentes lightmaps o diferentes porciones del mismo lightmap.
VARIABLES DE CLASE:
lightmaps:
static var lightmaps : LightmapData[]
Es un array de tipo LightmapData que puede almacenar diferentes lightmaps. LightmapData es una clase con dos variables:
lightmapFar: Lightmap que almacena la totalidad de la luz entrante.
lightmapNear: Lightmap que almacena sólo la luz indirecta entrante.
lightsmapMode:
static var lightmapsMode : LightmapsMode
Modo de renderizado de lightmaps. LightmapsMode es una enumeración con los siguientes dos valores:
Single: Modo de renderizado de lightmap tradicional.
Dual: Modo de renderizado de lightmap dual.
106. CLASE GIZMOS
Los Gizmos son usados para permitir un debug visual o bien para colocar ayudas en la vista de escena.
Todos los gizmos deben ser dibujados o con la función OnDrawGizmos o con la función. OnDrawGizmosSelected. La diferencia de ambas es que:
OnDrawGizmos es llamada cada frame.
OnDrawGizmosSelected es llamada sólo si el objeto al cual está vinculado el script es seleccionado.
VARIABLES DE CLASE:
color:
static var color : Color
Establece el color para los gizmos que serán dibujados a continuación.
Vamos a hacer un pequeño ejemplo. Aseguráos de que MiPrimerScript sigue estando vinculado a la esfera, y acto seguido deseleccionar cualquier gameobject haciendo click en un espacio vacío de la Jerarquía. Comprobamos que en la vista game tengamos marcada la pestaña Gizmos. Escribimos:
function OnDrawGizmosSelected () {
Gizmos.color = Color.blue;
var direction : Vector3 = transform.TransformDirection (Vector3.forward) * 5;
Gizmos.DrawRay (transform.position, direction);
}
Le damos al play y no parece ocurrir nada. Esto es porque estamos llamando a la función OnDrawGizmosSelected, que sólo muestra el dibujo cuando seleccionamos el objeto al cual va vinculado el script, así que en la jerarquía seleccionamos la esfera y automáticamente nos debería aparecer una línea de color azul que va desde la posición del transform de la esfera cinco metros en adelante.
FUNCIONES DE CLASE:
DrawRay:
static function DrawRay (r : Ray) : void
static function DrawRay (from : Vector3, direction : Vector3) : void
Dibuja un rayo que empieza desde from hasta from + direction. Lo hemos visto en funcionamiento en el ejemplo anterior.
DrawWireSphere:
static function DrawWireSphere (center : Vector3, radius : float) : void
Dibuja una esfera de alambre con centro y radio.
var radio = 2.0;
function OnDrawGizmos() {
Gizmos.color = Color.cyan;
Gizmos.DrawWireSphere (transform.position, radio);
}
Meramente como apunte, aquí la esfera de alambre se ve tengamos o no seleccionado el game object esfera, porque la hemos dibujado con la función OnDrawGizmos.
DrawSphere:
static function DrawSphere (center : Vector3, radius : float) : void
Dibuja una esfera sólida con centro y radio.
DrawWireCube:
static function DrawWireCube (center : Vector3, size : Vector3) : void
Dibuja una caja de alambre con centro y tamaño.
DrawCube:
static function DrawCube (center : Vector3, size : Vector3) : void
Dibuja una caja sólida con centro y tamaño.
DrawIcon:
static function DrawIcon (center : Vector3, name : String) : void
Dibuja un icono en posición global en la vista de escena. El icono deberá tener el mismo nombre que le asignamos al parámetro name y estará ubicado en las coordenadas que le pasemos al parámetro center. El path del icono puede encontrarse en la carpeta Assets/Gizmos.
Vamos por partes: Antes que nada necesitamos una imagen tipo icono. Yo para el ejemplo he usado ésta.
Renombramos a la imagen como "nave". Por otro lado, en el archivo donde estamos guardando estos ejemplos, dentro de la carpeta assets, hemos de crear una carpeta llamada Gizmos, que es el path que Unity buscará para dar con los iconos de este tipo. Luego arrastramos nuestra nave a la recién creada carpeta.
Y ahora editamos el script:
function OnDrawGizmos () {
Gizmos.DrawIcon (transform.position + Vector3(0,2,0), "nave.png");
}
Pulsamos el play, y dos metros por encima de nuestra esfera debería aparecernos la nave, tal que así:
DrawGUITexture:
static function DrawGUITexture (screenRect : Rect, texture : Texture, mat : Material = null) : void
static function DrawGUITexture (screenRect : Rect, texture : Texture, leftBorder : int, rightBorder : int, topBorder : int, bottomBorder : int, mat : Material = null) : void
Dibuja una textura en coordenadas de pantalla. Es útil para backgrounds de GUI.
105. CLASE EVENT (y III)
FUNCIONES:
GetTypeFromControl:
function GetTypeForControl (controlID : int) : EventType
Esta función devuelve un tipo de evento que es filtrado para un determinado control cuya id pasamos como parámetro. Esta función es usada para implementar bloqueos de ratón y de focos de teclado.
El id del control para el que requerimos el tipo de evento se obtiene de GUIUtilty.GetControlID (), y en EventType podemos ver una lista de sus posibles valores.
Use:
function Use () : void
Evento ya utilizado. deberíamos llamar a este método cuando ya hemos usado un evento. El tipo de evento será colocado en EventType.Used, causando que otros elementos GUI lo ignoren.
VARIABLES DE CLASE:
current:
static var current : Event
El evento actual/corriente que está siendo procesado en este mismo momento.
Un ejemplo:
function OnGUI() {
var miEvento : Event = Event.current;
if(miEvento.type != EventType.repaint && miEvento.type != EventType.layout){
Debug.Log("Current detected event: " + Event.current);
}
}
Salvamos y tras pulsar al play disparamos los eventos que deseemos. Detenemos el reproductor y accedemos a la consola donde se muestran los mensajes haciendo click sobre el último y ahí tendremos toda la información sobre teclas pulsadas, movimientos y clics del ratón, etc. Observaréis que descarté la impresión de eventos de tipo repaint y layout, que son los que se producen de manera automática y en un número mayor.
104. CLASE EVENT (II)
clickCount:
var clickCount : int
Cuántos clicks de ratón consecutivos hemos recibido.
Es usado en el evento EventType.MouseDown. Usadlo para diferenciar entre un click único y un doble click.
Un ejemplo:
private var numeroClicks : int = 0;
function OnGUI() {
var miEvento : Event = Event.current;
if (miEvento.isMouse) {
numeroClicks +=miEvento.clickCount;
Debug.Log("Mouse clicks: " + numeroClicks);
}
}
Si lo probamos, vemos que tenemos un contador de clicks que contabiliza cada actividad (down y up) del botón del ratón desde el inicio del juego. Es una adaptación del script que está en el manual de referencia. Si os fijáis, declaramos la variable numeroClicks fuera de la función onGUI, para que no nos contabilice (como hace en el manual de referencia) los clicks de cada frame, sino los totales. Por lo demás, el script no tiene mucho misterio: inicializamos una variable de tipo Event con el evento actual, nos aseguramos de que el evento tenga que ver con el ratón y pasamos a contar clicks.
character:
var character : char
El tipo de caracter.
function OnGUI() {
var miEvento : Event = Event.current;
if (miEvento.isKey) {
Debug.Log("Pulsado caracter: " + miEvento.character);
}
}
commandName
var commandName : String
El nombre de un evento de tipo ExecuteCommand o Validate Command ("Copy", "Cut", "Paste", "Delete", "FrameSelected", "Duplicate", "SelectAll", etc)
keyCode:
var keyCode : KeyCode
El key code para eventos de teclado. Usado en los eventos EventType.KeyDown y EventType.KeyUp; devuelve el valor del KeyCode, por lo que se usa para manejar, por ejemplo, teclas de cursor, de funciones, etc.
Teclead este código y tras salvar y darle al play pulsad por ejemplo una de las flechas de desplazamiento del teclado:
function OnGUI() {
var miEvento : Event = Event.current;
if (miEvento.isKey) {
Debug.Log("El key code es: " + miEvento.keyCode);
}
}
shift:
var shift : boolean
¿Está shift pulsado? (sólo lectura)
control:
var control : boolean
¿Está control pulsado? (sólo lectura)
alt:
var alt : boolean
¿Está alt pulsado? (Sólo lectura)
capsLock:
var capsLock : boolean
¿Está el bloqueo de mayúsculas pulsado? (sólo lectura)
numeric:
var numeric : boolean
¿Se está presionando alguna tecla del teclado numérico) (sólo lectura)
functionKey:
var functionKey : boolean
¿Es la tecla presionada una tecla de función (alt, ctrl, shift, etc)? (Sólo lectura)
isKey:
var isKey : boolean
¿Es este evento un evento de teclado? (sólo lectura)
isMouse:
var isMouse : boolean
¿Es este evento un evento de ratón? (sólo lectura)
107. CLASE EVENT (I)
Tipos de teclas modificadores que pueden estar activos durante un proceso de pulsación de tecla.
Los eventos pueden corresponder a entradas de usuario (teclas presionadas, acción de ratón) o bien ser distribuciones (layers) de unityGUI o eventos de renderizado. Asi como OnGUI es potencialmente llamado multiples veces por frame. Event.current corresponde al actual evento dentro de la llamada a OnGUI.
VARIABLES:
type:
var type : EventType
Variable que indica el tipo de evento. Es de tipo EventType, que es una enumeración que permite los siguientes valores:
MouseDown Un botón del ratón ha sido presionado.
MouseUp Un botón del ratón ha sido liberado.
MouseMove El ratón se ha movido (sólo en vista de edición).
MouseDrag El ratón fue arrastrado.
KeyDown Una tecla del teclado fue presionada.
KeyUp Una tecla del teclado fue liberada.
ScrollWheel La rueda del ratón se movió.
Repaint Un evento de repintado. Se envía uno cada frame.
Layout Un evento de distribución.
DragUpdated Solo en editor: operación de drag & drop actualizada.
DragPerform Sólo en editor: operación de drag & drop realizada.
DragExited Sólo en editor: operacion de drag & drop finalizada.
Ignore el evento debe ser ignorado.
Used Evento ya procesado.
ValidateCommand Valida un comando especial (p.ej. copy & paste)
ExecuteCommand Ejecuta un comando especial (p.ej. copy & paste)
ContextClick El usuario ha hecho click con el botón derecho.
Pongamos un breve ejemplo:
function OnGUI () {
Debug.Log("Current event detected: " + Event.current.type);
}
Este script meramente imprime el evento que está teniendo lugar cada frame. Prueba, tras pulsar play, a hacer click con diferentes botones del ratón, pulsa distintas teclas, mueve el ratón, etc. Luego detén el reproductor y haz click sobre el último mensaje de la consola para que te aparezca el pop up. Verás una lista enorme de eventos que han tenido lugar, la mayoría de repintado y distribución, pero entre ellos estarán los que hayas provocado durante ese tiempo.
mousePosition:
var mousePosition : Vector2
La posición del ratón. Variable usada en los eventos EventType.MouseMove y EventType.MouseDrag.
delta:
var delta : Vector2
El movimiento relativo del ratón comparado con el último evento.
button:
var button : int
Qué botón del ratón ha sido presionado.
Apliquemos un ejemplo:
function OnGUI() {
var miEvento : Event = Event.current;
if(miEvento.button == 0 && miEvento.isMouse){
Debug.Log("Botón izquierdo");
} else if(miEvento.button == 1) {
Debug.Log("Botón derecho");
} else if (miEvento.button == 2) {
Debug.Log("Botón del centro");
}
}
Creamos primero una instancia de la clase Event, que contendrá el evento actual. Si dicho evento es un evento de ratón (isMouse, que estudiaremos de aquí a un momento) y button vale cero (esto es, button vale cero pese a haber un evento de ratón, ya que si no hay evento de ratón button también vale cero, no sé si me estoy explicando)
se imprime un mensaje, y así sucesivamente (con valores de button en uno y dos no hace falta descartar la posibilidad de que no se esté produciendo un evento de ratón por lo anteriormente explicado.
modifiers:
var modifiers : EventModifiers
Qué tecla modificadora está siendo pulsada( ahift, ctrl, alt...)
function OnGUI() {
var miEvento : Event = Event.current;
Debug.Log(miEvento.modifiers);
}
Probad a pulsar las teclas modificadoras y las veréis impresas, a diferencia de las que no tienen esa condición.
106. CLASE DEBUG
Clase que contiene métodos para desbugear con facilidad mientras se desarrolla un juego:
VARIABLES DE CLASE:
isDebugBuild:
static var isDebugBuild : boolean
En el diálogo Build Settings, que podemos encontrar en el menú=>File, hay un check box llamado “Development Build”. Si dicho check box está marcado, entonces isDebugBuild será true.
FUNCIONES DE CLASE:
DrawLine:
static function DrawLine (start : Vector3, end : Vector3, color : Color = Color.white, duration : float = 0.0f) : void
Dibuja una lidea desde el punto que le pasemos como parámetro start hasta el establecido como end con el color que le establezcamos como tercer parámetro y durante un tiempo fijado en duration. Si la duración es 0 entonces la linea es dibujada un frame.
La linea será dibujada en la vista de escena del editor. Si en la ventana Game está habilitada la opcion Gizmos, también se mostrará ahí la línea.
Un pequeño ejemplo:
function Update () {
Debug.DrawLine (Vector3.zero, transform.position, Color.red);
}
Estamos dibujando una línea que empezaría en el centro de la escena y que iría hasta el centro del objeto que tiene vinculado el script, esto es, la esfera. La línea sería de color rojo y se dibuja cada frame, coincidiendo con las veces que es llamada la función Update. Si queremos ver también la línea en la vista Game, recordemos activar el botón Gizmos.
DrawRay:
static function DrawRay (start : Vector3, dir : Vector3, color : Color = Color.white, duration : float = 0.0f) : void
Dibuja una línea desde start a start+dir con el color que especifiquemos por una duración de tiempo también establecida. Si duración es 0 entonces la línea es dibujada un frame.
Para ver las diferencias con la función anterior, lo mejor será realizar el mismo ejemplo con la nueva función. Así:
function Update () {
Debug.DrawRay (Vector3.zero, transform.position*10, Color.red);
}
Vemos que aquí el segundo parámetro no es el destino final del rayo, sino la dirección y distancia de éste. En este caso veremos una línea/rayo de 10 metros saliendo desde el centro de la escena.
Break:
static function Break () : void
Pausa el editor. Esto es útil cuando queremos comprobar ciertos valores en el inspector y no somos capaces de pausarlo manualmente.
Log:
static function Log (message : object) : void
Anota mensajes en la consola de Unity:
Debug.Log("Hola, mundo");
static function Log (message : object, context : Object) : void
Cuando seleccionas en mensaje en la consola se dibuja una conexión con el objeto contextual. Esto es muy útil si queremos saber qué errores ocurren en un objeto. Me explico. Escribimos esto en MiPrimerScript (que recordemos que tenemos vinculado a la esfera):
Debug.Log ("Hola, mundo", gameObject);
Al darle al play, tal como podemos suponer, aparece el mensaje impreso en la consola. Pero en este caso, si hacemos click sobre ese mensaje, observaremos que en la jerarquia automáticamente se nos selecciona la esfera durante unos segundos.
LogError:
static function LogError (message : object) : void
Una variable de Debug.Log que anota un mensaje de error en la consola (en color rojo)
Debug.LogError("Esto es un error");
static function LogError (message : object, context : Object) : void
Variante similar a la que tratábamos antes para Log.
LogWarning:
static function LogWarning (message : object) : void
Una variante de Debug.Log que muestra un mensaje de aviso en la pantalla (en color amarillo)
static function LogWarning (message : object, context : Object) : void
Mensaje vinculado a un determinado objeto, como en los dos casos anteriores.
105. CLASE CONTROLLERCOLLIDERHIT
ControllerColliderHit es usado por CharacterController.OnControllerColliderHit para dar información detallada sobre la colisión y como trabajar con ella.
VARIABLES:
controller:
var controller : CharacterController
El controller que golpea el collider.
un simple ejemplo, para el cual con la esfera seleccionada vamos a menú=>Component=>Physics=>Character Controller, y reemplazamos la Sphere Collider. Luego escribimos el siguiente script:
function OnControllerColliderHit(colision : ControllerColliderHit) {
Debug.Log(colision.controller.name);
}
function FixedUpdate(){
collider.Move(Vector3(-8,0,0));
}
Poco que explicar. Movemos la esfera hacia el cubo (notad que sustituimos la función AddForce por Move, ya que ahora nuestra esfera tiene un character controller. Una vez impacta con el cubo, se imprime el nombre del controller (la esfera)
collider:
var collider : Collider
El collider que fue golpeado por el controller. Para verlo en un ejemplo sustituyamos "colision.controller.name" por "colision.collider.name".
rigidbody:
var rigidbody : Rigidbody
El rigidbody que fue golpeado por el controller. Es null si no se toca un rigidbody sino un collider estático.
gameObject:
var gameObject : GameObject
El game object que fue golpeado por el controller.
transform:
var transform : Transform
El transform que fue golpeado por el controller.
point:
var point : Vector3
El punto de impacto en coordenadas globales.
normal:
var normal : Vector3
El normal de la superficie con la que colisionamos en coordenadas globales.
moveDirection:
var moveDirection : Vector3
Aproximadamente la dirección desde el centro de la cápsula al punto que tocamos. Esto puede ser útil para encontrar una dirección razonable para aplicar fuerzas a rigidbodies golpeados.
Por poner un ejemplo muy básico:
function OnControllerColliderHit(colision : ControllerColliderHit) {
colision.rigidbody.AddForce(colision.moveDirection * 15);
Debug.Log(colision.moveDirection);
}
function FixedUpdate(){
collider.Move(Vector3(-2,0,0));
}
Cuando el cubo recibe el impacto de la esfera, a su vez al rigidbody vinculado al cubo le aplicamos una fuerza en la misma dirección del impacto, multiplicada por quince. Paralelamente imprimimos la dirección desde el centro de la cápsula de nuestro controller al punto de contacto.
moveLenght:
var moveLength : float
Indica lo lejos que el character controller ha viajado hasta golpear al collider. Note que esto puede ser diferente de lo que pasas a CharacterController.Move, porque todos los movimientos están constreñidos por colisiones.
104. CLASE COLLISION
Clase que obtiene diferente información de una colisión.
La información de la collision es pasada a los eventos Collider.OnCollisionEnter, Collider.OnCollisionStay y Collider.OnCollisionExit.
VARIABLES:
relativeVelocity:
Variable de sólo lectura que devuelve la velocidad lineal relativa de los dos objetos que colisionan.
Para realizar un ejemplo, recoloquemos antes la esfera en (2,0,0). Luego escribamos nuestro script:
function OnCollisionEnter(colision : Collision) {
var velCol: Vector3 = colision.relativeVelocity;
Debug.Log(velCol.magnitude);
}
function FixedUpdate(){
rigidbody.AddForce(Vector3(-4,0,0));
}
Expliquemos el script de abajo arriba. En la función FixedUpdate lo único que hacemos es aplicar una fuerza de cuatro unidades hacia la izquierda a la esfera, forzándola a colisionar con el cubo. En el momento en que la esfera topa con el cubo, los datos de la colisión son almacenados en el parámetro colision. Uno de dichos datos es, como estamos estudiando, la velocidad relativa a la que aquélla se produce, velocidad que almacenamos en la variable velCol, de tipo Vector3. Ya sólo nos queda imprimir la fuerza o longitud de dicho vector, que como recordaremos se hace a través de la variable magnitude.
Pulsamos play y observamos que la magnitud de la colisión es de algo menos de 4 (fruto de descontar el rozamiento y la resistencia respecto de la fuerza aplicada)
rigidbody:
var rigidbody : Rigidbody
Variable de sólo lectura que hace referencia al rigidbody que golpeamos. Es nulo si el objeto que golpeamos es un collider sin rigidbody vinculado.
Es fácil de ilustrar con un ejemplo:
function OnCollisionEnter(colision : Collision) {
if(colision.rigidbody){
Debug.Log("He topado con el rigidbody del objeto " + colision.rigidbody.name);
}
}
function FixedUpdate(){
rigidbody.AddForce(Vector3(-4,0,0));
}
No hay mucho que explicar. Si el collider con el que topa nuestra esfera tiene un rigidbody, se nos imprime un texto que además incluye el nombre del objeto al que dicho rigidbody pertenece.
collider:
var collider : Collider
El collider que golpeamos (sólo lectura).
Para determinar la parte concreta que golpeamos de cada collider deberemos iterar a través de los puntos de contacto con la propiedad contacts.
transform:
var transform : Transform
El transform del objeto que golpeamos (read only). Si chocamos contra un collider con un rigidbody, el transform será el vinculado al rigidbody. Si colisionamos contra un collider sin rigidbody, el transform será el vinculado al collider.
gameObject:
var gameObject : GameObject
Variable de sólo lectura que devuelve el objeto con el que chocamos.
contacts:
var contacts : ContactPoint[]
El punto de contacto generado por el engine de físicas.
Cada contacto implica un punto de contacto, un normal y dos colliders que colisionan (ver ContactPoint). A través de OnCollisionStay o OnCollisionEnter puedes siempre estar seguro de que el contacto tiene al menos un elemento.
ContactPoint es una estructura que tiene estas variables:
1) point: el punto de contacto. Por ejemplo:
function OnCollisionEnter(colision : Collision) {
if(colision.relativeVelocity.magnitude > 2){
print("Puntos de colision: " + colision.contacts.Length);
print("Primer punto de colision: " + colision.contacts[0].point);
}
}
function FixedUpdate(){
rigidbody.AddForce(Vector3(-8,0,0));
}
Una breve explicación del script: Como en el anterior aplicamos una fuerza a la esfera que la obliga a colisionar con el cubo. Si dicha colisión tiene una fuerza superior a 2 unidades se imprimen dos mensajes: uno que indica el número de colisiones que se ha producido y otro el punto exacto de la primera colisión. Si no hubiéramos establecido una fuerza mínima del contacto para que aparecieran los mensajes, el propio contacto de la esfera con el suelo habría disparado dichos mensajes. Pulsamos play y veremos uno de los mensajes, y si hacemos click sobre dicho mensaje para que nos aparezca el popup de la consola, encontraremos el segundo, tal como muestro en esta captura:
2) normal: El normal del punto de contacto.
3) thisCollider: El primer collider en contacto, o sea, el vinculado al script.
function OnCollisionEnter(colision : Collision) {
if (colision.relativeVelocity.magnitude > 2){
print("This collider is named: " + colision.contacts[0].thisCollider.name);
}
}
function FixedUpdate(){
rigidbody.AddForce(Vector3(-8,0,0));
}
En este sencillo script observamos que thisCollider se corresponde a la esfera.
4) otherCollider: El otro collider en contacto. Para comprobar que hace referencia al cubo, meramente sustituir en el script anterior thisCollider por otherCollider.
103. ESTRUCTURA BOUNDS
Como es fácil apreciar, Bounds no es una clase, sino una estructura. La diferencia, aunque a efectos prácticos una clase es lo mismo que una estructura, es más de tipo semántico. Esto es, cuando nos topamos con una estructura, se nos quiere informar de que la misma tiene un componente de complemento a una o varias clases que no suelen tener las clases en sí.
La estructura bounds representa una caja de bordes con los ejes alineados. También denominada AABB (para abreviar axis-aligned bounding box), es una caja alineada con los ejes de coordenadas globales que envuelve algún objeto.
Como la caja nunca rota respecto de los ejes, puede ser definida por su centro y extensiones, o alternativamente por mínimo y máximo. (center, extents, min y max, en inglés)
La estructura Bounds se usa en Collider.bounds, Mesh.bounds y Renderer.bounds.
VARIABLES:
center:
var center : Vector3
El centro de la caja.
size:
var size : Vector3
El tamaño total de la caja. Es siempre dos veces más grande que las extensiones (extents)
extents:
var extents : Vector3
Las extensiones de la caja. Es siempre la mitad del tamaño (size)
min:
var min : Vector3
El punto mínimo de la caja. Es siempre igual a center – extents.
max:
var max : Vector3
El punto máximo de la caja. Siempre es igual a center+extents.
FUNCIONES:
static function Bounds (center : Vector3, size : Vector3) : Bounds
Crea una nueva caja de bordes con un centro dado y un tamaño total. Las extensiones deben ser la mitad del tamaño dado.
SetMinMax:
function SetMinMax (min : Vector3, max : Vector3) : void
Establece los bordes en los valores mínimos y máximos de la caja. Usar esta función es más rápido que asignar min y max de manera separada.
Encapsulate:
function Encapsulate (point : Vector3) : void
function Encapsulate (bounds : Bounds) : void
Incrementa la caja para incluir el punto que se pasa como parámetro (1er prototipo) o para incluir la nueva caja (2º prototipo)
Expand:
function Expand (amount : float) : void
function Expand (amount : Vector3) : void
Expande la caja para incrementar su tamaño en una cantidad a lo largo de cada cara.
Intersects:
function Intersects (bounds : Bounds) : boolean
¿Hay alguna otra caja intersectando nuestra caja?
Contains:
function Contains (point : Vector3) : boolean
¿Está el punto point contenido en la caja?
sqrDistance:
function SqrDistance (point : Vector3) : float
El cuadrado de la distancia entre el punto point y la caja.
intersectRay:
function IntersectRay (ray : Ray) : boolean
¿El rayo ray intersecta esta caja?
Pongamos un ejemplo. Previamente ubicamos la esfera (que es el gameobject al que tenemos vinculado nuestro script) en la posicion (2,0,2), y le añadimos de nuevo un componente Rigidbody.
Ahora reeditamos MiPrimerScript así:
var rayo : Ray = new Ray (Vector3.zero, Vector3.forward);;
function Update () {
Debug.DrawRay (Vector3.zero, Vector3.forward * 999, Color.green);
var bordes : Bounds = transform.collider.bounds;
if (bordes.IntersectRay (rayo))
Debug.Log("La caja tocó el rayo");
}
function FixedUpdate() {
rigidbody.AddForce(-Vector3.right*6*Time.deltaTime);
}
Creamos primero un rayo que surge en el centro global de la escena y se prolonga a lo largo del eje z positivo (vulgarmente, hacia delante). Ya dentro de la función update dibujamos ese mismo rayo que ya tenemos descrito, para que visualmente podamos seguir lo que está pasando. Acto seguido creamos una instancia de la estructura Bounds que en un alarde de originalidad llamaremos bordes, y la inicializaremos con la caja de bordes del collider de nuestro gameobject (la caja que envuelve el collider, ojo, no confundir con el collider mismo. En este caso el collider tiene forma de escena y el Bounds de la esfera sigue teniendo forma de caja). Dejamos establecido que si la caja toca el rayo se mostrará un mensaje en pantalla, así que sólo nos queda darle movimiento a la esfera para que cuando intersecte el rayo (que aquí hemos dibujado a través de DrawRay, pero que podríamos haber dejado invisible) se muestre dicho mensaje.
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)
ENTRADAS
-
▼
2011
(127)
-
▼
octubre
(121)
- 116. ESTRUCTURA RAYCASTHIT
- 115. ESTRUCTURA RAY
- 114. CLASE RANDOM
- 113. ESTRUCTURA QUATERNION
- 112. CLASE PHYSICS (y II)
- 111. CLASE PHYSICS (I)
- 110. ESTRUCTURA MATHF (y III)
- 109. ESTRUCTURA MATHF (II)
- 108. ESTRUCTURA MATHF (I)
- 107. CLASE LIGHTMAPSETTINGS
- 106. CLASE GIZMOS
- 105. CLASE EVENT (y III)
- 104. CLASE EVENT (II)
- 107. CLASE EVENT (I)
- 106. CLASE DEBUG
- 105. CLASE CONTROLLERCOLLIDERHIT
- 104. CLASE COLLISION
- 103. ESTRUCTURA BOUNDS
- 102. CLASE INPUT (y IV)
- 101. CLASE INPUT (III)
- 100. CLASE INPUT (II)
- 99. CLASE INPUT (I)
- 98. CLASE TEXTURE2D (y II)
- 97. CLASE TEXTURE2D (I)
- 96. CLASE TEXTURE
- 95. CLASE GUILAYOUT (y IV)
- 94. CLASE GUILAYOUT (III)
- 93. CLASE GUILAYOUT (II)
- 92. CLASE GUILAYOUT (I)
- 91. CLASE GUI (y VIII)
- 90. CLASE GUI ( VII)
- 89. CLASE GUI (VI)
- 88. CLASE GUI (V)
- 87. CLASE GUI (IV)
- 86. CLASE GUI (III)
- 85. CLASE GUI ( II)
- 84. CLASE GUI (I)
- 83. CLASE GUITEXTURE
- 82. CLASE GUITEXT (y II)
- 81. CLASE GUITEXT (I)
- 80. CLASE GUIELEMENT
- 79. CLASE COMPONENT
- 78. CLASE PHYSICMATERIAL
- 77. CLASE SHADER
- 76. CLASE GAMEOBJECT (y VI)
- 75. CLASE GAMEOBJECT (V)
- 74. CLASE GAMEOBJECT (IV)
- 73. CLASE GAMEOBJECT (III)
- 72. CLASE GAMEOBJECT (II)
- 71. CLASE GAMEOBJECT (I)
- 70. CLASE MESH (y II)
- 69. CLASE MESH (I)
- 68. CLASE PARTICLEEMITTER (y III)
- 67. CLASE PARTICLEEMITTER (II)
- 66. CLASE PARTICLEEMITTER (I)
- 65. CLASE RENDERTEXTURE (y III)
- 64. CLASE RENDERTEXTURE (II)
- 63. CLASE RENDERTEXTURE (I)
- 62. CLASE CUBEMAP
- 61. CLASE MATERIAL (y III)
- 60. CLASE MATERIAL (II)
- 59. CLASE MATERIAL (I)
- 58. CLASE LIGHT (y III)
- 57. CLASE LIGHT (II)
- 56. CLASE LIGHT (I)
- 55. CLASE CAMERA (VI)
- 54. CLASE CAMERA (V)
- 53. CLASE CAMERA (IV)
- 52. CLASE CAMERA (III)
- 51. CLASE CAMERA (II)
- 50. CLASE CAMERA (I)
- 49. CLASE MONOBEHAVIOUR (y IX)
- 48. CLASE MONOBEHAVIOUR (VIII)
- 47. CLASE MONOBEHAVIOUR (VII)
- 46. CLASE MONOBEHAVIOUR (VI)
- 45. CLASE MONOBEHAVIOUR (V)
- 44. CLASE MONOBEHAVIOUR (IV)
- 43. CLASE MONOBEHAVIOUR (III)
- 42. CLASE MONOBEHAVIOUR (II)
- 41. CLASE MONOBEHAVIOUR (I)
- 40. CLASE BEHAVIOUR
- 39. CLASE CHARACTERJOINT
- 38. CLASE SPRINGJOINT
- 37. CLASE HINGEJOINT (y II)
- 36. CLASE HINGEJOINT (I)
- 35. CLASE JOINT (y II)
- 34. CLASE JOINT (I)
- 33. CLASE MESHFILTER
- 32. CLASE RENDERER (y II)
- 31. CLASE RENDERER (I)
- 30. CLASE CHARACTERCONTROLLER (y III)
- 29. CLASE CHARACTERCONTROLLER (II)
- 28. CLASE CHARACTERCONTROLLER (I)
- 27. CLASE MESHCOLLIDER
- 26. CLASE COLLIDER (II)
- 25. CLASE COLLIDER (I)
- 24. CLASE RIGIDBODY (y VIII)
- 23. CLASE RIGIDBODY (VII)
- 22. CLASE RIGIDBODY (VI)
- 21. CLASE RIGIDBODY (V)
-
▼
octubre
(121)