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:

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
1PlayerIl personaggio giocante
2EnemyTutti i corpi nemici
3EnvironmentMuri, pavimenti, piattaforme
4ProjectileProiettili, frecce, incantesimi
5PickupOggetti, monete, kit di cura
6TriggerSensori, 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
Player12, 3, 5, 6Rileva nemici, ambiente, pickup, trigger
Enemy21, 3Rileva giocatore e ambiente
Environment3Passivo — rilevato dagli altri
Projectile42, 3Colpisce nemici e muri
Pickup5Passivo — il giocatore lo rileva
Trigger61Rileva solo il giocatore

Top-down / Roguelike

Oggetto Layer Mask Spiegazione
Player12, 3, 5, 6Rileva nemici, muri, NPC, sensori
Enemy21, 3Rileva giocatore e muri
Wall3Passivo
Bullet41, 2, 3Colpisce giocatore, nemici e muri
NPC53Collide solo con i muri
Sensor61Rileva l'ingresso del giocatore

Layer di Area2D / Area3D

Le Area usano lo stesso sistema Layer/Mask. In più, hanno due proprietà di attivazione:

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

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 — $15
Strumenti correlati: setup_collision set_physics_layers get_physics_layers get_collision_info add_raycast