Está en la página 1de 37

Parte 2 Fundamentos Unity: Gameplay,

mover, rotar y animar un personaje 3d.


Yone Moreno Jiménez Follow
Dec 17, 2017 · 12 min read

Parte 1: https://medium.com/@yonem9/fundamentos-unity-gameplay-
parte-1-teor%C3%ADa-dise%C3%B1o-y-el-editor-de-unity-5f8713e9b0e6

Índice (los enlaces van al documentro Drive original donde escribí este
artículo)

Créditos 1

Recursos 1

Mover el personaje 1
Rotar el personaje 13

Animar el personaje 21

Créditos
Curso original creado por Joshua Kinney traducido por Yone Moreno
Jiménez.

Recursos
Materiales a usar durante el curso (animaciones y modelos 3d, más la
escena/mapa del juego) son 1.5GB comprimido en .zip) Los he subido para
que estén disponible públicamente en : Enlace

Mover el personaje
En la anterior parte de este curso empezamos viendo teoría sobre diseño.
Luego continuamos haciendo un esbozo del script del jugador, Player,
donde listamos las variables y métodos que debería tener:
Pero el problema es que no es flexible y sería engorroso de cambiar. Así que
lo que vamos a hacer es separar cada método en su propio script, por
ejemplo haremos un script nuevo:
Y lo llamamos PlayerMovement:

Queremos mover al jugador tanto por teclado como por mando, abrimos el
script en el editor:

Primero queremos ser capaces de variar la velocidad de movimiento en


Unity, para ello creamos la variable pública:
Luego queremos detectar lo que pulsa el jugador cada vez que se refresca la
imagen en pantalla, ello se consigue con la función Update() la cual se
llama cada vez que se redibuja la imagen:

A continuación queremos guardar los valores que el usuario introduce


cuando pulsa awsd o los joysticks. Antes necesitamos saber dónde configura
Unity los controles del jugador, para ello volvemos a unity, en el menú
superior vamos a Edit, Project Settings, Input:
A la derecha se nos muestran todos los ejes disponibles en juego:
Entonces volviendo al código, queremos hacer lo siguiente, dentro del
update:

Escribimos:

float lh = Input.GetAxis(“Horizontal”);

La explicación, es que al pulsar la a obtenemos un -1 y al pulsar la d un +1,


entonces al guardar esos valores en una variable lh, podremos controlar el
movimiento del personaje.

Además si pulsamos rápidamente la tecla, nos devolverá un valor entre 0 y


1, o 0 y -1, por tanto eso nos ayudará a regular la velocidad del personaje.

Lo mismo hacemos:
Para el eje vertical, es decir la w d junto al joystick arriba abajo.

A continuación queremos calcular el punto de destino del personaje, para


ello usamos un tipo de datos llamado Vector3, que es usado para almacenar
las tres coordenadas de un espacio 3d:

Para ello creamos:

Private Vector3 moveInput;


Después calculamos el punto de destino del personaje así:

Dentro del Update() escribimos:

moveInput = new Vector3(lh, 0f, lv);

Que significa: asignamos a moveInput un nuevo vector de coordenadas,


donde de izquierda a derecha, es decir, en el eje x, nos movemos en función
de lo que quiera el jugador, ya que hemos guardado el eje horizontal en lh.

En el eje y, es decir de arriba hacia abajo, nos movemos 0f, porque no


queremos que el jugador salte.

Por último, en el eje z es decir desde adelante hacia atrás queremos que se
mueva lo que el jugador pida que hemos almacenado en lv.
Ahora lo que nos gustaría hacer es:

Es decir, mover realmente al personaje en la dirección que diga el jugador, a


la velocidad que le de el jugador, y además que el personaje mire hacia
donde se mueve.

Por tanto en la parte de variables pondremos una nueva:


Private Vector3 moveVelocity;

Que nos será de utilidad cuando movamos realmente al personaje.

Luego dentro del Update()

moveVelocity = transform.forward * moveSpeed;

Expresamos que queremos que el personaje se mueva hacia adelante con


una cierta velocidad, y eso lo almacenamos en moveVelocity.

Ahora, como queremos mover al personaje realmente, usaremos la física, el


rigidbody que le pusimos al personaje en la primera lección.

Puesto que nos interesa que el movimiento sea fluido, es decir, que se
mueva el personaje cada pocos milisegundos independientemente de lo
potente que sea el dispositivo de juego, usaremos una función llamada
FixedUpdate()
En concreto FixedUpdate() es una función que se llama cada 20ms.

Primero, ya que usaremos la física, el rigidbody, creamos una variable:

Private Rigidbody rb;

Y dentro del FixedUpdate():

rb.velocity = moveVelocity;

Con lo cual logramos que cada 20 ms el personaje sea empujado por las
físicas en la dirección de moveVelocity.
Una cuestión que no hemos tenido en cuenta en el Update():

Añadimos * moveInput.sqrMagnitude; a moveVelocity.

La razón es que antes simplemente estábamos usando una velocidad fija,


que es moveSpeed, y una dirección fija, que es transform.forward; pero nos
interesa que el jugador de hecho interactúe poniendo él la dirección y
velocidad, para ello escribimos moveInput.sqrMagnitude. Además
sqrMagnitude nos devuelve la magnitud del vector al cuadrado es decir:

moveInput(1.0f, 0f, 2.0f) -> moveInput.sqrMagnitude = x * x + y * y + z *


z=

1.0 * 1.0 + 0.0 * 0.0 + 2.0 * 2.0 = 5

Nos interesa hacer sqrMagnitude, porque queremos que moveVelocity sea


un número, una unidad, no un vector o dirección. Más info.
A continuación clicamos en el jugador y le añadimos el script
PlayerMovement:

Escribimos en la moveSpeed 10

Y nos da un error:
NullReferenceException

Significa que algo en nuestro script que no ha sido asignado, hemos


intentado usarlo. Significa que algo falta. Entonces, si clicamos dos veces en
el error, nos lleva al editor, a la línea donde se causó:

En este caso lo que ocurre es que no le hemos dado un rigidbody con el que
trabajar, es decir, si existe la variable rb de tipo RigidBody, pero está vacía.

Así que necesitamos obtener el componente rigidbody del personaje:


Para ello en Start() escribimos:

rb = GetComponent<RigidBody>();

Con ello expresamos: coge el componente del tipo RigidBody del objeto
actual (el personaje) y guárdalo en la variable rb.

Ya con ello el error desaparece, y si le damos al Play en Unity:


Moveremos al personaje.

Aunque la cuestión aquí es que el personaje sólo se mueve hacia delante. Es


cierto que lo podemos girar, pero no podemos moverlo en otras direcciones.

Rotar el personaje
Hasta ahora hemos conseguido mover al personaje mediante el control del
jugador.

El primer reto va a ser ¿ cómo hacemos que la rotación del personaje se


relacione con la cámara?

Tal y como está la cámara ahora, en perspectiva de arriba hacia abajo, el


vector hacia adelante son unos 45 grados en dirección al puente:
Si pulsamos hacia adelante, la w o el joystick se mueve el personaje hacia el
puente:
Lo que nos gustaría hacer es que al girar el joystick o al apretar otras teclas
el personaje mirase y fuese en esa dirección.

Lo primero es editar el script PlayerMovement que escribimos en el


apartado anterior, y añadir una variable para recopilar información de la
cámara:

Private Camera mainCamera;

Luego para obtener el componente que es la cámara, en el start()


mainCamera = Camera.main;

Está frase es una versión abreviada, sin tener que usar el GetComponent… y
sirve porque en Unity la Main Camera tiene el tag MainCamera:

Después capturamos la dirección en frente de la cámara así, ya que


recordemos que nos interesa rotar al personaje en función la vista que nos
muestra la cámara:
Vector3 cameraForward = mainCamera.transform.forward;

Con lo anterior estamos hallando la dirección en el eje z de la cámara, es


decir qué está mirando la cámara hacia delante y lo guardamos en la
variable cameraForward.

Además, pondremos que el eje y de la cameraForward sea 0 porque si no, al


jugador mover el joystick, el personaje tendería a ir hacia la cámara, o sea,
salta, y no queremos eso:

Ahora hablaremos de la rotación en sí. Unity nos ofrece un tipo de datos


llamado Quaternion, con el que se manejan la rotaciones.

La razón por la que se usa este tipo de datos, es que existe un concepto
llamado en español bloqueo del cardán y en inglés gimbal lock, significa
que cuando dos ejes de los tres usados para rotar se alinean, el objeto pierde
un grado de libertad restringiéndoe sus movimientos.

Ejemplo de bloqueo del cardán, los movimientos mediante el eje azul y el


verde tendrian igual efecto, perdiéndose un grado de libertad. Fuente

Para empezar con la rotación:


Quaternion cameraRelativeRotation =
Quaternion.FromToRotation(Vector3.forward, cameraForward);

Con esa frase expresamos: nos creamos una variable de tipo Quaternion
llamada cameraRelativeRotation, a la cual le asignamos el resultado de la
llamada a la función Quaternion.FromToRotation() la cual usa como primer
parámetro la posición actual, y como segundo la posición hacia la que
queremos rotar, por ello se usa en los paréntesis (Vector3.forward,
cameraForward);

Más info.

Ahora lo que queremos es hacer que el personaje mire hacia donde le


decimos mediante teclado/joystick en relación con lo que ve la cámara.
Vector3 lookToward = cameraRelativeRotation * moveInput;

En la frase expresamos: creamos una variable de tipo Vector3 llamada


lookToward, a la cual le asignamos la cameraRelativeRotation, es decir el
caminito que ha de seguir el personaje desde el frente hacia la posición
final, * moveInput, o sea, lo que el jugador pulsa.

A partir de aquí queremos hacer que rote de verdad. Para ello vamos a
poner la condición de que rote sólo si el jugador está dándole velocidad al
personaje:

A partir de aquí logramos calcular la dirección la cual debería estar mirando


el personaje así. La idea es crear un rayo desde la posición del personaje,
hacia donde tiene que moverse

Más info en español del Ray.


Ray lookRay = new Ray(transform.position, lookToward);

Es decir, creamos un rayo, tipo Ray, llamado lookRay, que parte desde la
posición del objeto actual (el personaje), ello se expresa con
transform.position, y termina el rayo en la posición que nos diga la cámara,
mediante lookToward.

Después hacemos la rotación real:

transform.LookAt(lookRay.GetPoint(1));

Lo que expresa la anterior frase es que el objeto actual (el personaje) mire
hacia un punto que está a un metro por delante del inicio del rayo llamado
lookRay. LookAt() es una función que nos ofrece Unity para rotar la
posición del objeto de forma que mire hacia el punto que le decimos: Más
Info
De forma que con lo anterior ya podemos movernos y rotar al personaje:

Además en la física del jugador vamos a cambiar:


Restringiremos la rotación en el eje y, para que el jugador no se caiga
cuando se golpee.

Y le bajamos un poco la velocidad de movimiento a 6 porque va demasiado


rápido:

Hasta aquí hemos logrado ver y rotar al personaje.

Animar el personaje
En realidad ya hemos configurado nuestro personaje, en la lección 1, para
que tenga los estados y animaciones necesarias, para hacer que esté ocioso,
camine y corra:
Pulsamos en el personaje y clicamos en la pestaña de Animator:

Dentro se observan los estados:


En la lección uno habíamos añadido un blend tree o árbol de combinación y
puesto un parámetro llamado blendSpeed.
Cuya misión es alternar entre la animación de ocioso, caminar y correr. El
comportamiento que queremos es que si a penas pulsamos las teclas o el
joystick, el personaje camine, pero si las pulsamos un rato, el personaje
corra, y si está parado se ejecute la animación de ocioso.

Entonces volvemos al código, al script PlayerMovement. Lo primero que


hacemos es crear una nueva variable:
Private Animator anim;

Donde guardaremos la referencia al Animator del objeto actual, el


personaje.

Luego necesitamos obtener el componente en sí:

anim = GetComponent<Animator>();

Luego dentro del FixedUpdate() recordemos que es la función que Unity


llama cada 20 ms e interesa para tratar las físicas y animaciones de forma
fluida independientemente de lo potente que sea el dispositivo de juego,
escribimos:
Para programar cómo tiene que cambiar el parámetro que definimos en la
lección 1 en el Animator, llamado blendSpeed, usamos:

anim.SetFloat(“blendSpeed”, rb.velocity.magnitude);

Estamos expresando que queremos usar algo dentro de nuestro Animator


que hemos guardado llamándolo anim.

Ese algo es un número decimal, por eso se usa SetFloat().

El primer argumento de la función es el nombre del parámetro dentro del


animator, que es “blendSpeed”.

El segundo argumento es lo que ponemos como valor al parámetro.

En nuestro caso recordemos que si presionas por ejemplo la a/s a la vez, es


decir hacemos que el personaje se mueva hacia abajo a la izquierda, lh, es
decir en el eje horizontal tendríamos un valor de -1 y en el eje vertical, lv,
otro -1.

Además recordemos que los valores del parámetro blendSpeed son:

Positivos, de 0 a 8. Por tanto necesitamos obtener siempre valores positivos.


Para ello usamos rb.velocity.magnitude ya que magnitude siempre nos
devuelve un valor positivo.

Ahora necesitamos llamar a la función que acabamos de crear, la podemos


poner al final del Update():
Ya con lo anterior logramos que el personaje camine y corra:

Así que en está lección hemos aprendido a mover, rotar y animar un


personaje 3d.

Learning Programming Tech Technology Design

Discover Medium Make Medium yours Become a member


Welcome to a place where words matter. Follow all the topics you care about, and Get unlimited access to the best stories on
On Medium, smart voices and original we’ll deliver the best stories for you to your Medium — and support writers while
ideas take center stage - with no ads in homepage and inbox. Explore you’re at it. Just $5/month. Upgrade
sight. Watch

About Help Legal

También podría gustarte