Godot handles collision so you do not implement it from scratch. Learn the physics body types, collision shapes and layers, detecting overlaps with Area2D, and responding to hits.
Godot provides three physics body types for different needs. StaticBody is immovable (walls, floors). RigidBody is fully simulated by the engine (crates that tumble, balls that bounce) — you apply forces and let physics move it. CharacterBody is moved by your code via move_and_slide (players, enemies) so you keep precise control. Choosing the right body type for each object is the first physics decision.
Three body types — pick by how the object should move:
StaticBody2D never moves; things collide WITH it
-> walls, floors, platforms
RigidBody2D fully simulated by the engine (gravity, forces, bouncing)
-> crates, barrels, debris. You apply_force; physics moves it.
CharacterBody2D moved by YOUR code (move_and_slide), not the simulation
-> players, enemies. Precise control, still collides.
+ Area2D detects OVERLAPS without physical collision
-> triggers, pickups, hitboxes (next topics)
Right body per object: static world, simulated props, code-driven characters.Every physics body needs a CollisionShape (a rectangle, circle, or polygon) defining its bounds — this is the AABB/convex shape from the Game Physics course. Collision layers and masks control what collides with what: a body is on certain layers and scans certain layers, so you can make the player collide with walls but not with pickup triggers. Setting up layers correctly prevents a whole class of "why does this collide?" bugs.
Each body needs a CollisionShape2D (Rectangle/Circle/Polygon) = its bounds.
LAYERS + MASKS control WHO collides with WHOM:
a body is ON some layers (what it "is")
a body's MASK is what it SCANS for (what it "collides with")
Example setup:
Player layer = [player] mask = [world, enemy, pickup]
Wall layer = [world] mask = []
Coin layer = [pickup] mask = [] (Area2D detects the Player's mask)
-> player collides with walls + enemies, and can pick up coins,
but coins don't collide with each other. Layers prevent unwanted collisions.For triggers that detect overlap without blocking movement — a coin to collect, a damage zone, a checkpoint — you use Area2D and its signals. When another body enters the area, Godot emits body_entered with that body, and you react. This signal-driven overlap detection is how most gameplay interactions (pickups, hitboxes, zones) are wired, keeping them decoupled from movement.
extends Area2D # a coin: detects the player overlapping, no blocking
func _ready() -> void:
# connect the built-in signal to a handler
body_entered.connect(_on_body_entered)
func _on_body_entered(body: Node2D) -> void:
if body.is_in_group("player"): # only react to the player
body.add_coin()
queue_free() # remove the collected coin
# Area2D + body_entered = pickups, damage zones, checkpoints, hitboxes.
# it detects OVERLAP without physically blocking — the trigger pattern.When a CharacterBody moves with move_and_slide, you can inspect the collisions it produced to react — bounce off a surface, damage what you hit, detect landing on an enemy’s head. Godot reports each contact with its collider and normal (the collision normal from the physics course). Reading these results turns raw collision into gameplay, closing the loop between the engine’s physics and your game’s rules.
extends CharacterBody2D
func _physics_process(delta: float) -> void:
velocity.y += 980 * delta
move_and_slide()
# inspect the collisions move_and_slide produced this frame
for i in get_slide_collision_count():
var collision := get_slide_collision(i)
var other := collision.get_collider()
var normal := collision.get_normal() # the surface normal
if other.is_in_group("enemy") and normal.y < 0:
other.stomp() # landed on the enemy's head
velocity.y = -300 # bounce off it
# read collider + normal per contact -> turn physics into gameplay rules.