CharacterBody2D/3D en Godot 4 — Guía completa

1. Introducción

Godot 4 introdujo grandes cambios en el movimiento de personajes. Los antiguos nodos KinematicBody2D y KinematicBody3D pasaron a llamarse CharacterBody2D y CharacterBody3D, y la API de move_and_slide() se rediseñó por completo. Tanto si migras desde Godot 3 como si empiezas de cero, esta guía cubre todo lo que necesitas saber.

CharacterBody2D y CharacterBody3D son cuerpos físicos pensados para personajes controlados por código. A diferencia de RigidBody, no reaccionan automáticamente a las fuerzas — controlas su movimiento por completo mediante script. Esto los hace ideales para personajes jugables, NPC y cualquier cosa que necesite un movimiento preciso y determinista.

2. Qué cambió respecto a Godot 3

Estos son los cambios más importantes en el movimiento de personajes entre Godot 3 y Godot 4:

Idea clave

En Godot 3, move_and_slide() devolvía la velocidad resultante. En Godot 4 devuelve un bool (si se produjo una colisión), y la velocidad se actualiza directamente en la propiedad velocity.

3. Controlador básico de plataformas 2D

Este es el controlador estándar de plataformas de desplazamiento lateral. El personaje puede moverse a izquierda/derecha y saltar cuando está en el suelo. Esta es la plantilla que Godot genera al crear un nuevo script de CharacterBody2D.

GDScript — platformer_controller.gd
extends CharacterBody2D

const SPEED = 300.0
const JUMP_VELOCITY = -400.0

func _physics_process(delta: float) -> void:
    # Apply gravity when not on floor
    if not is_on_floor():
        velocity += get_gravity() * delta

    # Jump when on floor and jump pressed
    if Input.is_action_just_pressed("ui_accept") and is_on_floor():
        velocity.y = JUMP_VELOCITY

    # Horizontal movement
    var direction := Input.get_axis("ui_left", "ui_right")
    if direction:
        velocity.x = direction * SPEED
    else:
        velocity.x = move_toward(velocity.x, 0, SPEED)

    move_and_slide()

Desglose línea por línea

Consejo: estructura de nodos necesaria

Tu CharacterBody2D necesita al menos un nodo hijo CollisionShape2D con una forma asignada (p. ej. RectangleShape2D o CapsuleShape2D). Sin ella, move_and_slide() no detectará ninguna colisión.

4. Controlador básico cenital 2D

Para juegos con vista cenital (RPG, twin-stick shooters, etc.), te mueves en las cuatro direcciones sin gravedad. El código es más sencillo que el de un juego de plataformas.

GDScript — topdown_controller.gd
extends CharacterBody2D

const SPEED = 200.0

func _physics_process(delta: float) -> void:
    var input_direction := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
    velocity = input_direction * SPEED
    move_and_slide()

Cómo funciona

Añadir aceleración y fricción

Para una sensación más suave con aceleración y desaceleración:

GDScript — topdown_smooth.gd
extends CharacterBody2D

const SPEED = 200.0
const ACCELERATION = 1200.0
const FRICTION = 1000.0

func _physics_process(delta: float) -> void:
    var input_direction := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")

    if input_direction != Vector2.ZERO:
        velocity = velocity.move_toward(input_direction * SPEED, ACCELERATION * delta)
    else:
        velocity = velocity.move_toward(Vector2.ZERO, FRICTION * delta)

    move_and_slide()

5. Controlador 3D en tercera persona

La versión 3D sigue el mismo patrón. La principal diferencia es trabajar con Vector3 y usar transform.basis para convertir la entrada 2D en movimiento en el espacio 3D del mundo.

GDScript — character_3d.gd
extends CharacterBody3D

const SPEED = 5.0
const JUMP_VELOCITY = 4.5

func _physics_process(delta: float) -> void:
    # Apply gravity
    if not is_on_floor():
        velocity += get_gravity() * delta

    # Jump
    if Input.is_action_just_pressed("ui_accept") and is_on_floor():
        velocity.y = JUMP_VELOCITY

    # Get input and convert to 3D direction
    var input_dir := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
    var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()

    if direction:
        velocity.x = direction.x * SPEED
        velocity.z = direction.z * SPEED
    else:
        velocity.x = move_toward(velocity.x, 0, SPEED)
        velocity.z = move_toward(velocity.z, 0, SPEED)

    move_and_slide()

Diferencias clave con 2D

Advertencia: get_gravity() requiere Godot 4.4+

El método get_gravity() se añadió en Godot 4.4. Para versiones anteriores, usa Vector2(0, ProjectSettings.get_setting("physics/2d/default_gravity")) para 2D, o Vector3(0, -ProjectSettings.get_setting("physics/3d/default_gravity"), 0) para 3D.

6. Referencia de las propiedades clave

Tanto CharacterBody2D como CharacterBody3D comparten estas propiedades importantes. Ajústalas en el Inspector o mediante código.

Propiedad Tipo Predeterminado Descripción
velocity Vector2 / Vector3 Vector2.ZERO La velocidad del personaje. Establécela antes de llamar a move_and_slide(). Tras la llamada se actualiza con la velocidad resultante.
floor_snap_length float 1.0 Reemplaza a move_and_slide_with_snap(). Distancia con la que el personaje se fija al suelo. Ponla a 0 para desactivarla. Útil para pendientes y escaleras.
up_direction Vector2 / Vector3 Vector2.UP Define qué dirección es «arriba». Esto determina qué cuenta como suelo, pared o techo. El valor predeterminado es (0, -1) en 2D, (0, 1, 0) en 3D.
floor_stop_on_slope bool true Cuando es true, el personaje no se desliza cuesta abajo en las pendientes mientras está quieto. Imprescindible para los juegos de plataformas.
floor_max_angle float 0.785 (45°) Ángulo máximo de pendiente transitable en radianes. Las superficies más empinadas que esto se tratan como paredes. Usa deg_to_rad(60) para establecer 60 grados.
max_slides int 6 Número máximo de iteraciones de colisión por cada llamada a move_and_slide(). Los valores más altos son más precisos pero más lentos.
wall_min_slide_angle float 0.262 (15°) Ángulo mínimo para el deslizamiento por paredes. Evita que el personaje se quede atascado en paredes casi paralelas.
platform_on_leave PlatformOnLeave ADD_VELOCITY Comportamiento al abandonar una plataforma móvil. ADD_VELOCITY conserva el impulso, ADD_UPWARD_VELOCITY solo añade la componente hacia arriba, DO_NOTHING ignora la velocidad de la plataforma.
slide_on_ceiling bool true Cuando es true, permite deslizarse por los techos. Cuando es false, detiene la velocidad horizontal al golpear el techo.

7. Detección de colisiones tras move_and_slide()

Tras llamar a move_and_slide(), puedes inspeccionar las colisiones que se produjeron. Esto es útil para reaccionar a tipos concretos de collider, reproducir efectos de sonido al aterrizar o implementar mecánicas de salto en pared.

GDScript — collision_detection.gd
func _physics_process(delta: float) -> void:
    # ... set velocity here ...
    move_and_slide()

    # Check all collisions from this frame
    for i in get_slide_collision_count():
        var collision := get_slide_collision(i)
        var collider := collision.get_collider()
        print("Collided with: ", collider.name)
        print("Normal: ", collision.get_normal())
        print("Position: ", collision.get_position())

    # Practical example: bounce off enemies
    for i in get_slide_collision_count():
        var collision := get_slide_collision(i)
        if collision.get_collider().is_in_group("enemies"):
            velocity = collision.get_normal() * 300
            break

Métodos útiles de KinematicCollision

8. Chuleta de migración

Referencia rápida para convertir código de Godot 3 a Godot 4:

Godot 3 Godot 4
KinematicBody2D CharacterBody2D
KinematicBody3D CharacterBody3D
velocity = move_and_slide(velocity, Vector2.UP) velocity = ...
move_and_slide()
move_and_slide_with_snap(vel, snap, up) floor_snap_length = 4.0
move_and_slide()
var vel = move_and_slide(...)
devuelve velocity
move_and_slide()
la propiedad velocity se actualiza directamente
var gravity = ProjectSettings.get("physics/2d/default_gravity") get_gravity() (4.4+)
move_and_slide(..., up_direction, ...) up_direction = Vector2.UP (establecido como propiedad)
move_and_slide(..., stop_on_slope, ...) floor_stop_on_slope = true (establecido como propiedad)
El conversor automático de Godot

Al abrir un proyecto de Godot 3 en Godot 4, el motor ofrece convertir tu proyecto. Renombra los nodos e intenta actualizar los scripts, pero no siempre acierta con las llamadas a move_and_slide(). Probablemente tendrás que corregir manualmente tu código de movimiento.

9. Errores comunes

Error 1: Pasar argumentos a move_and_slide()

Incorrecto
# ERROR: move_and_slide() takes no arguments in Godot 4
velocity = move_and_slide(velocity, Vector2.UP)
Correcto
# Set velocity, then call move_and_slide() with no arguments
velocity.x = direction * SPEED
move_and_slide()

Error 2: Olvidar establecer velocity antes de move_and_slide()

Incorrecto — velocity nunca se establece, así que nada se mueve
func _physics_process(delta: float) -> void:
    move_and_slide()  # velocity is Vector2.ZERO — nothing happens

Error 3: Usar _process() en lugar de _physics_process()

move_and_slide() debe llamarse en _physics_process(), que se ejecuta a una tasa fija (60 Hz por defecto). Usar _process() vincula la física a la tasa de fotogramas de renderizado, provocando un comportamiento inconsistente.

Error 4: No configurar la CollisionShape

Un CharacterBody2D/CharacterBody3D sin un hijo CollisionShape atravesará todo. Godot muestra un icono de advertencia en el editor si falta la forma de colisión.

Error 5: Sobrescribir velocity.y con la gravedad en cada fotograma

Incorrecto — reinicia velocity.y, por lo que el salto nunca funciona
# This overwrites any jump velocity!
velocity.y = gravity * delta  # should be +=, not =
Correcto — acumula la gravedad
# Gravity accumulates over time
velocity += get_gravity() * delta

Error 6: Aplicar la gravedad estando en el suelo

Envuelve siempre la gravedad con if not is_on_floor(). Sin esta comprobación, la gravedad sigue acumulándose mientras se está en el suelo. Cuando el personaje se sale de un borde, se desplomará a una velocidad extrema en lugar de caer de forma natural.

10. Configura controladores de personaje con IA

¿Quieres que la IA configure tu controlador de personaje?

Godot MCP Pro permite que los asistentes de IA creen nodos CharacterBody, configuren propiedades físicas, preparen formas de colisión, escriban scripts de movimiento, lancen tu juego y prueben el movimiento — todo a partir de prompts en lenguaje natural.

add_node setup_physics_body setup_collision set_physics_layers create_script simulate_key play_scene capture_frames
Consigue Godot MCP Pro — $15