30. CLASE CHARACTERCONTROLLER (y III)
FUNCIONES:
Move:
function Move (motion : Vector3) : CollisionFlags
Esta función mueve un character controller en la dirección y velocidad establecida por el parámetro de tipo vector tres. Dicho movimiento sólo será restringido por las colisiones que sufra el character.
Empecemos por un ejemplo básico. Eliminamos el script vinculado al cubo, y acto seguido modificamos el script vinculado a la esfera, para que quede así:
private var miCharCol : CharacterController;
miCharCol = GetComponent(CharacterController);
function Update() {
miCharCol.Move(Vector3(1 * Time.deltaTime ,0,0));
}
No tiene mucho misterio. Almacenamos el componente character controller de nuestro gameobject en una variable (que declaramos como privada para que no sea accesible desde el inspector), y acto seguido le damos un movimiento de una unidad por segundo a la derecha. Pulsando el play efectivamente la esfera se desplaza hasta que topa con el cubo.
El collider del cubo en este caso detiene el avance de la esfera, porque lo intercepta de pleno. Pero si al cubo lo ubicamos en position.Z= 0.8 y volvemos a darle al play, observamos que la esfera no detiene su avance. Choca y se desplaza de manera acorde a la colisión, pero acto seguido continúa avanzando hacia la derecha.
La función devuelve una variable de tipo collisionFlags, que estudiamos hace un par de capítulos, y que aporta información sobre la ubicación de las colisiones que ha sufrido el character controller. Con esa información, podemos alterar el comportamiento de nuestro character controller cuando sufra una colisión en una zona determinada de su cápsula.
Ampliamos el script anterior, para que quede así:
private var miCharCol : CharacterController;
miCharCol = GetComponent(CharacterController);
private var direccion : Vector3 = Vector3.right;
function Update() {
var misGolpes : CollisionFlags = miCharCol.Move(direccion * Time.deltaTime);
if(misGolpes == CollisionFlags.Sides)
{
direccion = Vector3(0,0,-1);
}
}
La esfera empieza su desplazamiento hacia la derecha (que es la dirección inicial que se le asigna a la función Move), hasta que colisiona con el cubo. Al hacerlo, nuestro condicional "if" detecta si la colisión se ha producido en uno de los laterales de la cápsula de nuestro character controller (CollisionFlags.Sides) y, para ese caso, se le pasa un nuevo vector3 a la dirección de la esfera.
SimpleMove:
function SimpleMove (speed : Vector3) : boolean
Podríamos deducir que esta función es similar a la anterior, y así es, pero con algunas peculiaridades. Por ejemplo, si a nuestra esfera le asignamos el siguiente script...
function Update() {
var miCharCol : CharacterController = GetComponent(CharacterController);
miCharCol.SimpleMove(Vector3(1 * Time.deltaTime, 0,0));
}
...podríamos esperar que la esfera se moviera hacia la derecha, pero se da el caso de que a la que presionamos play la esfera atraviesa el suelo y cae.
Esto es porque esta función automáticamente le asigna gravedad al character controller que la llama. Por otro lado, esta función no devuelve información sobre el lugar de contacto en que se ha producido las colisiones.
Y con esto acabamos una nueva clase.
Adiós.
29. CLASE CHARACTERCONTROLLER (II)
radius:
var radius : float
El radio de la cápsula del character controller.
height:
var height : float
La altura de la cápsula del character controller.
center:
var center : Vector3
El centro de la cápsula del character relativo a la posición del transform.
slopeLimit:
var slopeLimit : float
El límite de pendiente en grados por el que puede ascender nuestro character controller.
Vamos a probar esta variable. Sigue estos pasos:
1.- Seleccionamos el cubo y lo desplazamos a la derecha (transform.x = 3, por
ejemplo)
2.- Vamos al menú=>GameObject=>create other=>Cube.
3.- En el apartado transform, le damos al nuevo cube estos valores:
position = 0,2,0
rotation = 0,0,315
scale = 0.2,7,1
Nos debería haber quedado algo así:

Vale, ahora tenemos una pasarela con una inclinación de 45 grados (360-315), por lo tanto, que nuestra esfera la pueda subir o no depende del valor que le demos a slopeLimit. Así, si tecleamos:
function Update () {
var controller : CharacterController = GetComponent(CharacterController);
controller.slopeLimit = 46.0;
controller.Move(Vector3(1,0,0));
}
Nuestra esfera sí ascenderá por la rampa, ya que el grado de inclinación de esta es inferior al que puede asumir nuestro character controller. Pero le asignamos a slopeLimit el valor 45.0. observaremos que ya la esfera se niega a subir.
stepOffset:
var stepOffset : float
Los límites de altura que el character controller podrá superar, fijados en metros.(no podrá por ejemplo subir una escalera si cada escalón mide más de ese límite)
Para trabajar con un ejemplo, vamos a seleccionar el gameobject que nos sirvió como rampa en el ejemplo anterior. Le establecemos estos valores:
position: 0,0,0
rotation: 0,0,90
scale: 0.6,3,1
Por otro lado, a nuestro cubo le vamos a aumentar momentáneamente la altura (scale.y = 4).
Y tecleamos el siguiente código para nuestra esfera:
function Update () {
var controller : CharacterController = GetComponent(CharacterController);
controller.stepOffset = 0.3;
controller.Move(Vector3(1,0,0));
}
Tomemos nota de que la antigua rampa tiene una altura de 0.6. En cambio, a nuestro character controller le hemos limitado la capacidad de superar alturas mayores de 0.3, por lo que cuando le demos al play...la esfera topará con la rampa. En cambio, si variamos el valor de stepOffset y lo colocamos, por ejemplo, a 0.9, la esfera no tendrá problemas en superar la rampa, aunque tras hacerlo topará con el cubo.
Por experiencia personal, las mediciones de esta variable no siempre resulta exactas, ya que no todos los gameobjects se asientan completamente y de manera exacta sobre el suelo, o éste presenta desniveles. Para evitar este tipo de inexactitudes es necesario probar el comportamiento de los objetos y modificar stepOffsset en consecuencia, hasta dar con el comportamiento adecuado.
Borramos la rampa y devolvemos al cubo a sus dimensiones habituales y a su posición 0,0,0.
detectCollisions:
var detectCollisions : boolean
Determina si otros rigidbodies o character controllers colisionan con nuestro character Controller (por defecto esto está siempre habilitado).
Esta variable no afecta a las colisiones que nuestro character controller sufre cuando se mueve, sino las que sufre a raíz del movimiento de otros character controllers o colliders, y en concreto a si esos colliders o character controllers entrantes deben ser bloqueados por nuestro controller.
Para este ejemplo tenemos que escribir dos scripts. Abrimos MiPrimerScript, que deberíamos tener vinculado a nuestra esfera, y tecleamos:
function Update () {
var controller : CharacterController = GetComponent(CharacterController);
controller.detectCollisions = false;
}
Aquí meramente le decimos a nuestro character controller que no queremos que bloquee los colliders entrantes. Y ahora abrimos MiSegundoScript y escribimos:
function FixedUpdate() {
rigidbody.AddForce(-10,0,0);
}
Le asignamos este segundo script al cubo, de tal forma que se desplazará hacia la izquierda, hasta colisionar con la esfera. Es preferible colocar la escena en vista superior (eje Y del gizmo). Le damos al play.
Y tal como era de esperar, nuestra esfera no bloquea al cubo. Eso sí, si lo hubiéramos hecho al revés (mover la esfera hacia el cubo) aunque la variable detectCollisions estuviera en false, se produciría la colisión y el consiguiente bloqueo.
Y en la próxima lección vamos a por las funciones de esta clase.
28. CLASE CHARACTERCONTROLLER (I)

Un character Controller nos permite hacer fácilmente movimientos limitados por colisiones sin tener que lidiar con un rigidbody.
Comprobémoslo empíricamente, siguiendo estos pasos:
1.- Le borramos a la esfera el script que tiene vinculado.
2.- Le eliminamos a la esfera su componente rigidbody (botón derecho del ratón
situado sobre el nombre de dicho componente=> remove component)
3.- Con la esfera seleccionada, vamos al menú Component=>Physics=>Character
Controller. Nos saldrá un aviso preguntándonos si realmente queremos sustituir
el collider primitivo que por defecto trae la esfera por un Character
collider. Presionamos Replace.
4.- En Jerarquía seleccionamos suelo, y en el inspector desmarcamos el checkbox
situado junto a Mesh Collider.
5.- Play.
El cubo, afectado por las leyes físicas, atraviesa el suelo al que le hemos deshabillitado la malla. Sin embargo el cubo, que ahora está controlado por el character controller, no se ve afectado por las leyes físicas.
Antes de seguir, volvamos a habilitar la malla del suelo en su correspondiente checkbox.
Un character Controller no se ve afectado tampoco por fuerzas y se moverá sólo cuando llamemos a la función Move, específica de esta clase.
VARIABLES:
isGrounded:
var isGrounded : boolean
Booleano que devuelve true si nuestro character controller (controlador de personaje, podríamos traducirlo) estaba tocando el suelo durante el último movimiento.
velocity:
var velocity : Vector3
La velocidad relativa actual del character. La velocidad así retornada es la diferencia durante la última actualización entre la distancia antes y después de llamar a la función Move o SimpleMove, esto es, dónde estaba el último frame, o la última porción de frame o el último segundo el character antes de llamar a una de esas funciones y dónde estába despues, para que distancia partida por (tiempo, frame o fracción dada) sea igual a la velocidad por tiempo, frame o fracción dada.
Decimos que la velocidad es relativa porque no puede seguir movimientos del transform que suceden fuera del character controller (por ej un character emparentado bajo otro transform en movimiento, como por ejemplo un vehículo moviéndose)
collisionFlags:
var collisionFlags : CollisionFlags
Esta variable nos indicá qué parte de la cápsula (que es la forma que tiene un character controller) colisionó con el entorno durante la última llamada a CharacterController.Move.
Comprobamos que la variable es de tipo CollisionFlags, que tal como podemos sospechar es de tipo enumeración, permitiéndonos usar los siguientes valores:
None: No hay colisión.
Sides: Colisión en los lados.
Above: Colisión en la parte superior.
Bellow: Colisión en la parte inferior.
Así, un sistema para determinar si nuestro character controller ha topado con algo, y en qué parte de la cápsula, sería como sigue (no hace falta que tecleéis esto, es sólo a modo indicativo):
function Update () {
var controller : CharacterController = GetComponent(CharacterController);
controller.Move(Vector3(1,0,0));
if (controller.collisionFlags == CollisionFlags.None)
print("No hay colisiones");
if (controller.collisionFlags & CollisionFlags.Sides)
print("Colisión lateral, al menos");
if (controller.collisionFlags == CollisionFlags.Sides)
print("Sólo colisión lateral, ninguna de otro tipo");
if (controller.collisionFlags & CollisionFlags.Above)
print("Colisión superior, al menos");
if (controller.collisionFlags == CollisionFlags.Above)
print("Sólo colisión superior, ninguna de otro tipo");
if (controller.collisionFlags & CollisionFlags.Below)
print("Tocando tierra");
if (controller.collisionFlags == CollisionFlags.Below)
print("Sólo tocando tierra, nada más");
}
Le añadimos el script a la esfera (si no lo tenía ya vinculado) y le damos al play.
La esfera se mueve hacia la derecha, hasta que impacta con el cubo (démonos cuenta que la esfera ya no tiene un ridigbody, pero gracias al character controller sigue colisionando con otros colliders. Debajo de la ventana game aparece impresa la última colisión, pero no es la única. Si le hacemos click al mensaje impreso nos saldrá una lista de todas las colisiones que ha sufrido nuestra esfera hasta topar con el cubo.
La función GetComponent que hemos tecleado al inicio del script aún no la hemos estudiado, pero su cometido es bastante obvio: buscar el componente del gameobject que hace la llamada y que sea del tipo que le pasamos como parámetro, retornándolo. En este caso, nos sirve para inicializar la variable controller, con la que trabajaremos para montar un primitivo sistema de identificación de colisiones.
la función Print es similar a Debug.Log, y la función Move la estudiaremos durante el próximo capítulo.
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)
