Quick answer: Layer is what the body IS. Mask is what it looks FOR. Bodies collide when A’s mask contains B’s layer (or vice versa). Name layers in Project Settings to keep them readable.

A shooter: bullets pass through walls but enemies bounce off them. Bullets collide with enemies but also with each other. Layer/mask confusion — the classic Godot physics gotcha.

Naming Layers

Project Settings → Layer Names → 2D / 3D Physics. Rename layer 1 to “World”, layer 2 to “Enemy”, layer 3 to “Bullet”, layer 4 to “Player”. Inspector now shows these names.

Layer/Mask Setup

BodyLayer (IS)Mask (COLLIDES WITH)
PlayerPlayerWorld, Enemy
EnemyEnemyWorld, Player, Bullet
BulletBulletWorld, Enemy
WallWorld(empty: walls don’t initiate)

Two bodies collide if either’s mask includes the other’s layer. Bullets pass each other because neither has Bullet in its mask.

Code Setup

var bullet_layer = 1 << 2   # layer 3 (0-indexed bit 2)
var world_layer = 1 << 0
var enemy_layer = 1 << 1

bullet.collision_layer = bullet_layer
bullet.collision_mask = world_layer | enemy_layer

Or use set_collision_layer_value / set_collision_mask_value:

bullet.set_collision_layer_value(3, true)
bullet.set_collision_mask_value(1, true)
bullet.set_collision_mask_value(2, true)

1-indexed bit numbers; clearer than bit shifts.

One-Way Logic

Often only one direction matters. Bullets check for enemies; enemies don’t need to check for bullets. If both check, you may double-handle events. Pick the direction that’s easier to filter.

Verifying

Fire bullets through wall: blocked. Fire at enemy: hits. Fire near another bullet: passes through. Enable Debug → Visible Collision Shapes to see bounding shapes in play.

“Layer is identity, mask is interest. Read it once carefully and the rest falls into place.”

Sketch a simple table of body types vs layers/masks before coding combat. Saves hours of ‘why didn’t this hit’ debugging later.