Physics & Collision
Godot Fundamentals
Chapter 6 · Physics & Collision
Every movement script so far has moved straight through walls, floors, and anything else in its path —
both Chapter 4 and Chapter 5 flagged this openly as unfinished business. This chapter replaces raw
position changes with Godot's own real physics nodes, which know about the rest of the game
world and actually respond to it.
Three Physics Node Types
Godot splits "something that participates in physics" into three different node types, each suited to a different job.
| Node | Who's in control | Typical use |
|---|---|---|
| CharacterBody2D | Your script, fully — you set velocity and call a move function every frame | A player character, an enemy with hand-scripted movement |
| RigidBody2D | Godot's own physics engine — gravity, forces, and collisions are simulated automatically | A ball, a crate, debris — anything that should behave like a real physical object |
| Area2D | Neither — it detects overlap but applies no physical collision response at all | A pickup, a damage zone, a trigger that opens a door |
CollisionShape2D — Required for All Three
None of the three node types above detect anything on their own — each needs a CollisionShape2D
child, with an actual Shape resource assigned to its own shape property (a
RectangleShape2D, a CircleShape2D, etc.).
Shape property must be set to a real shape resource, or the whole node is
invisible to physics regardless of how it's positioned.
CharacterBody2D — Scripted Movement That Respects the World
A CharacterBody2D has a built-in velocity property (a Vector2), and a built-in
move_and_slide() method that actually moves the node by that velocity, sliding smoothly along any
wall or floor it collides with instead of passing through it.
move_and_slide() takes no arguments now — in Godot 3,
it took a velocity parameter and returned the resulting velocity, which you had to store back yourself.
Godot 4 simplified this: set the node's own built-in velocity property first, then call
move_and_slide() with no arguments at all — it reads and updates velocity
automatically. A lot of tutorials still online use the old Godot 3 call shape; if code from one of those
throws an "too many arguments" error, this is almost always why.
For a platformer, gravity is applied by hand each frame, and is_on_floor() reports whether
the body is currently resting on the ground:
Area2D — Detecting Overlap Without Physical Collision
Unlike CharacterBody2D or RigidBody2D, an Area2D doesn't stop
anything from passing through it — it simply notices when something does, and emits a signal.
The connection pattern here is exactly Chapter 3's own custom-signal approach — body_entered
is simply a signal Godot's built-in Area2D already declares for you, connected and used the same
way as the custom coin_collected signal from that chapter.
is_in_group("player") checks whether a node was tagged into
a named group (set in the editor's Node panel, under "Groups"). It's a lightweight way to ask "is this
specifically the player?" without the Area2D needing a direct reference to the player scene at all —
another small instance of the same decoupling idea from earlier chapters.
body_entered never fires — the most common cause is a
collision layer/mask mismatch: the Area2D's own collision_mask has to include
whatever layer the other body is actually on. Both nodes also need a real Shape assigned (see above), and
the Area2D's own monitoring property has to be left enabled.
RigidBody2D — Letting the Engine Take Over
A RigidBody2D is deliberately not driven by setting position or
velocity directly each frame — Godot's own physics engine already applies gravity and resolves
collisions on its own. Instead, you nudge it with forces or impulses.
This course focuses mainly on CharacterBody2D, since a hand-controlled player is this
course's own central goal — RigidBody2D is worth knowing exists for anything that should behave
like a genuinely physical object rather than a directly-controlled character.
Coding Challenges
move_and_slide()
controller from this chapter and confirm the character stops at the walls instead of passing through.
is_on_floor() to
only allow jumping while grounded. Confirm the character can't "double jump" by holding the jump key
in mid-air.
"player" group. Connect the coin's body_entered signal so that walking into
it prints "Coin collected!" and removes the coin from the scene.
Quick Reference — Physics & Collision
- CharacterBody2D — you control velocity and call
move_and_slide(); respects walls/floors - RigidBody2D — the engine simulates it; nudge with
apply_central_impulse()/forces - Area2D — detects overlap only, no physical collision response; used for triggers/pickups
- Every one of the three needs a CollisionShape2D child with a real Shape assigned
- Godot 4:
move_and_slide()takes no arguments — setvelocityfirst, it updates automatically is_on_floor()— true only while a CharacterBody2D is resting on the ground- Area2D's
body_entered(body)signal — connect it exactly like a custom signal (Chapter 3)