Por qué importan las capas de colisión

Las capas de colisión son la base de todas las interacciones físicas en Godot 4 — movimiento, detección de impactos, raycasting, disparadores de Area y mucho más. Entender la diferencia entre Layer y Mask es crucial, y malinterpretarla es uno de los tropiezos más comunes tanto para principiantes como para desarrolladores experimentados.

Layer vs Mask — El modelo mental

Cada objeto físico en Godot tiene dos propiedades de máscara de bits:

Regla clave

A colisiona con B cuando la máscara de A incluye la capa de B O la máscara de B incluye la capa de A. Basta con que uno de los lados "vea" al otro para que se produzca una colisión.

Nombrar las capas en la configuración del proyecto

Antes de escribir cualquier código, ponles nombre a tus capas. Esto hace que el Inspector sea mucho más fácil de usar y evita confusiones a medida que tu proyecto crece.

Configuración del proyecto > Nombres de capas > Física 2D (o Física 3D):

Capa n.º Nombre Propósito
1PlayerEl personaje del jugador
2EnemyTodos los cuerpos enemigos
3EnvironmentMuros, suelos, plataformas
4ProjectileBalas, flechas, hechizos
5PickupObjetos, monedas, botiquines
6TriggerSensores, zonas de aparición, puntos de control

Configurar capas por código (GDScript)

Godot 4 ofrece dos enfoques — la API basada en valores (recomendada) y la asignación directa de la máscara 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)

Truco de la máscara de bits

Los números de capa empiezan en 1 en set_collision_layer_value(), pero la máscara de bits subyacente empieza en 0. Capa 1 = bit 0 = valor 1, Capa 2 = bit 1 = valor 2, Capa 3 = bit 2 = valor 4. Ante la duda, usa la API basada en valores para evitar errores.

Esquemas de capas comunes

Plataformas / Scroll lateral

Objeto Layer Mask Explicación
Player12, 3, 5, 6Detecta enemigos, entorno, objetos y disparadores
Enemy21, 3Detecta al jugador y el entorno
Environment3Pasivo — detectado por otros
Projectile42, 3Golpea a enemigos y muros
Pickup5Pasivo — el jugador lo detecta
Trigger61Detecta solo al jugador

Cenital / Roguelike

Objeto Layer Mask Explicación
Player12, 3, 5, 6Detecta enemigos, muros, NPCs y sensores
Enemy21, 3Detecta al jugador y los muros
Wall3Pasivo
Bullet41, 2, 3Golpea al jugador, a los enemigos y a los muros
NPC53Colisiona solo con los muros
Sensor61Detecta la entrada del jugador

Capas de Area2D / Area3D

Las Areas usan el mismo sistema de Layer/Mask. Además, tienen dos propiedades de conmutación:

Señales: area_entered vs body_entered

body_entered se dispara cuando un PhysicsBody (CharacterBody, RigidBody, StaticBody) entra en la Area. area_entered se dispara cuando entra otra Area. Asegúrate de conectar la señal correcta según tu caso de 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()

Máscara de colisión de RayCast

Los nodos RayCast solo tienen Mask (sin Layer) porque son detectores, no cuerpos físicos. Configura la máscara para filtrar lo que el rayo puede golpear:

# 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

Ejemplo práctico: Player – Enemy – Projectile

Aquí tienes una configuración de capas completa para un juego de acción típico. Los comentarios muestran el razonamiento detrás de cada decisión:

# 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

Consejo: prevención del fuego amigo

Fíjate en que las balas del jugador enmascaran la capa 2 (Enemy) pero no la capa 1 (Player), y las balas enemigas enmascaran la capa 1 (Player) pero no la capa 2 (Enemy). Así es como se evita el fuego amigo puramente mediante la configuración de capas — sin necesidad de código.

Consejos de depuración

Cambios de migración de 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)
El parámetro bit empezaba en 0 El parámetro layer empieza en 1
20 capas disponibles 32 capas disponibles

Trampa de la migración

Si estás portando un proyecto de Godot 3, recuerda que set_collision_layer_bit(0, true) se convierte en set_collision_layer_value(1, true). El índice se desplaza en +1. Si se te pasa esto, todas tus capas quedarán desplazadas en uno.

Errores comunes

1. Olvidar configurar la Mask

Tu objeto tiene una Layer pero la Mask está vacía (todo ceros). El objeto existe en el mundo físico pero no detecta nada. Otros objetos con máscaras coincidentes seguirán detectándolo a él, pero move_and_slide() en este objeto lo atravesará todo.

2. Confundir Layer con Mask

Poner la Layer del jugador en 2 (Enemy) en lugar de su Mask. Ahora el jugador es un enemigo a ojos del motor de física. Recuerda siempre: Layer = lo que soy, Mask = lo que escaneo.

3. Usar valores de máscara de bits en lugar de números de capa

Escribir set_collision_layer_value(4, true) pensando que configura el valor de máscara de bits 4 (capas 1+2). En realidad, activa la capa 4. La API basada en valores toma números de capa, no valores de bit.

4. Detección unidireccional cuando se espera bidireccional

El objeto A enmascara la capa de B, pero B no enmascara la capa de A. move_and_slide() en A colisionará con B, pero move_and_slide() en B atravesará a A. Para que dos nodos CharacterBody se bloqueen mutuamente, ambos necesitan tener la capa del otro en su máscara.

Automatiza la configuración de física con Godot MCP Pro

Deja de activar casillas de capas manualmente. Deja que la IA configure toda tu colisión en segundos — incluyendo el nombrado de capas, la asignación de máscaras y la adición de raycasts.

Consigue Godot MCP Pro — $15
Herramientas relacionadas: setup_collision set_physics_layers get_physics_layers get_collision_info add_raycast