Physics — Bodies, Collision, Jolt
StaticBody3D, RigidBody3D, CharacterBody3D, Area3D — and why physics got faster in 4.6.
As of Godot 4.6, Jolt became the default physics engine for 3D — a high-performance engine used in Death Stranding 2 and other AAA games. The old Godot Physics remains available as an option and continues to be the default for 2D.
This means: predictable, scalable 3D physics out of the box. No need to integrate any third-party engines.
Four body classes
Nodes inheriting from CollisionObject3D that form a physics object:
| Node | When |
|---|---|
| StaticBody3D | Doesn’t move. Walls, floors, static architecture. |
| AnimatableBody3D | Moves via animation or script. Pushes RigidBody3D. Equivalent to Unity’s Kinematic Rigidbody. |
| RigidBody3D | Full dynamics — gravity, forces, impulses, collisions with response. |
| CharacterBody3D | Kinematics for a character: you set velocity, the engine moves it accounting for collisions. The only node with move_and_slide(). |
Also:
- Area3D — an invisible region with
body_entered/area_enteredtriggers. Equivalent to a Unity Collider withisTrigger=true. - PhysicalBone3D — for ragdolls inside Skeleton3D.
- SoftBody3D — soft bodies (cloth, flags, simple jelly-like objects). Uses mesh-based soft-body simulation; works with both Godot Physics and Jolt (with some limitations).
CollisionShape3D — the shape for physics
Unlike Unity, where a collider is a component on the same GameObject, in Godot CollisionShape3D
is a separate child node. It has a shape: Shape3D property — a resource that describes the shape:
RigidBody3D (Player)
├── MeshInstance3D (visual mesh)
└── CollisionShape3D
└── shape: CapsuleShape3D (height=2, radius=0.4)
Types of Shape3D:
- BoxShape3D, SphereShape3D, CapsuleShape3D, CylinderShape3D — primitives. Cheap.
- ConvexPolygonShape3D — a convex mesh. For dynamic objects with complex shapes.
- ConcavePolygonShape3D — an arbitrary mesh (triangulated). Static only.
- HeightMapShape3D — terrain from a 2D heightmap.
Just add several child CollisionShape3D nodes — they all become shapes of that body. Convenient for compound colliders (for example, a car: chassis + bumper).
CharacterBody3D — the go-to node for platformers/FPS
CharacterBody3D holds velocity: Vector3 and the move_and_slide() method, which tries
to move the body by velocity * delta while accounting for collisions: it stops, slides along walls,
descends slopes, and steps up onto stairs.
extends CharacterBody3D
@export var speed: float = 5.0
@export var jump_velocity: float = 6.0
func _physics_process(delta: float) -> void:
# Gravity — from project settings (Project Settings → Physics → 3D → Default Gravity)
# get_gravity() returns Vector3(0, -9.8, 0) by default
if not is_on_floor():
velocity += get_gravity() * delta
# Jump
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = jump_velocity
# Horizontal movement
var input_dir := Input.get_vector("move_left", "move_right", "move_forward", "move_back")
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * speed
velocity.z = direction.z * speed
else:
velocity.x = move_toward(velocity.x, 0, speed)
velocity.z = move_toward(velocity.z, 0, speed)
move_and_slide()
Useful CharacterBody3D methods and properties:
is_on_floor(),is_on_wall(),is_on_ceiling()— simple contact checks.get_floor_normal()— the normal of the floor you’re standing on.floor_max_angle— the maximum slope angle still considered a floor (45° by default).floor_snap_length— how deeply to “snap” to the floor when going down a slope (avoids bouncing on descents).get_slide_collision_count()+get_slide_collision(i)— details of collisions during this tick.
Custom 3D without an engine: you compute next_pos = pos + velocity * dt and handle collisions
by hand. Hard and buggy.
CharacterController.Move(motion) ↔ move_and_slide(). CharacterBody3D is more powerful: it
automatically slides along walls, steps up onto stairs, and snaps to slopes — all configured
via flags.
RigidBody3D — dynamics
For physics objects that react to forces (a ball, a crate, a dropped item):
extends RigidBody3D
func _ready() -> void:
mass = 2.0
linear_damp = 0.5
func explode_push(direction: Vector3, force: float) -> void:
apply_central_impulse(direction * force)
Methods:
apply_force(force: Vector3, position: Vector3 = Vector3.ZERO)— a continuous force (in_physics_process).apply_central_force(force)— a force at the center of mass.apply_impulse(impulse, position)— an instantaneous impulse.apply_central_impulse(impulse)— an instantaneous impulse at the center of mass.apply_torque_impulse(impulse)— torque.
Properties:
mass: float— mass.gravity_scale: float— gravity multiplier (0 = none, 1 = normal).linear_damp/angular_damp— damping.freeze/freeze_mode— freeze.lock_rotation: bool— disable rotation.continuous_cd: CCDMode—DISABLED/CAST_RAY/CAST_SHAPE— for fast-moving bodies, to prevent tunneling.
Area3D — triggers
Area3D is not a physics body, but it emits signals when it overlaps with other CollisionObject3D nodes:
extends Area3D
func _ready() -> void:
body_entered.connect(_on_body_entered)
area_entered.connect(_on_area_entered)
func _on_body_entered(body: Node3D) -> void:
if body.is_in_group("player"):
print("Player picked up coin")
queue_free()
func _on_area_entered(area: Area3D) -> void:
print("Another area overlapped: ", area.name)
Area3D signals:
body_entered(body)/body_exited(body)— a physics body entered/exited.area_entered(area)/area_exited(area)— another Area3D.body_shape_entered,area_shape_entered— detailed versions with shape indices.
Collision Layers and Masks
Each CollisionObject3D has two bitfields:
- Collision Layer — which layers this object is on.
- Collision Mask — which layers this object scans (overlaps with / reacts to).
For A to notice B: A’s mask must contain B’s layer(s). For the interaction to be two-way, B’s mask must also contain A’s layer.
Layer names are configured in Project Settings → Layer Names → 3D Physics.
In Unity the layer matrix is bidirectional. In Godot there are two independent bitfields per object. This gives more flexibility (for example, “the bullet sees the enemy but not vice versa”), but requires care.
Jolt vs Godot Physics
As of 4.6, Jolt is the default for new 3D projects. Existing projects don’t switch automatically — set it in Project Settings → Physics → 3D → Physics Engine.
| Parameter | Godot Physics | Jolt |
|---|---|---|
| Performance with 1000+ bodies | Degrades | Stable |
| Stacking (stacks of crates) | Can sag | Better |
| CCD (continuous) | Yes | Yes, better |
| Double-sided thin colliders | Occasional bugs | Stable |
| Joints | Basic | Full set |
If you already have a working project on Godot Physics — stay on it. For a new one — Jolt.
In the next chapter — the camera and Phantom Camera.