Overview
When trying to move characters in Godot, you'll encounter two similarly named functions: move_and_slide() and move_toward(). Both are for moving objects, but their underlying mechanisms and optimal use cases are completely different.
Understanding the differences between these two is crucial for implementing smooth physics-based movement and game logic that behaves exactly as intended (like knockback).

move_and_slide(): Citizen of the Physics World
move_and_slide() is a sophisticated movement method exclusive to nodes controlled by the physics engine, like CharacterBody2D and CharacterBody3D. Simply calling it makes Godot's physics engine perform complex calculations behind the scenes, achieving very natural movement.
Key Features:
- Physics-Based Collision Handling: Works closely with Godot's physics engine, automatically detecting and responding to collisions with other physics bodies and tilemaps. Prevents objects from overlapping.
- Smooth Movement on Walls and Slopes: When hitting a wall, the object doesn't stop but "slides" along it. This dramatically improves controls, especially in narrow passages. Combined with the
up_directionproperty, it enables smooth movement up and down slopes. - Moving Platform Support:
move_and_slide()automatically detects moving platforms and adjustsvelocityso characters move along with the platform while standing on it. - Integration with
velocityProperty: This function takes the node'svelocityproperty as input and executes movement. Importantly, it returns the velocity after it's been modified by collisions.
Basic Usage:
The standard practice is to use move_and_slide() inside _physics_process(delta), which is called every physics frame.
extends CharacterBody2D
const SPEED = 300.0
const JUMP_VELOCITY = -400.0
# Get gravity from project settings (default: 980)
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
func _physics_process(delta):
# Apply gravity acceleration
if not is_on_floor():
velocity.y += gravity * delta
# Jump processing
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Get left/right input direction
var direction = Input.get_axis("ui_left", "ui_right")
velocity.x = direction * SPEED
# Let physics engine handle movement and collision
move_and_slide()
move_toward(): Simple Mathematical Interpolation
move_toward() is a general-purpose mathematical function built into Godot. It has nothing to do with the physics engine—it linearly changes a value (number, vector, etc.) toward a target by a specified amount.
Key Features:
- Completely Ignores Physics: This function doesn't detect collisions. It only performs value calculations. If you directly modify an object's position with this function, it may pass through walls.
- Constant Rate of Change: Regardless of current position or distance to target, it always changes the value by the specified constant step (the
deltaargument). This makes constant-speed movement or changes easy to achieve. - High Versatility: Usable with various data types beyond
Vector2andVector3positions—float(HP, experience),Color(fade in/out),Transform2D, and more.
Primary Uses:
- Moving Non-Physics Objects: UI elements, background objects, cameras—objects that don't need collision.
- Value Smoothing: Smoothing out rapidly changing values. For example, slightly delaying camera following for a smoother look.
- State Change Effects: HP bars decreasing smoothly, character colors gradually changing.
- Physics Calculation Assistance: When directly manipulating physics properties like
velocity, used to smoothly change values toward a target (e.g.,Vector2.ZERO). Recovery from knockback is a classic example.
# Example 1: Move UI element to target position
func _process(delta):
var target_position = get_viewport_rect().size / 2
# Move toward center at 200 pixels per second
position = position.move_toward(target_position, 200 * delta)
# Example 2: Enemy character follows player
func _physics_process(delta):
# player_node is reference to player
if player_node:
var direction = global_position.direction_to(player_node.global_position)
velocity = direction * ENEMY_SPEED
move_and_slide()
Practical Example: Knockback with State Management
The best example of move_and_slide and move_toward working together is "knockback." Here, we incorporate simple state machine concepts for a more robust implementation.
extends CharacterBody2D
const SPEED = 300.0
const JUMP_VELOCITY = -400.0
const KNOCKBACK_FRICTION = 500.0
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
enum State { MOVE, KNOCKBACK }
var current_state = State.MOVE
var knockback_vector = Vector2.ZERO
func _physics_process(delta):
match current_state:
State.MOVE:
move_state(delta)
State.KNOCKBACK:
knockback_state(delta)
# Normal movement state
func move_state(delta):
if not is_on_floor():
velocity.y += gravity * delta
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
var direction = Input.get_axis("ui_left", "ui_right")
velocity.x = direction * SPEED
move_and_slide()
# Knockback state
func knockback_state(delta):
# Overwrite velocity with knockback vector
velocity = knockback_vector
move_and_slide() # Let physics engine handle collision
# Use move_toward to gradually reduce knockback force to 0 (deceleration)
knockback_vector = knockback_vector.move_toward(Vector2.ZERO, KNOCKBACK_FRICTION * delta)
# Return to normal state when knockback force is nearly 0
if knockback_vector.is_equal_approx(Vector2.ZERO):
current_state = State.MOVE
# Call this function from external sources (e.g., enemy attack hitbox area)
func apply_knockback(direction: Vector2, power: float):
current_state = State.KNOCKBACK
knockback_vector = direction.normalized() * power
In this implementation, current_state clearly separates character behavior. In State.MOVE, player input is accepted; in State.KNOCKBACK, input is ignored and movement is forced. The key point is using move_toward within knockback_state to smoothly decay knockback_vector. This achieves natural recovery from knockback.
Common Mistakes and Best Practices
Here's a summary of common pitfalls when using these functions and best practices to avoid them.
| Function | Common Mistake | Best Practice |
|---|---|---|
move_and_slide() | Calling it inside _process (not synchronized with physics) | Always call it inside _physics_process. Physics calculations run at a fixed frame rate, so synchronization is essential. |
Trying to change position directly instead of setting velocity | With CharacterBody, the principle is to always control movement through the velocity property, not direct position manipulation. | |
move_toward() | Using it directly for CharacterBody movement, causing wall pass-through | Don't use for objects that need physical collision. Use as assistance for changing velocity values, or limit to non-physics objects like UI. |
Forgetting to multiply by delta (frame-rate dependent movement) | Multiply the change amount by delta like move_toward(target, speed * delta) to maintain constant speed regardless of frame rate. | |
Not understanding the difference from lerp | move_toward is constant speed; lerp decreases change amount with distance (easing). Use move_toward for hard stops, lerp for smooth stops. |
Performance and Alternatives
-
Cost of
move_and_slide(): This function performs multiple raycasts and collision checks internally, making it not a lightweight operation. Placing manyCharacterBodynodes in a scene can impact performance. Optimization like disabling_physics_processitself (set_physics_process(false)) for distant enemies that don't need to move is effective. -
move_toward()vsTween: For UI animation and simple object movement, theTweennode is also a very powerful option. Whilemove_towardcontrols linear movement in code,Tweenallows setting diverse easing asynchronously from the inspector. UseTweenfor complex effects and sequences,move_towardfor simple interpolation and physics property control.
Summary
move_and_slide() and move_toward() are completely different tools, each with its own philosophy.
move_and_slide(): A high-level movement method forCharacterBodythat follows physics world laws, considering collision and gravity.move_toward(): A mathematical interpolation tool that ignores physics and moves values toward targets. An unsung hero that handles everything fromvelocitycontrol to UI animation.
By deeply understanding these two characteristics and combining them appropriately—like in knockback processing—your game characters will move significantly more lifelike and exactly as intended.