move_and_slide()
Default choice for platformers, top-down movement, slopes, and walls.
- Updates
is_on_floor()andis_on_wall() - Slides along surfaces automatically
- Works with the built-in
velocityproperty
Physics Guide. Choose the right body type, collision layer, and movement API before tuning feel.
Map familiar Unity Rigidbody and trigger habits to Godot's body types, then practice the movement pattern that matches your game object.
Pick the body by ownership of motion first: you drive it, physics drives it, it blocks, or it only detects.
Think of this as "Rigidbody2D plus CharacterController behavior." You set velocity, then call move_and_slide().
move_and_slide()Default choice for platformers, top-down movement, slopes, and walls.
is_on_floor() and is_on_wall()velocity propertymove_and_collide()Use when you need custom collision response.
KinematicCollision2Dextends CharacterBody2D
@export var speed := 300.0
@export var jump_velocity := -420.0
var gravity: float = ProjectSettings.get_setting("physics/2d/default_gravity")
func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity.y += gravity * delta
var direction := Input.get_axis("move_left", "move_right")
velocity.x = direction * speed
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = jump_velocity
move_and_slide()Create a CharacterBody2D with a CollisionShape2D and Sprite2D. Add Input Map actions for move_left, move_right, and jump, then test floor and wall behavior.
This maps closely to Rigidbody2D. Apply impulses and forces
instead of writing transform position directly.
extends RigidBody2D
@export var thrust := 420.0
@export var launch_impulse := Vector2(180.0, -260.0)
func _ready() -> void:
apply_central_impulse(launch_impulse)
func _physics_process(_delta: float) -> void:
if Input.is_action_pressed("thrust"):
var force := Vector2.UP.rotated(rotation) * thrust
apply_central_force(force)If you set position or linear_velocity every frame,
collision can look jittery or unfair. Use impulses, forces, gravity scale,
damping, or the custom integrator when you need control.
This is like a Collider2D without a Rigidbody. It blocks physics bodies but should not be animated every frame.
extends AnimatableBody2D
@export var travel := 220.0
@export var speed := 1.5
var start_position: Vector2
func _ready() -> void:
start_position = position
func _physics_process(_delta: float) -> void:
var t := Time.get_ticks_msec() * 0.001 * speed
position.x = start_position.x + sin(t) * travelThis behaves like a Collider2D with isTrigger enabled. It detects
bodies and areas but does not block movement.
extends Area2D
func _ready() -> void:
body_entered.connect(_on_body_entered)
func _on_body_entered(body: Node2D) -> void:
if not body.is_in_group("player"):
return
body.add_coin()
queue_free()extends Area2D
@export var damage_per_second := 10.0
func _physics_process(delta: float) -> void:
for body in get_overlapping_bodies():
if body.has_method("take_damage"):
body.take_damage(damage_per_second * delta)Before jumping to the next page, turn the idea into one tiny scene or script. That is where the Godot habit sticks.
Rigidbody habits do not map one-to-one to CharacterBody2D.
Character movement is less prebuilt, but more explicit and scriptable.
Use CharacterBody for controlled actors, RigidBody for simulation, Area for detection.
Build a collision layer chart for player, enemy, world, trigger, and pickup.