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. UnArea2D
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.
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.
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 :
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)
using Godot;
public partial class Spaceship : RigidBody2D
{
private Vector2 _thrust = new Vector2(0, -250);
private float _torque = 20000;
public override void _IntegrateForces(PhysicsDirectBodyState2D state)
{
if (Input.IsActionPressed("ui_up"))
state.ApplyForce(_thrust.Rotated(Rotation));
else
state.ApplyForce(new Vector2());
var rotationDir = 0;
if (Input.IsActionPressed("ui_right"))
rotationDir += 1;
if (Input.IsActionPressed("ui_left"))
rotationDir -= 1;
state.ApplyTorque(rotationDir * _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()
using Godot;
public partial class Body : PhysicsBody2D
{
private Vector2 _velocity = new Vector2(250, 250);
public override void _PhysicsProcess(double delta)
{
var collisionInfo = MoveAndCollide(_velocity * (float)delta);
if (collisionInfo != null)
{
var collisionPoint = collisionInfo.GetPosition();
}
}
}
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())
using Godot;
public partial class Body : PhysicsBody2D
{
private Vector2 _velocity = new Vector2(250, 250);
public override void _PhysicsProcess(double delta)
{
var collisionInfo = MoveAndCollide(_velocity * (float)delta);
if (collisionInfo != null)
_velocity = _velocity.Bounce(collisionInfo.GetNormal());
}
}
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()
using Godot;
public partial class Body : CharacterBody2D
{
private float _runSpeed = 350;
private float _jumpSpeed = -1000;
private float _gravity = 2500;
private void GetInput()
{
var velocity = Velocity;
velocity.X = 0;
var right = Input.IsActionPressed("ui_right");
var left = Input.IsActionPressed("ui_left");
var jump = Input.IsActionPressed("ui_select");
if (IsOnFloor() && jump)
velocity.Y = _jumpSpeed;
if (right)
velocity.X += _runSpeed;
if (left)
velocity.X -= _runSpeed;
Velocity = velocity;
}
public override void _PhysicsProcess(double delta)
{
var velocity = Velocity;
velocity.Y += _gravity * (float)delta;
Velocity = velocity;
GetInput();
MoveAndSlide();
}
}
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é.