Up to date

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

Caractère cinématique (2D)

Introduction

Oui, le nom semble étrange. "Personnage cinématique". Qu'est-ce que c'est que ça ? La raison pour ce nom est que, lorsque les moteurs physiques sont apparus, ils étaient appelés moteurs "dynamiques" (parce qu'ils s'occupaient principalement des réactions de collisions). Beaucoup de tentatives ont été faites pour créer un contrôleur de personnage qui utilise les moteurs dynamiques, mais ce n'était pas aussi facile que ça en avait l'air. Godot a l'une des meilleures implémentations de contrôleur de personnage dynamique que vous pouvez trouver (comme vous pouvez le voir dans la démo de jeu de plateforme 2d), mais l'utiliser demande un niveau de compétence considérable ainsi qu'une bonne connaissance des moteurs physiques (ou beaucoup de patience avec des essais et des erreurs).

Certains moteurs physiques, comme Havok, semblent considérer les contrôleurs de personnages dynamiques comme la meilleure option, alors que d'autres (PhysX) promeuvent plutôt les contrôleurs cinématiques.

Et donc, quelle est la différence ? :

  • Un contrôleur de personnage dynamique utilise un corps rigide avec un tenseur d'inertie infini. En fait, cela veut simplement dire que le corps rigide ne peut pas tourner. Les moteurs physiques laissent toujours les objets entrer en collision, puis résolvent leurs collisions tous ensemble. Cela fait que le contrôleur de personnage dynamique peut interagir avec d'autres objets physiques sans problème, comme on peut le voir dans la démo du jeu de plateforme. Cependant, ces interactions ne sont pas toujours prévisibles. Les collisions peuvent aussi prendre plus qu'une trame pour être résolues, donc quelques collisions peuvent sembler être un petit peu déplacées. Ces problèmes peuvent être résolus, mais demandent un certain niveau de compétence.

  • Un contrôleur de personnage cinématique est toujours considéré comme commençant dans un état sans collision, et va toujours aller vers un état sans collision. S'il commence dans un état de collision, il essaiera de se libérer tout seul comme les corps rigides le font, mais c'est une exception, pas la règle. Cela fait que leur contrôle et leur mouvement sont beaucoup plus prévisibles et plus faciles à programmer. Par contre, l'inconvénient est qu'ils ne peuvent pas interagir directement avec les autres objets physiques, à moins que cela ne soit fait à la main dans le code.

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.

Processus physique

Pour gérer la logique d'un corps ou d'un personnage cinématique, il est toujours conseillé d'utiliser le processus physique, car il est appelé avant l'étape physique et son exécution est synchronisée avec le serveur physique, il est aussi appelé le même nombre de fois par seconde, toujours. Cela rend la physique et le calcul de mouvement plus prévisibles que l'utilisation du processus régulier, qui peut avoir des pics ou perdre en précision si la fréquence d'images est trop élevée ou trop faible.

extends CharacterBody2D

func _physics_process(delta):
    pass

Configuration de la scène

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

Vous remarquerez qu'il y a une icône d'avertissement à côté de notre nœud CollisionShape2D ; c'est parce que nous n'avons pas défini de forme pour lui. Créez un nouveau CircleShape2D dans la propriété de forme de CollisionShape2D. Cliquez sur <CircleShape2D> pour accéder aux options correspondantes, et réglez le rayon sur 30 :

../../_images/kbradius.webp

Note : Comme mentionné précédemment dans le tutoriel sur la physique, le moteur physique ne peut pas gérer l'échelle sur la plupart des types de formes (seuls les polygones de collision, les plans et les segments fonctionnent), donc changez toujours les paramètres (comme le rayon) de la forme au lieu de l'échelle. Il en va de même pour les corps cinématiques/rigides/statiques eux-mêmes, car leur échelle affecte l'échelle des formes.

Maintenant, créez un script pour le personnage, celui utilisé comme exemple ci-dessus devrait servir de base.

Enfin, instanciez cette scène personnage dans la tilemap, et faites de la tilemap la scène principale, de sorte qu'elle s'exécute lorsque vous appuyez sur play.

../../_images/kbinstance.webp

Déplacer le personnage cinématique

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.

Déplaçons notre sprite vers le bas jusqu'à ce qu'il touche le sol :

extends CharacterBody2D

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

Il en résulte que le personnage bouge, mais s'arrête pile lorsqu'il touche le sol. Plutôt cool, hein ?

La prochaine étape sera d'ajouter de la gravité au mélange, de cette façon il se comporte un peu plus comme un personnage de jeu ordinaire :

extends CharacterBody2D

const GRAVITY = 200.0

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

    var motion = velocity * delta
    move_and_collide(motion)

Maintenant, que le personnage tombe en douceur. Faisons-le marcher sur les côtés, à gauche et à droite en touchant les touches directionnelles. Rappelez-vous que les valeurs utilisées (pour la vitesse au moins) sont en pixels/seconde.

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()

Et essayez-le.

C'est un bon point de départ pour un plateformer. Une démo plus complète se trouve dans le zip de démonstration distribué avec le moteur, ou sur le site https://github.com/godotengine/godot-demo-projects/tree/master/2d/kinematic_character.