Skip to content
Build a world

Godot Collision Layers and Masks Explained Without the Headache

Learn Godot collision layers and masks with a practical 2D setup. Understand what objects are, what they detect, and how to debug collisions that refuse to fire.

On this page

When a player passes through a wall or a pickup never fires its signal, check the collision shapes and filtering separately. This guide explains what layers and masks control, then walks through player, enemy, pickup, and projectile setups.

The practical rule is this: layer means what I am, and mask means what I look for. Once that sentence sticks, Godot collision setup becomes much calmer. If you want the larger body-type overview first, open the Godot Physics guide or the longer Godot physics tutorial.

Layer Means What I Am

Every physics object in Godot can belong to one or more collision layers. Think of layers as labels the physics server can check quickly. A player might be on the Player layer. Enemies might be on the Enemy layer. Walls might be on the World layer.

  • Layer 1 - World: floors, walls, one-way platforms, and tile collisions.
  • Layer 2 - Player: the player character and sometimes player sensors.
  • Layer 3 - Enemy: enemies, enemy hurtboxes, and enemy bodies.
  • Layer 4 - Pickup: coins, health, keys, and level triggers.
  • Layer 5 - Projectile: bullets, arrows, thrown objects, and temporary hits.

You can name these layers in Project Settings so the Inspector shows readable labels instead of anonymous numbers. Do that early. Future-you will not remember that layer 7 meant hazard sensors.

Mask Means What I Detect

The collision mask is the other half. It tells the object which layers it cares about. A player body usually detects World and Enemy. A pickup Area2D usually detects Player. A player bullet might detect Enemy and World, but not Player or Pickup.

gdscript
# Example: configure a pickup Area2D in code.
# In the editor, naming layers is easier. This shows the idea.
extends Area2D

const PLAYER_LAYER := 2

func _ready() -> void:
    collision_layer = 1 << 3 # Pickup layer, if using layer 4
    collision_mask = 1 << (PLAYER_LAYER - 1)
    body_entered.connect(_on_body_entered)

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

Most of the time, set layers in the Inspector instead of code. Code is useful for spawned objects, temporary sensors, or tests, but visual setup is easier to audit.

A Simple 2D Prototype Setup

For a small 2D prototype, start with fewer layers than you think you need. Add more only when two object types need different rules.

  • Player CharacterBody2D: layer Player, mask World + Enemy + Pickup.
  • Enemy CharacterBody2D: layer Enemy, mask World + Player.
  • Coin Area2D: layer Pickup, mask Player.
  • Wall StaticBody2D: layer World, mask usually empty unless it needs detection.
  • Player Bullet Area2D: layer Projectile, mask Enemy + World.

This pairs well with the 2D platformer tutorial: make the player, coin, and level as separate scenes, then assign layers as part of each scene's setup.

Debugging Collisions That Do Not Fire

When a signal does not fire, do not rewrite the script first. Debug the physical setup. Godot collision bugs are often missing shapes, disabled monitoring, or mismatched masks.

  • Turn on Debug > Visible Collision Shapes and confirm the shapes are where you think they are.
  • Check that the Area2D has Monitoring enabled.
  • Check that the target object is on a layer included in the detector's mask.
  • Make sure you connected body_entered for physics bodies and area_entered for areas.
  • Use groups like player or enemy after detection, not as a replacement for collision rules.

Name Your Layers in Project Settings

Open Project Settings and find Layer Names → 2D Physics. Name the entries from Layer 1 to Layer 32 as needed. The following examples use an alternative layout to the pickup example above: Player is now layer 1 and World is layer 4. Use this layout for the remaining code examples, or adjust their layer numbers to match your project.

  • 1: player: the character the person controls
  • 2: enemy: anything that can damage the player
  • 3: pickup: coins, health, keys
  • 4: world: floors, walls, platforms
  • 5: hazard: spikes, water, kill zones

The names are project-wide and appear as checkbox labels in the Inspector, so every collision decision after this reads in English instead of bit positions. There is a separate list for 3D Physics; naming both is worth the two minutes.

Set Layers and Masks in Code

The Inspector stores collision_layer and collision_mask as integers, both initially 1 on CollisionObject2D. Godot’s value helpers let you change one layer using its Inspector number instead of calculating the raw bitmask.

gdscript
extends CharacterBody2D

func _ready() -> void:
    # Layer numbers are 1-based (1 to 32), matching the Inspector labels.
    set_collision_layer_value(1, true)   # I am on "player"
    set_collision_mask_value(3, true)    # I scan "pickup"
    set_collision_mask_value(4, true)    # I scan "world"

    # Reading it back is just as explicit.
    if get_collision_mask_value(2):
        print("This body is currently scanning for enemies")

Raycasts and ShapeCasts Use Masks Too

RayCast2D has a collision_mask that selects the layers it can hit. It has no collision layer of its own. RayCast3D, ShapeCast2D/3D, and direct physics queries also use masks to filter potential hits.

gdscript
@onready var ground_check: RayCast2D = $GroundCheck

func _ready() -> void:
    ground_check.set_collision_mask_value(4, true)  # only "world"

    # A ray ignores Area2D by default. If you are raycasting for
    # triggers, hitboxes or pickups, you must opt in.
    ground_check.collide_with_areas = true

    # Never let the ray detect the body that owns it.
    ground_check.add_exception(self)

The Same Rules in 3D

Nothing conceptually changes in 3D. CharacterBody3D, RigidBody3D, StaticBody3D and Area3D all inherit from CollisionObject3D, which exposes the identical collision_layer, collision_mask and set_collision_layer_value() API. The only differences are practical:

  • 3D layer names live in a separate list: Project Settings → Layer Names → 3D Physics.
  • Godot 4 uses Jolt as the default 3D physics engine, so tuning values do not transfer from a 2D prototype.
  • The signals are the same names with 3D types: body_entered(body: Node3D) and area_entered(area: Area3D).

Collision Exceptions and One-Way Collision

Layers and masks define broad collision rules. For a specific exception, such as a body-based projectile ignoring its shooter, use collision exceptions. One-way collision shapes handle platforms that a character can jump through from below.

gdscript
# One-off: this projectile ignores its shooter, nobody else.
func setup(shooter: PhysicsBody2D) -> void:
    add_collision_exception_with(shooter)

# Jump-through platform: set on the CollisionShape2D, not the body.
@onready var shape: CollisionShape2D = $CollisionShape2D

func _ready() -> void:
    shape.one_way_collision = true
    shape.one_way_collision_margin = 1.0

The Mental Model to Keep

Test one relationship at a time: first the player against the world, then the pickup detecting the player. Confirm the detector, its mask, and the target layer before adding enemies or projectiles.

Frequently asked questions

What is the difference between collision layer and collision mask in Godot?
A collision layer says what an object is. A collision mask says what that object checks for. For example, a bullet can be on the Bullet layer while its mask checks only the Enemy and Wall layers.
Why is my Area2D not detecting collisions in Godot?
Check that both objects have collision shapes, monitoring is enabled on the Area2D, the target is on a layer included in the Area2D mask, and the signal is connected.
Should players and enemies be on separate collision layers?
Usually yes. Separate layers make it easier to control which objects collide or trigger detection, especially once bullets, pickups, hazards, and sensors enter the project.
Verification notes

Sources and revision context

Updated September 8, 2026. Clarified the separate layer layouts used by the examples and how masks select collisions. This revision does not establish a full tutorial runtime test.