Up to date

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

Introduction à la physique

Dans le développement d'un jeu, vous avez souvent besoin de savoir quand deux objets du jeu se croisent ou entrent en contact. C'est ce qu'on appelle la détection des collisions. Lorsqu'une collision est détectée, vous voulez généralement que quelque chose se produise. C'est ce qu'on appelle la réponse à la collision.

Godot offre un certain nombre d'objets de collision en 2D et 3D pour fournir à la fois la détection et la réponse aux collisions. Essayer de décider lequel utiliser pour votre projet peut prêter à confusion. Vous pouvez éviter les problèmes et simplifier le développement si vous comprenez comment chacun fonctionne et quels sont ses avantages et ses inconvénients.

Dans ce guide, vous apprendrez :

  • Les quatre types d'objets de collision de Godot

  • Comment chaque objet de collision fonctionne

  • Quand et pourquoi choisir un type plutôt qu'un autre

Note

Les exemples de ce document utilisent des objets 2D. Chaque objet physique 2D et chaque forme de collision a un équivalent direct en 3D et dans la plupart des cas, ils fonctionnent de la même manière.

Objets de collisions

Godot offers four kinds of collision objects which all extend CollisionObject2D. The last three listed below are physics bodies and additionally extend PhysicsBody2D.

  • Area2D

    Les nœuds Area2D fournissent la détection et l'influence. Ils peuvent détecter quand les objets se chevauchent et peuvent émettre des signaux quand des corps entrent ou sortent. Un Area2D peut aussi être utilisé pour outrepasser les propriétés physiques, telles que la gravité ou l'amortissement, dans une zone définie.

  • StaticBody2D

    Un corps statique est un corps qui n'est pas déplacé par le moteur physique. Il participe à la détection des collisions, mais ne bouge pas en réponse à la collision. Ils sont le plus souvent utilisés pour des objets qui font partie de l'environnement ou qui n'ont pas besoin d'avoir un comportement dynamique.

  • RigidBody2D (Corps rigide 2D)

    C'est le nœud qui implémente la physique 2D simulée. Vous ne contrôlez pas directement un RigidBody2D, mais vous lui appliquez des forces (gravité, impulsions, etc.) et le moteur physique calcule le mouvement résultant. En savoir plus sur l'utilisation des RigidBody.

  • CharacterBody2D

    Un corps qui fournit la détection de collision, mais n'a pas de physique. Toute réponse au mouvement ou à la collision doit être implémentée dans le code.

Physics material

Static bodies and rigid bodies can be configured to use a PhysicsMaterial. This allows adjusting the friction and bounce of an object, and set if it's absorbent and/or rough.

Formes de collisions

Un corps physique peut contenir n'importe quel nombre d'objets Shape2D comme enfants. Ces formes sont utilisées pour définir les limites de collision de l'objet et pour détecter le contact avec d'autres objets.

Note

Afin de détecter les collisions, au moins un Shape2D doit être assigné à l'objet.

La façon la plus courante d'assigner une forme est d'ajouter un CollisionShape2D ou CollisionPolygon2D comme un enfant de l'objet. Ces nœuds vous permettent de dessiner la forme directement dans l'espace de travail de l'éditeur.

Important

Faites attention à ne jamais mettre à l'échelle vos formes de collision dans l'éditeur. La propriété "Scale" de l'Inspecteur doit rester "(1, 1)". Lorsque vous changez la taille de la forme de la collision, vous devez toujours utiliser les poignées de taille, pas les poignées graduées Node2D. La mise à l'échelle d'une forme peut entraîner un comportement de collision inattendu.

../../_images/player_coll_shape.png

Rappel des processus physiques

The physics engine runs at a fixed rate (a default of 60 iterations per second). This rate is typically different from the frame rate which fluctuates based on what is rendered and available resources.

It is important that all physics related code runs at this fixed rate. Therefore Godot differentiates between physics and idle processing. Code that runs each frame is called idle processing and code that runs on each physics tick is called physics processing. Godot provides two different callbacks, one for each of those processing rates.

The physics callback, Node._physics_process(), is called before each physics step. Any code that needs to access a body's properties should be run in here. This method will be passed a delta parameter, which is a floating-point number equal to the time passed in seconds since the last step. When using the default 60 Hz physics update rate, it will typically be equal to 0.01666... (but not always, see below).

Note

Il est recommandé de toujours utiliser le paramètre delta lorsque cela est pertinent dans vos calculs physiques, afin que le jeu se comporte correctement si vous modifiez le taux de mise à jour physique ou si l'appareil du joueur ne peut pas suivre.

Niveaux et masques de collisions

One of the most powerful, but frequently misunderstood, collision features is the collision layer system. This system allows you to build up complex interactions between a variety of objects. The key concepts are layers and masks. Each CollisionObject2D has 32 different physics layers it can interact with.

Examinons chacune des propriétés à tour de rôle :

  • collision_layer

    Elle décrit les calques dans lesquels l'objet apparaît in. Par défaut, tous les corps sont sur la couche 1.

  • collision_mask

    Cette section décrit les couches que le corps va scanner pour détecter les collisions. Si un objet n'est pas dans l'une des couches du masque, le corps l'ignore. Par défaut, tous les corps scannent la couche 1.

Ces propriétés peuvent être configurées via le code ou en les modifiant dans l'inspecteur.

Il peut être difficile de garder une trace de ce que vous utilisez pour chaque calque, il peut donc être utile d'attribuer des noms aux calques que vous utilisez. Les noms peuvent être assignés dans Project Settings -> Layer Names.

../../_images/physics_layer_names.png

Exemple dans l'interface graphique

Vous avez quatre types de nœuds dans votre jeu : Murs, joueur, ennemi et pièce de monnaie. Le joueur et l'ennemi doivent entrer en collision avec les murs. Le nœud Player doit détecter les collisions avec l'ennemi et la pièce, mais l'ennemi et la pièce doivent s'ignorer mutuellement.

Commencez par nommer les couches 1-4 "murs", "joueur", "ennemis" et "pièces" et placez chaque type de nœud dans sa couche respective en utilisant la propriété "Layer". Définissez ensuite la propriété "Mask" de chaque nœud en sélectionnant les calques avec lesquels il doit interagir. Par exemple, les paramètres du joueur ressemblent à ceci :

../../_images/player_collision_layers.png ../../_images/player_collision_mask.png

Exemple en code

In function calls, layers are specified as a bitmask. Where a function enables all layers by default, the layer mask will be given as 0xffffffff. Your code can use binary, hexadecimal, or decimal notation for layer masks, depending on your preference.

L'équivalent en code de l'exemple ci-dessus où les couches 1, 3 et 4 ont été activées serait le suivant :

# Example: Setting mask value for enabling layers 1, 3 and 4

# Binary - set the bit corresponding to the layers you want to enable (1, 3, and 4) to 1, set all other bits to 0.
# Note: Layer 32 is the first bit, layer 1 is the last. The mask for layers 4,3 and 1 is therefore
0b00000000_00000000_00000000_00001101
# (This can be shortened to 0b1101)

# Hexadecimal equivalent (1101 binary converted to hexadecimal)
0x000d
# (This value can be shortened to 0xd)

# Decimal - Add the results of 2 to the power of (layer to be enabled - 1).
# (2^(1-1)) + (2^(3-1)) + (2^(4-1)) = 1 + 4 + 8 = 13
pow(2, 1-1) + pow(2, 3-1) + pow(2, 4-1)

Area2D

Les nœuds de zone assurent la détection et l'influence. Ils peuvent détecter quand les objets se chevauchent et émettre des signaux quand les corps entrent ou sortent. Les zones peuvent également être utilisées pour outrepasser les propriétés physiques, telles que la gravité ou l'amortissement, dans une zone définie.

Il y a trois utilisations principales pour Area2D :

  • Remplacer les paramètres physiques primordiaux (comme la gravité) dans une région donnée.

  • Détecter quand d'autres corps entrent ou sortent d'une région ou quels corps se trouvent actuellement dans une région.

  • Vérification des chevauchements avec d'autres zones.

Par défaut, les zones reçoivent également les entrées de la souris et de l'écran tactile.

StaticBody2D

Un corps statique est un corps qui n'est pas déplacé par le moteur physique. Il participe à la détection des collisions, mais ne bouge pas en réponse à la collision. Cependant, il peut donner du mouvement ou de la rotation à un corps en collision comme si il se déplaçait, en utilisant ses propriétés constant_linear_velocity et constant_angular_velocity.

Les nœuds StaticBody2D sont le plus souvent utilisés pour des objets qui font partie de l'environnement ou qui n'ont pas besoin d'avoir un comportement dynamique.

Exemples d'utilisation de StaticBody2D :

  • Plates-formes (y compris les plates-formes mobiles)

  • Convoyeur à courroies

  • Murs et autres obstacles

RigidBody2D

C'est le nœud qui implémente la physique 2D simulée. Vous ne contrôlez pas un RigidBody2D directement. Au lieu de cela, vous lui appliquez des forces et le moteur physique calcule le mouvement résultant, y compris les collisions avec d'autres corps, et les réactions de collision, telles que le rebondissement, la rotation, etc.

Vous pouvez modifier le comportement d'un corps rigide via des propriétés telles que "Mass", "Friction" ou "Bounce", qui peuvent être définies dans l'inspecteur.

Le comportement du corps est également affecté par les propriétés du monde, telles que définies dans Project Settings -> Physics, ou en entrant un Area2D qui surcharge les propriétés physiques globales.

Quand un corps rigide est au repos et n'a pas bougé depuis un moment, il s'endort. Un corps endormi agit comme un corps statique, et ses forces ne sont pas calculées par le moteur physique. Le corps se réveille lorsque des forces sont appliquées, soit par une collision, soit par un code.

Utiliser RigidBody2D

Un des avantages de l'utilisation d'un corps rigide est qu'il est possible d'avoir beaucoup de comportement "gratuitement" sans écrire de code. Par exemple, si vous créez un jeu de type "Angry Birds" avec des blocs tombants, vous n'aurez qu'à créer RigidBody2Ds et ajuster leurs propriétés. L'empilement, la chute et le rebondissement seraient automatiquement calculés par le moteur physique.

However, if you do wish to have some control over the body, you should take care - altering the position, linear_velocity, or other physics properties of a rigid body can result in unexpected behavior. If you need to alter any of the physics-related properties, you should use the _integrate_forces() callback instead of _physics_process(). In this callback, you have access to the body's PhysicsDirectBodyState2D, which allows for safely changing properties and synchronizing them with the physics engine.

Par exemple, voici le code d'un vaisseau spatial de type "Astéroïdes" :

extends RigidBody2D

var thrust = Vector2(0, -250)
var torque = 20000

func _integrate_forces(state):
    if Input.is_action_pressed("ui_up"):
        state.apply_force(thrust.rotated(rotation))
    else:
        state.apply_force(Vector2())
    var rotation_direction = 0
    if Input.is_action_pressed("ui_right"):
        rotation_direction += 1
    if Input.is_action_pressed("ui_left"):
        rotation_direction -= 1
    state.apply_torque(rotation_direction * torque)

Notez que nous ne réglons pas directement les propriétés linear_velocity ou angular_velocity, mais appliquons plutôt des forces (thrust et torque) au corps et laissons le moteur physique calculer le mouvement résultant.

Note

Quand un corps rigide s'endort, la fonction _integrate_forces() ne sera pas appelée. Pour outrepasser ce comportement, vous devrez garder le corps éveillé en créant une collision, en lui appliquant une force ou en désactivant la propriété can_sleep. Sachez que cela peut avoir un effet négatif sur la performance.

Rapport de contact

By default, rigid bodies do not keep track of contacts, because this can require a huge amount of memory if many bodies are in the scene. To enable contact reporting, set the max_contacts_reported property to a non-zero value. The contacts can then be obtained via PhysicsDirectBodyState2D.get_contact_count() and related functions.

La surveillance des contacts par signaux peut être activée via la propriété contact_monitor. Voir RigidBody2D pour la liste des signaux disponibles.

CharacterBody2D

CharacterBody2D bodies detect collisions with other bodies, but are not affected by physics properties like gravity or friction. Instead, they must be controlled by the user via code. The physics engine will not move a character body.

When moving a character body, you should not set its position directly. Instead, you use the move_and_collide() or move_and_slide() methods. These methods move the body along a given vector, and it will instantly stop if a collision is detected with another body. After the body has collided, any collision response must be coded manually.

Character collision response

After a collision, you may want the body to bounce, to slide along a wall, or to alter the properties of the object it hit. The way you handle collision response depends on which method you used to move the CharacterBody2D.

move_and_collide

Lorsque vous utilisez move_and_collide(), la fonction retourne un objet KinematicCollision2D, qui contient des informations sur la collision et le corps en collision. Vous pouvez utiliser ces informations pour déterminer la réponse.

Par exemple, si vous voulez trouver le point dans l'espace où la collision s'est produite :

extends PhysicsBody2D

var velocity = Vector2(250, 250)

func _physics_process(delta):
    var collision_info = move_and_collide(velocity * delta)
    if collision_info:
        var collision_point = collision_info.get_position()

Ou pour rebondir sur l'objet en collision :

extends PhysicsBody2D

var velocity = Vector2(250, 250)

func _physics_process(delta):
    var collision_info = move_and_collide(velocity * delta)
    if collision_info:
        velocity = velocity.bounce(collision_info.get_normal())

move_and_slide

Le glissement est une réaction de collision courante ; imaginez un joueur se déplaçant le long des murs dans un jeu descendant ou courant le long des pentes dans un jeu de plates-formes. Bien qu'il soit possible de coder cette réponse vous-même après avoir utilisé move_and_collide(), move_and_slide() offre un moyen pratique d'implémenter un mouvement glissant sans écrire beaucoup de code.

Avertissement

move_and_slide() inclut automatiquement le pas de temps dans son calcul, il ne faut donc pas multiplier le vecteur vitesse par delta.

Par exemple, utilisez le code suivant pour créer un personnage capable de marcher sur le sol (y compris sur les pentes) et de sauter debout sur le sol :

extends CharacterBody2D

var run_speed = 350
var jump_speed = -1000
var gravity = 2500

func get_input():
    velocity.x = 0
    var right = Input.is_action_pressed('ui_right')
    var left = Input.is_action_pressed('ui_left')
    var jump = Input.is_action_just_pressed('ui_select')

    if is_on_floor() and jump:
        velocity.y = jump_speed
    if right:
        velocity.x += run_speed
    if left:
        velocity.x -= run_speed

func _physics_process(delta):
    velocity.y += gravity * delta
    get_input()
    move_and_slide()

Voir Caractère cinématique (2D) pour plus de détails sur l'utilisation de move_and_slide(), qui inclut un projet de démonstration avec le code détaillé.