Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Personaje cinemático (2D)

Introducción

Sí, el nombre suena extraño. "Personaje Cinemático". ¿Qué es eso? La razón es que cuando aparecieron los motores de físicas, fueron llamados motores de "Dinámicas" (porque tratan principalmente con respuestas de colisiones). Se llevaron a cabo muchos intentos para crear un controlador de personajes utilizando los motores de dinámicas, pero no fue tan fácil como parecía. Godot tiene una de las mejores implementaciones de controlador de personajes dinámicos (como puede verse en la demo 2d/plataformas), pero usarlo requiere un considerable nivel de habilidad y conocimiento de motores de físicas (o mucha paciencia con el ensayo y error).

Algunos motores de física como Havok parecen apostar por los controladores de personaje dinámico como la mejor alternativa, mientras que otros (PhysX) prefieren promover los de personaje cinemático.

Entonces, ¿cuál es la diferencia?:

  • Un controlador de personaje dinámico utiliza un cuerpo rígido con tensor de inercia infinita. Básicamente, es un cuerpo rígido que no puede rotar. Los motores de física siempre dejan que los objetos se muevan y colisionen, después resuelven sus colisiones todas juntas. Esto hace que los controladores de personaje dinámico sean capaces de interactuar con otros objetos físicos sin inconvenientes, como se ve en la demo del juego de plataformas. Sin embargo estas interacciones no son siempre predecibles. Las colisiones pueden tardar más de un frame en ser resueltas, así que unas pocas colisiones pueden verse desplazadas un poquito. Esos problemas pueden solucionarse, pero requieren de cierta habilidad.

  • Un controlador cinemático de personaje asume siempre en un estado de no colisión, y siempre se moverá a un estado de no colisión. Si comienza en un estado de colisión, intentará liberarse como lo hacen los cuerpos rígidos, pero esta es la excepción, no la regla. Esto hace que su control y movimiento sean mucho más predecibles y fáciles de programar. Sin embargo, como desventaja, no pueden interactuar directamente con otros objetos de la física, a menos que se haga a mano en código.

This short tutorial focuses on the kinematic character controller. It uses the old-school way of handling collisions, which is not necessarily simpler under the hood, but well hidden and presented as an API.

Proceso físico

Para manejar la lógica de un personaje o cuerpo cinemático, siempre se aconseja utilizar el proceso de la física, ya que es llamado antes del paso de la física y su ejecución está sincronizada con el servidor de física, también siempre es llamado la misma cantidad de veces por segundo. Esto hace que la física y el cálculo de movimiento funcionen de una manera más predecible que el proceso normal, que puede tener picos o perder precisión si la frecuencia de imagen es demasiado alta o demasiado baja.

extends CharacterBody2D

func _physics_process(delta):
    pass

Configuración de la escena

To have something to test, here's the scene (from the tilemap tutorial): kinematic_character_2d_starter.zip. We'll be creating a new scene for the character. Use the robot sprite and create a scene like this:

../../_images/kbscene.webp

Notarás que hay un icono de advertencia junto al nodo CollisionShape2D, esto es porque no hemos definido una forma para él. Crea un nuevo CircleShape2D en la propiedad shape de CollisionShape2D. Haz clic en <CircleShape2D> para ir a las opciones correspondientes, y establece el radio en 30:

../../_images/kbradius.webp

Nota: Como se mencionó anteriormente en el tutorial de física, el motor de física no puede manejar la escala en la mayoría de los tipos de formas (sólo funcionan los polígonos de colisión, planos y segmentos), así que cambia siempre los parámetros (como el radio) de la forma en lugar de escalarla. Lo mismo ocurre con los cuerpos cinemáticos/rígidos/estáticos, ya que su escala afecta a la escala de la forma.

Ahora crea un script para el personaje, el que se usa como ejemplo anterior debería funcionar como base.

Por último, instancia la escena del personaje en el tilemap, y haz que la escena del mapa sea la principal, para que se ejecute al presionar play.

../../_images/kbinstance.webp

Moviendo el personaje cinemático

Go back to the character scene, and open the script, the magic begins now! Kinematic body will do nothing by default, but it has a useful function called CharacterBody2D.move_and_collide(). This function takes a Vector2 as an argument, and tries to apply that motion to the kinematic body. If a collision happens, it stops right at the moment of the collision.

Entonces, movamos nuestro sprite hacia abajo hasta que toque el suelo:

extends CharacterBody2D

func _physics_process(delta):
    move_and_collide(Vector2(0, 1)) # Move down 1 pixel per physics frame

El resultado es que el personaje se moverá, pero se detendrá justo cuando golpee el suelo. Bastante genial, ¿no?

El siguiente paso será añadir gravedad a la combinación, de esta manera se comporta de una manera más parecida a la de un personaje real de un juego:

extends CharacterBody2D

const GRAVITY = 200.0

func _physics_process(delta):
    velocity.y += delta * GRAVITY

    var motion = velocity * delta
    move_and_collide(motion)

Ahora el personaje cae suavemente. Hagamos que camine hacia los lados, izquierda y derecha, cuando se presionen las teclas de dirección. Recuerda que los valores utilizados (al menos para la velocidad) son píxeles/segundo.

This adds basic support for walking when pressing left and right:

extends CharacterBody2D

const GRAVITY = 200.0
const WALK_SPEED = 200

func _physics_process(delta):
    velocity.y += delta * GRAVITY

    if Input.is_action_pressed("ui_left"):
        velocity.x = -WALK_SPEED
    elif Input.is_action_pressed("ui_right"):
        velocity.x =  WALK_SPEED
    else:
        velocity.x = 0

    # "move_and_slide" already takes delta time into account.
    move_and_slide()

E inténtalo.

Este es un buen punto de partida para un juego de plataformas. Se puede encontrar una demostración más completa en el zip de demostración distribuido con el motor, o en https://github.com/godotengine/godot-demo-projects/tree/master/2d/kinematic_character.