Third Person Controller en Unity

Third Person Controller en Unity

Third Person Controller

En este post aprenderemos a crear un Third Person Controller con Unity, desde cero.

Para realizar nuestro Controlador en tercera persona necesitaremos el Cinemachine. Este Package de Unity nos ofrece la solución para crear el movimiento interactivo de la cámara. Nos facilita mucho la creación del comportamiento avanzado de la cámara sin escribir código. Para instalar el package, nos dirigimos a la pestaña Window/Package Manager y buscamos Cinemachine.

Primero de todo vamos a crear nuestro jugador, nuestro player será una cápsula y tendrá como hijo un cubo para marcar la dirección y estará dentro de un Empty GameObject. Les quitaremos todas las colisiones. 

Configuración de Cinemachine

Seguimos creando desde Cinemachine la cámara que usaremos, “Free Look”. Al crear este objeto nos podemos fijar que ha aparecido un icono en nuestra cámara.

Lo que hará el «CM FreeLook» es ordenar a nuestra Main Camera todas las opciones por donde se puede mover. Al inicio del componente veremos dos apartados y asignaremos el Player al Follow y al Look At. Como podemos ver en nuestra escena, nuestra cámara sigue a nuestro player y apunta hacia él.

Para modificar desde nuestra cámara el comportamiento debemos ir al apartado de Orbits. Si no fijamos en nuestra escena podemos ver 3 órbitas distintas: Top, Middle, Bottom. Nuestra cámara se moverá por estas 3 órbitas dependiendo de donde este nuestro Mouse. Subiremos la velocidad del ratón y cambiaremos el «Binding Mode» a World Space.

Ajustaremos la altura y el radio de las órbitas a nuestro gusto.

Vamos a añadir a nuestro ThirdPersonController un CharacterController para darle movimiento al Player. Y creamos el script para el movimiento.

PlayerMovement.cs

Para explicar el movimiento debemos conocer el GetAxis(“Horizontal”) y el GetAxis (“Vertical”) detectan cuando estamos pulsando A, D y flecha izquierda y derecha para GetAxis(“Horizontal”), devolviéndonos un -1 para la izquierda y un +1 para la derecha. Y W y S y las flechitas del teclado de arriba y abajo para el GetAxis(“Vertical”), también devolviendo un -1 y un +1. Una vez sabemos esto vamos a crear dos variables para la X y la Z en el Update.

A continuación añadiremos la dirección, declararemos un Vector3 llamado dirección que cogerá los valores antes creados. Para no movernos más rápido pulsando las dos teclas a la vez, normalizaremos el Vector. 

A continuación, vamos a generar dos variables, para el Character Controller y para la velocidad, asignándola en el Start.

 

 

Vamos a escribir una condición, para que nos detecte el movimiento, es decir, cuando estemos pulsando una tecla del GetAxis. Escribiendo si el valor del Vector es mayor de 0.1, ya que cuando no pulsamos siempre será 0. Y añadimos el movimiento con el CharacterController antes declarado.

Como podemos ver con este código nuestro personaje ya se mueve, pero no respeta hacia donde estamos mirando. Para corregir esto primero de todo necesitamos saber cuanto deberá rotar nuestro personaje en el eje Y cogiendo la dirección, crearemos un float que será el ángulo hacia donde apunta dentro de la condición. Usando una función de la clase Mathf, llamada Atan2 nos devuelve el ángulo entre el eje X empezando desde 0 y terminando en x, y, y nos devuelve el float en radiantes así que lo pasaremos a grados también. 

A continuación sumaremos este ángulo a la rotación de la cámara (todo dentro de la condición). 

Si comprobamos el movimiento de nuestro jugador ya apunta hacia la dirección de la cámara, pero lo hace de forma brusca, así que vamos a suavizar esta rotación.

Crearemos 3 variables para suavizar: 

Usaremos una funciona matemática de Mathf llamada SmoothDampAngle que nos pide:

Nuestro personaje ya rota de la manera correcta así que ahora solo falta que avance hacia esa dirección. Crearemos un Vector3 llamado moveDir y debemos pasar una rotación a Vector3, para hacer esto simplemente multiplicamos por Vector3.forward.

Con el script ya terminado comprobamos el movimiento y vemos que funciona todo perfectamente. En este punto nuestro personaje ya se moverá correctamente y con completa libertad, solo falta añadir la gravedad, ya que hemos desarrollado el player con CharacterController y no con rigidBody. Vamos al script del player y añadiremos dos nuevas variables:

Vamos a escribir en el Update que la velocidad en Y, es decir la dirección de Y, es igual a esta velocidad multiplicada por la gravedad por el tiempo. Y se lo añadiremos al Character Controller como hemos hecho antes, pero multiplicando otra vez por el tiempo, ya que la gravedad se multiplica por tiempo al cuadrado.

Si nos fijamos en la variable de velocidad en Y, vemos que cada segundo se reduce en 9,81 y si nos cayésemos de cualquier sitio lo haríamos a muchísima velocidad. Para corregir este problema, necesitaremos comprobar el suelo. Para comprobar que estamos tocando el suelo crearemos un objeto empty en los pies del jugador.

En este punto generaremos una pequeña esfera que nos detectara si el objeto con el cual colisiona tiene una LayerMask determinada. Vamos a verlo a continuación, crearemos 4 variables.

En el Update haremos la línea para que nos detecte capa si la esfera la colisiona y nos cambie el valor de la booleana a true. Si la esfera collisiona con la Capa “floorMask” y la velocidad en Y es negativa, le pondremos el valor de Y a -2 (puede variar dependiendo de nuestro player).

Para crear y añadir la capa debemos dirigirnos al inspector de Unity en Layer/Default/Add Layer, añadimos la nueva capa y se la seleccionamos a todos los objetos de nuestra escena.

Salto

Ahora ya solo nos quedaría añadir el salto a nuestro movimiento.

Para implementar el salto vamos a usar otro de los Inputs que nos proporciona Unity. Y le decimos que nos haga el salto si pulsamos la tecla de saltar y si está en el suelo. Usaremos una fórmula física para saltar la distancia que queramos: raíz cuadrada de la altura (3) que queremos saltar *-2 *gravedad.

  

Una vez aplicada la gravedad y el salto, si nos fijamos cuando pasamos por delante de un objeto, la cámara se posiciona dentro de este. Para corregir este error, Cinemachine nos da herramientas para detectar las colisiones y así ajustar la cámara. En este caso vamos a la opción de Add Extensión y añadimos CinemachineCollider.

Ya tenemos nuestro Third Person Controller completo, quedaría algo así:

public class PlayerMovement: MonoBehaviour
{
    public CharacterController cc;
    private float speed = 12f;

    public float Gravity = -9.81f;
    public Vector3 velocity;

    public Transform groundCheck;
    public float groundDistance = 0.4f;
    public LayerMask floorMask;
    bool isGrounded;

    public float turnSmoothTime = 0.1f;
    float turnSmoothVelocity;

    public Transform cam;

    private void Start()
    {
        cc = GetComponent<CharacterController>();
    }
    void Update()
    {
        //Movimiento
        float horizontal = Input.GetAxisRaw("Horizontal");
        float vertical = Input.GetAxisRaw("Vertical");

        Vector3 direction = new Vector3(horizontal, 0, vertical).normalized;

        if (direction.magnitude >= 0.1f)
        {
            float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + cam.eulerAngles.y;
            float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);

            transform.rotation = Quaternion.Euler(0, angle, 0);

            Vector3 moveDir = Quaternion.Euler(0, targetAngle, 0) * Vector3.forward;
            cc.Move(moveDir.normalized * speed * Time.deltaTime);
        }

        //Detección de suelo
        isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, floorMask);
        //Gravedad
        velocity.y += Gravity * Time.deltaTime;
        if (isGrounded && velocity.y < 0)
        {
            velocity.y = -1.86f;
        }
        cc.Move(velocity * Time.deltaTime);
        //Salto
        if (Input.GetButtonDown("Jump") && isGrounded)
        {
            velocity.y = Mathf.Sqrt(3 * -2 * Gravity);
        }

    }
    
}

Si os ha sido de utilidad el Third Person Controller, podéis echar un vistazo al First Person Controller pulsando aquí.

Escribe un comentario