CharacterController vs Rigidbody#
Para un personaje que anda con precisión (shooters, plataformas 3D), el CharacterController suele ir mejor que un Rigidbody: da control directo y sin "resbalones", pero la gravedad la gestionas tú. Añade el componente Character Controller al jugador (sustituye al collider) y quita cualquier Rigidbody. Ver el porqué en Rigidbody.
Requisitos#
Un objeto "Jugador" con Character Controller, y una Camera como hija de ese objeto, colocada a la altura de los ojos.
El movimiento#
using UnityEngine;
[RequireComponent(typeof(CharacterController))]
public class JugadorFPS : MonoBehaviour
{
[SerializeField] private float velocidad = 6f;
[SerializeField] private float fuerzaSalto = 8f;
[SerializeField] private float gravedad = -20f;
private CharacterController cc;
private Vector3 velocidadVertical; // guarda caída/salto en Y
void Awake() => cc = GetComponent<CharacterController>();
void Update()
{
// Movimiento en el plano, relativo a hacia dónde mira el jugador
float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");
Vector3 mov = transform.right * x + transform.forward * z;
cc.Move(mov * velocidad * Time.deltaTime);
// Gravedad y salto
if (cc.isGrounded)
{
velocidadVertical.y = -1f; // pequeño valor para "pegarse" al suelo
if (Input.GetButtonDown("Jump"))
velocidadVertical.y = fuerzaSalto;
}
else
{
velocidadVertical.y += gravedad * Time.deltaTime;
}
cc.Move(velocidadVertical * Time.deltaTime);
}
}En vez de 0, ponemos una velocidad vertical negativa pequeña estando en el suelo. Así el CharacterController mantiene contacto y isGrounded responde de forma fiable en rampas y escalones, en vez de parpadear entre "en suelo" y "en aire".
Mirar con el ratón#
La cámara (hija) gira en vertical; el cuerpo del jugador gira en horizontal. Bloqueamos el cursor al centro.
using UnityEngine;
public class MirarConRaton : MonoBehaviour
{
[SerializeField] private float sensibilidad = 200f;
[SerializeField] private Transform cuerpo; // el objeto Jugador (padre)
private float rotacionX;
void Start()
{
Cursor.lockState = CursorLockMode.Locked; // cursor al centro, oculto
}
void Update()
{
float ratonX = Input.GetAxis("Mouse X") * sensibilidad * Time.deltaTime;
float ratonY = Input.GetAxis("Mouse Y") * sensibilidad * Time.deltaTime;
// Vertical: se acumula y se limita para no dar la voltereta
rotacionX = Mathf.Clamp(rotacionX - ratonY, -85f, 85f);
transform.localRotation = Quaternion.Euler(rotacionX, 0f, 0f);
// Horizontal: gira todo el cuerpo
cuerpo.Rotate(Vector3.up * ratonX);
}
}A diferencia del Rigidbody, el CharacterController se mueve con cc.Move en Update (usa Time.deltaTime). No es física de Rigidbody, así que no va en FixedUpdate.
Liberar el cursor#
Con el cursor bloqueado no puedes usar menús. Libéralo (por ejemplo al pausar) así:
if (Input.GetKeyDown(KeyCode.Escape))
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}Errores frecuentes#
- Mezclar Rigidbody y CharacterController en el mismo objeto (elige uno).
- Mover el CharacterController en
FixedUpdate(va enUpdate). - No limitar la rotación vertical y acabar mirando "del revés".
- Olvidar bloquear el cursor y que la cámara se comporte raro.
- Poner la cámara como objeto suelto en vez de hija del jugador.
Resumen#
El CharacterController da un control en primera persona preciso: mueve con cc.Move en Update relativo a transform.forward/right, aplica la gravedad tú mismo acumulándola en la Y, y salta comprobando isGrounded. La cámara (hija) mira en vertical con el ratón (limitada con Clamp) y el cuerpo gira en horizontal, con Cursor.lockState bloqueado. Para tercera persona, combínalo con Cinemachine.