🎮 UnityDocs

Movimiento 3D: CharacterController vs Rigidbody

Las dos formas de mover un personaje 3D y cuándo usar cada una: el CharacterController (control preciso, tú aplicas la gravedad, pensado para personajes) frente al Rigidbody (física real). Pendientes, escalones, gravedad y salto bien hechos.

📄 ArtículoIntermedio✅ RevisadoUnity 6.0 LTSActualizado 2026-07-17
DificultadConceptual Código Matemáticas
Tiempo📖 Lectura 8 min · ⌨️ Práctica 25 min

Dos filosofías para mover un personaje#

Un personaje 3D no se mueve como una caja física normal: quieres control preciso (que responda al instante, suba escalones, no rebote). Hay dos caminos:

  • CharacterController: un componente pensado para personajes. No es física real: tú decides cómo se mueve (incluida la gravedad), pero choca con paredes y sube escalones solo. Control total.
  • Rigidbody: física real. El personaje obedece a fuerzas y colisiones. Realista, pero más difícil de hacer "responsivo" y propenso a resbalar o volcar.
🧭 ¿Qué debería usar? · ¿CharacterController o Rigidbody?
  • ¿Personaje que anda, un FPS/tercera persona, control preciso y responsivo? → CharacterController
  • ¿El personaje es física (una bola que rueda, un coche, algo que empujan fuerzas)? → Rigidbody
  • ¿Necesitas que otros objetos físicos lo empujen de forma realista? → Rigidbody (el CharacterController no reacciona a fuerzas por sí solo)

CharacterController: lo esencial#

Añade el componente (trae una cápsula de colisión) y muévelo con Move. Clave: la gravedad la aplicas tú.

C#
using UnityEngine;

[RequireComponent(typeof(CharacterController))]
public class MovimientoPersonaje : MonoBehaviour
{
    [SerializeField] private float velocidad = 6f;
    [SerializeField] private float gravedad = -20f;
    [SerializeField] private float fuerzaSalto = 8f;

    private CharacterController cc;
    private float velocidadY;

    void Awake() => cc = GetComponent<CharacterController>();

    void Update()
    {
        // Movimiento horizontal según input
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");
        Vector3 horizontal = (transform.right * x + transform.forward * z) * velocidad;

        // Gravedad y salto (la Y la gestionamos nosotros)
        if (cc.isGrounded)
        {
            velocidadY = -1f;                       // pequeño empuje para "pegarse" al suelo
            if (Input.GetButtonDown("Jump")) velocidadY = fuerzaSalto;
        }
        else velocidadY += gravedad * Time.deltaTime;

        Vector3 movimiento = horizontal + Vector3.up * velocidadY;
        cc.Move(movimiento * Time.deltaTime);       // un solo Move por frame
    }
}
  • isGrounded: si toca suelo (para saltar y resetear la caída).
  • Move: mueve respetando colisiones; devuelve info de choques. Llama a Move una vez por frame con el vector total.
  • SimpleMove: variante que aplica gravedad automática pero ignora el eje Y manual (no sirve para saltar).

Pendientes y escalones (gratis)#

El CharacterController resuelve solo dos cosas molestas, ajustables en el Inspector:

  • Slope Limit: la pendiente máxima que puede subir (por encima, resbala).
  • Step Offset: la altura de escalón que sube sin saltar (bordillos, escaleras).
  • Skin Width: un margen fino que evita quedarse "pillado" en geometría; no lo pongas a 0.
isGrounded es caprichoso: pégate al suelo

isGrounded a veces parpadea en falso al bajar cuestas o escalones. El truco del velocidadY = -1f cuando está en suelo mantiene al personaje "pegado" y estabiliza la detección. Para casos exigentes, complementa con un raycast hacia abajo.

Si eliges Rigidbody#

Para un personaje con Rigidbody: congela la rotación (Constraints → Freeze Rotation X/Y/Z para que no vuelque), mueve en FixedUpdate con linearVelocity o MovePosition, y detecta suelo con un raycast. Da física real (rampas, empujones), a cambio de más trabajo para que se sienta preciso.

Errores frecuentes#

  • Esperar que el CharacterController caiga solo: no aplica gravedad, la pones tú.
  • Llamar a Move varias veces por frame (comportamiento raro): acumula en un vector y un solo Move.
  • Mover el CharacterController con transform.position (ignora colisiones): usa Move.
  • Personaje Rigidbody que vuelca: falta congelar la rotación.
  • Olvidar Time.deltaTime en el Move (velocidad dependiente de FPS).

Ponte a prueba#

📝 Pon a prueba lo aprendido

Resumen#

Para mover un personaje 3D con control preciso, el CharacterController es la opción por defecto: choca con paredes y sube escalones (Step Offset) y pendientes (Slope Limit) solo, pero tú aplicas la gravedad y lo mueves con un único Move por frame usando isGrounded para el salto. Si el personaje es física (rueda, lo empujan fuerzas), usa un Rigidbody con la rotación congelada y movimiento en FixedUpdate. Combínalo con rotaciones suaves para orientarlo.

Fuentes y para profundizar