Perché i collision layer sono importanti
I collision layer sono la base di tutte le interazioni fisiche in Godot 4 — movimento, rilevamento dei colpi, raycasting, trigger delle Area e altro ancora. Comprendere la differenza tra Layer e Mask è fondamentale, e fraintenderla è uno dei punti dolenti più comuni sia per i principianti sia per gli sviluppatori esperti.
Layer vs Mask — Il modello mentale
Ogni oggetto fisico in Godot ha due proprietà bitmask:
- Layer = "Io esisto su questi layer" (ciò che sono)
- Mask = "Io scansiono questi layer" (ciò che posso vedere / colpire)
Regola fondamentale
A collide con B quando la Mask di A include il Layer di B OPPURE la Mask di B include il Layer di A. È sufficiente che un solo lato "veda" l'altro perché avvenga una collisione.
Assegnare nomi ai layer nelle impostazioni del progetto
Prima di scrivere qualsiasi codice, dai un nome ai tuoi layer. Questo rende l'Inspector molto più facile da usare ed evita confusione man mano che il progetto cresce.
Impostazioni progetto > Nomi layer > Fisica 2D (o Fisica 3D):
| N. layer | Nome | Scopo |
|---|---|---|
| 1 | Player | Il personaggio giocante |
| 2 | Enemy | Tutti i corpi nemici |
| 3 | Environment | Muri, pavimenti, piattaforme |
| 4 | Projectile | Proiettili, frecce, incantesimi |
| 5 | Pickup | Oggetti, monete, kit di cura |
| 6 | Trigger | Sensori, zone di spawn, checkpoint |
Impostare i layer nel codice (GDScript)
Godot 4 offre due approcci — l'API basata sui valori (consigliata) e l'assegnazione diretta della bitmask:
# 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)
Trappola della bitmask
I numeri dei layer sono a base 1 in set_collision_layer_value(), ma la bitmask sottostante è a base 0. Layer 1 = bit 0 = valore 1, Layer 2 = bit 1 = valore 2, Layer 3 = bit 2 = valore 4. In caso di dubbio, usa l'API basata sui valori per evitare errori.
Schemi di layer comuni
Platformer / Side-scroller
| Oggetto | Layer | Mask | Spiegazione |
|---|---|---|---|
| Player | 1 | 2, 3, 5, 6 | Rileva nemici, ambiente, pickup, trigger |
| Enemy | 2 | 1, 3 | Rileva giocatore e ambiente |
| Environment | 3 | — | Passivo — rilevato dagli altri |
| Projectile | 4 | 2, 3 | Colpisce nemici e muri |
| Pickup | 5 | — | Passivo — il giocatore lo rileva |
| Trigger | 6 | 1 | Rileva solo il giocatore |
Top-down / Roguelike
| Oggetto | Layer | Mask | Spiegazione |
|---|---|---|---|
| Player | 1 | 2, 3, 5, 6 | Rileva nemici, muri, NPC, sensori |
| Enemy | 2 | 1, 3 | Rileva giocatore e muri |
| Wall | 3 | — | Passivo |
| Bullet | 4 | 1, 2, 3 | Colpisce giocatore, nemici e muri |
| NPC | 5 | 3 | Collide solo con i muri |
| Sensor | 6 | 1 | Rileva l'ingresso del giocatore |
Layer di Area2D / Area3D
Le Area usano lo stesso sistema Layer/Mask. In più, hanno due proprietà di attivazione:
-
monitoring— Setrue, questa Area rileva attivamente gli altri oggetti che vi entrano. -
monitorable— Setrue, le altre Area possono rilevare questa Area.
Segnali: area_entered vs body_entered
body_entered viene emesso quando un PhysicsBody (CharacterBody, RigidBody, StaticBody) entra nell'Area. area_entered viene emesso quando un'altra Area vi entra. Assicurati di collegare il segnale giusto per il tuo caso d'uso.
# 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()
Collision mask del RayCast
I nodi RayCast hanno solo una Mask (nessun Layer), perché sono rilevatori e non corpi fisici. Imposta la Mask per filtrare ciò che il raggio può colpire:
# 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
Esempio pratico: Player – Enemy – Projectile
Ecco una configurazione completa dei layer per un tipico gioco d'azione. I commenti mostrano il ragionamento dietro ogni scelta:
# 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
Suggerimento: prevenire il fuoco amico
Nota che i proiettili del giocatore mascherano il layer 2 (Enemy) ma non il layer 1 (Player), e i proiettili dei nemici mascherano il layer 1 (Player) ma non il layer 2 (Enemy). È così che previeni il fuoco amico esclusivamente tramite la configurazione dei layer — senza scrivere alcun codice.
Consigli per il debug
- Forme di collisione visibili: Nell'editor, vai su Debug > Forme di collisione visibili per disegnare tutte le forme di collisione a runtime. Questo rivela immediatamente i collider mancanti o disallineati.
- Verifica nell'Inspector: Seleziona un nodo ed espandi Collision > Layer e Collision > Mask nell'Inspector. Passa il mouse su ogni bit per vederne il nome (se li hai nominati nelle impostazioni del progetto).
-
Stampa a runtime:
print("Layer: ", collision_layer, " Mask: ", collision_mask)per verificare i valori della bitmask durante il gioco.
Modifiche di migrazione 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) |
Il parametro bit era a base 0
|
Il parametro layer è a base 1
|
| 20 layer disponibili | 32 layer disponibili |
Insidia della migrazione
Se stai portando un progetto Godot 3, ricorda che set_collision_layer_bit(0, true) diventa set_collision_layer_value(1, true). L'indice si sposta di +1. Se non te ne accorgi, tutti i tuoi layer risulteranno spostati di uno.
Errori comuni
1. Dimenticare di impostare la Mask
Il tuo oggetto ha un Layer ma la Mask è vuota (tutti zeri). L'oggetto esiste nel mondo fisico ma non rileva nulla. Gli altri oggetti con maschere corrispondenti continueranno a rilevare lui, ma move_and_slide() su questo oggetto attraverserà tutto.
2. Confondere Layer con Mask
Impostare il Layer del giocatore su 2 (Enemy) invece della sua Mask. Ora, per quanto riguarda il motore fisico, il giocatore è un nemico. Ricorda sempre: Layer = ciò che sono, Mask = ciò che scansiono.
3. Usare valori di bitmask invece dei numeri dei layer
Scrivere set_collision_layer_value(4, true) pensando che imposti il valore bitmask 4 (layer 1+2). In realtà attiva il layer 4. L'API basata sui valori accetta numeri di layer, non valori di bit.
4. Rilevamento unidirezionale dove ci si aspetta la bidirezionalità
L'oggetto A maschera il layer di B, ma B non maschera il layer di A. move_and_slide() su A collide con B, ma move_and_slide() su B attraversa A. Affinché due nodi CharacterBody si blocchino a vicenda, entrambi devono avere il layer dell'altro nella propria mask.
Automatizza la configurazione della fisica con Godot MCP Pro
Basta con l'attivazione manuale delle caselle dei layer. Lascia che l'IA configuri l'intera impostazione delle collisioni in pochi secondi — inclusi la denominazione dei layer, l'assegnazione delle maschere e l'aggiunta dei raycast.
Ottieni Godot MCP Pro — $15setup_collision
set_physics_layers
get_physics_layers
get_collision_info
add_raycast