Pourquoi les calques de collision comptent

Les calques de collision sont le fondement de toutes les interactions physiques dans Godot 4 — déplacement, détection de collision, raycasting, déclencheurs de zone (Area) et plus encore. Comprendre la différence entre Layer et Mask est essentiel, et la mécomprendre est l'un des pièges les plus fréquents, aussi bien pour les débutants que pour les développeurs expérimentés.

Layer vs Mask — le modèle mental

Chaque objet physique dans Godot possède deux propriétés de type masque de bits :

Règle fondamentale

A entre en collision avec B lorsque le Mask de A inclut le Layer de B OU que le Mask de B inclut le Layer de A. Il suffit qu'un seul côté « voie » l'autre pour qu'une collision se produise.

Nommer les calques dans les Paramètres du projet

Avant d'écrire la moindre ligne de code, nommez vos calques. Cela rend l'Inspecteur bien plus facile à utiliser et évite la confusion à mesure que votre projet grandit.

Paramètres du projet > Noms des calques > Physique 2D (ou Physique 3D) :

N° de calque Nom Rôle
1PlayerLe personnage du joueur
2EnemyTous les corps ennemis
3EnvironmentMurs, sols, plateformes
4ProjectileProjectiles, flèches, sorts
5PickupObjets, pièces, kits de soin
6TriggerCapteurs, zones d'apparition, points de contrôle

Définir les calques par le code (GDScript)

Godot 4 propose deux approches — l'API basée sur les valeurs (recommandée) et l'affectation directe du masque de bits :

# Godot 4 API — value-based (1-indexed, recommended)
set_collision_layer_value(1, true)   # I am on layer 1
set_collision_mask_value(2, true)    # I detect layer 2

# Or use bitmask directly
collision_layer = 1   # Layer 1 only (bit 0)
collision_mask = 6    # Layers 2 and 3 (bits 1 + 2 = 6)

# Read current state
var on_layer_1: bool = get_collision_layer_value(1)
var scans_layer_2: bool = get_collision_mask_value(2)

Piège du masque de bits

Les numéros de calque sont indexés à partir de 1 dans set_collision_layer_value(), mais le masque de bits sous-jacent est indexé à partir de 0. Calque 1 = bit 0 = valeur 1, calque 2 = bit 1 = valeur 2, calque 3 = bit 2 = valeur 4. En cas de doute, utilisez l'API basée sur les valeurs pour éviter les erreurs.

Schémas de calques courants

Plateformer / Défilement horizontal

Objet Layer Mask Explication
Player12, 3, 5, 6Détecte ennemis, environnement, objets, déclencheurs
Enemy21, 3Détecte le joueur et l'environnement
Environment3Passif — détecté par les autres
Projectile42, 3Touche les ennemis et les murs
Pickup5Passif — le joueur le détecte
Trigger61Détecte uniquement le joueur

Vue de dessus / Roguelike

Objet Layer Mask Explication
Player12, 3, 5, 6Détecte ennemis, murs, PNJ, capteurs
Enemy21, 3Détecte le joueur et les murs
Wall3Passif
Bullet41, 2, 3Touche le joueur, les ennemis et les murs
NPC53N'entre en collision qu'avec les murs
Sensor61Détecte l'entrée du joueur

Calques Area2D / Area3D

Les Areas utilisent le même système Layer/Mask. Elles disposent en plus de deux propriétés d'activation :

Signaux : area_entered vs body_entered

body_entered se déclenche lorsqu'un PhysicsBody (CharacterBody, RigidBody, StaticBody) entre dans l'Area. area_entered se déclenche lorsqu'une autre Area y entre. Veillez à connecter le signal approprié à votre cas d'usage.

# Pickup Area2D — detect when the Player body enters
func _ready() -> void:
    body_entered.connect(_on_body_entered)

func _on_body_entered(body: Node2D) -> void:
    if body.is_in_group("player"):
        collect()
        queue_free()

Masque de collision RayCast

Les nœuds RayCast n'ont qu'un Mask (pas de Layer), car ce sont des détecteurs et non des corps physiques. Définissez le Mask pour filtrer ce que le rayon peut toucher :

# RayCast that only detects enemies (layer 2)
$RayCast2D.collision_mask = 2  # Layer 2 = Enemy
# Or use the value-based API:
$RayCast2D.set_collision_mask_value(1, false)  # Ignore Player
$RayCast2D.set_collision_mask_value(2, true)   # Detect Enemy
$RayCast2D.set_collision_mask_value(3, false)  # Ignore Environment

# Line-of-sight ray that ignores projectiles
$LineOfSight.collision_mask = 0
$LineOfSight.set_collision_mask_value(1, true)  # Player
$LineOfSight.set_collision_mask_value(3, true)  # Environment

Exemple pratique : Player – Enemy – Projectile

Voici une configuration de calques complète pour un jeu d'action typique. Les commentaires montrent le raisonnement derrière chaque choix :

# Player (CharacterBody2D)
# Layer: 1 (Player)          — "I am the player"
# Mask: 2 (Enemy), 3 (Environment), 5 (Pickup)
#   — I collide with enemies, walls, and can pick up items

# Enemy (CharacterBody2D)
# Layer: 2 (Enemy)            — "I am an enemy"
# Mask: 1 (Player), 3 (Environment)
#   — I collide with the player and walls

# Player Bullet (Area2D)
# Layer: 4 (Projectile)       — "I am a projectile"
# Mask: 2 (Enemy), 3 (Environment)
#   — I hit enemies and walls, but NOT the player who fired me

# Enemy Bullet (Area2D)
# Layer: 4 (Projectile)       — "I am a projectile"
# Mask: 1 (Player), 3 (Environment)
#   — I hit the player and walls, but NOT the enemy who fired me

Astuce : empêcher les tirs amis

Remarquez que les projectiles du joueur masquent le calque 2 (Enemy) mais pas le calque 1 (Player), et que les projectiles ennemis masquent le calque 1 (Player) mais pas le calque 2 (Enemy). C'est ainsi que l'on empêche les tirs amis uniquement par la configuration des calques — sans aucun code.

Conseils de débogage

Changements de migration Godot 3 → 4

Godot 3 Godot 4
set_collision_layer_bit(bit, value) set_collision_layer_value(layer, value)
set_collision_mask_bit(bit, value) set_collision_mask_value(layer, value)
Le paramètre bit était indexé à partir de 0 Le paramètre layer est indexé à partir de 1
20 calques disponibles 32 calques disponibles

Piège de migration

Si vous portez un projet Godot 3, souvenez-vous que set_collision_layer_bit(0, true) devient set_collision_layer_value(1, true). L'index est décalé de +1. Si vous oubliez cela, tous vos calques seront décalés d'un cran.

Erreurs courantes

1. Oublier de définir le Mask

Votre objet possède un Layer, mais le Mask est vide (que des zéros). L'objet existe dans le monde physique, mais ne détecte rien. Les autres objets dont les masques correspondent le détecteront quand même, mais move_and_slide() sur cet objet traversera tout.

2. Confondre Layer et Mask

Régler le Layer du joueur sur 2 (Enemy) au lieu de son Mask. Le joueur est désormais un ennemi du point de vue du moteur physique. Retenez toujours : Layer = ce que je suis, Mask = ce que je scanne.

3. Utiliser des valeurs de masque de bits au lieu de numéros de calque

Écrire set_collision_layer_value(4, true) en croyant définir la valeur de masque de bits 4 (calques 1+2). En réalité, cela active le calque 4. L'API basée sur les valeurs prend des numéros de calque, pas des valeurs de bits.

4. Détection à sens unique alors qu'on attend le bidirectionnel

L'objet A masque le Layer de B, mais B ne masque pas le Layer de A. move_and_slide() sur A entrera en collision avec B, mais move_and_slide() sur B traversera A. Pour que deux nœuds CharacterBody se bloquent mutuellement, il faut que les deux aient le calque de l'autre dans leur Mask.

Automatiser la configuration de la physique avec Godot MCP Pro

Fini de cocher manuellement les cases des calques. Laissez l'IA configurer toute votre installation de collision en quelques secondes — nommage des calques, affectation des masques et ajout de raycasts inclus.

Obtenir Godot MCP Pro — $15
Outils associés : setup_collision set_physics_layers get_physics_layers get_collision_info add_raycast