Dándole peso a nuestro personaje: La Gravedad
¡Seguimos evolucionando nuestro sistema de movimiento! Un mundo 3D sin gravedad es como flotar en el espacio. Hasta ahora, con los scripts anteriores, si nuestro personaje caminaba por el borde de una rampa o un abismo, se quedaba caminando en línea recta por el aire como si fuera un fantasma. Hoy vamos a atarlo al suelo aplicando una fuerza gravitatoria realista y, sobre todo, controlable.
Entendiendo la gravedad en el Character Controller
Al no usar un Rigidbody, el Character Controller no cae por inercia propia; nosotros tenemos que decirle matemáticamente cómo hacerlo. Así es como lo logramos en este script:
- La propiedad isGrounded: Esta es una variable nativa del Character Controller que nos devuelve un true si el collider del personaje está pisando algo sólido, o un false si está en el aire. ¡Es la pieza fundamental para saber si debemos aplicar la caída libre!
- Aceleración de la caída: Si estamos en el aire, no caemos a una velocidad constante. La gravedad es una aceleración. Por eso, restamos continuamente el valor de la gravedad a nuestra velocidad en el eje vertical Y (
fallVelocity -= gravity * Time.deltaTime), haciendo que el personaje caiga cada vez más rápido cuanto más tiempo esté en el aire. - Pegados al suelo: Cuando pisamos tierra firme, no podemos poner la velocidad en Y a cero absoluto de golpe, o la variable
isGroundedparpadeará fallando las colisiones al bajar rampas. Por eso aplicamos una fuerza negativa continua e imperceptible (-gravity * Time.deltaTime) para mantener al personaje bien "pegado" al piso.
Copia el snippet que te dejo a continuación en tu clase PlayerController, asigna un valor a la variable Gravity en el Inspector de Unity (te recomiendo un valor fuerte, entre 9.8 y 20) y ¡observa cómo tu personaje por fin obedece a las leyes de la física!
Nota sobre versiones recientes de Unity
Este código utiliza el sistema de entrada clásico de Unity (Legacy Input Manager). Sigue siendo 100% funcional y excelente para aprender las bases en las versiones actuales de Unity. Solo asegúrate de ir a Edit > Project Settings > Player y comprobar que Active Input Handling está configurado en "Input Manager (Old)" o "Both".
Character Controller - Aplicando gravedad
Actualización del Character Controller para aplicarle gravedad.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour {
float horizontalMove;
float verticalMove;
private Vector3 playerInput;
public CharacterController player;
public float playerSpeed;
public float gravity;
public float fallVelocity;
public Camera mainCamera;
private Vector3 camForward;
private Vector3 camRight;
private Vector3 movePlayer;
// Use this for initialization
void Start()
{
player = GetComponent<CharacterController>();
}
// Update is called once per frame
void Update() {
horizontalMove = Input.GetAxis("Horizontal");
verticalMove = Input.GetAxis("Vertical");
playerInput = new Vector3(horizontalMove, 0, verticalMove);
playerInput = Vector3.ClampMagnitude(playerInput, 1);
CamDirection();
movePlayer = playerInput.x * camRight + playerInput.z * camForward;
movePlayer = movePlayer * playerSpeed;
player.transform.LookAt(player.transform.position + movePlayer);
SetGravity();
player.Move(movePlayer * Time.deltaTime);
Debug.Log(player.isGrounded);
}
//Funcion para determinar la direccion a la que mira la camara.
public void CamDirection()
{
camForward = mainCamera.transform.forward;
camRight = mainCamera.transform.right;
camForward.y = 0;
camRight.y = 0;
camForward = camForward.normalized;
camRight = camRight.normalized;
}
//Funcion para la gravedad.
public void SetGravity()
{
if (player.isGrounded)
{
fallVelocity = -gravity * Time.deltaTime;
movePlayer.y = fallVelocity;
}
else
{
fallVelocity -= gravity * Time.deltaTime;
movePlayer.y = fallVelocity;
}
}
}