【Godot】CharacterBody2D Motion Mode: Choosing Between Top-Down and Side-Scroller

Created: 2025-06-20Last updated: 2025-12-16

Learn the differences between CharacterBody2D's Grounded and Floating modes. Discover optimal usage for top-down vs side-scrolling games, with code examples, common mistakes, and best practices.

Overview

When starting game development in Godot, CharacterBody2D is often the first choice for moving a player character. However, just calling move_and_slide() can result in strange behavior. "The jump feels wrong," "The character sticks to walls," "Why is my top-down character falling due to gravity?" Many of these issues stem from the CharacterBody2D Motion Mode setting.

This article explains the differences between CharacterBody2D's two main Motion Modes: Grounded and Floating. We'll cover which game genres each mode suits best and implementation best practices, with concrete code examples.

What is Motion Mode?

Motion Mode is the most important property determining how CharacterBody2D behaves in physical space—specifically how it interprets "floor," "wall," and "gravity." Configured from the CharacterBody2D properties in the inspector, it defines the foundation of character physics behavior.

ModeKey CharacteristicsOptimal Game Type
Grounded(Ground Contact Mode) Affected by gravity, clearly distinguishes floor/wall/ceiling. Useful floor detection APIs like is_on_floor() are available.Side-scrolling platformers, physics-based action games
Floating(Floating Mode) Ignores gravity, no concept of floor. Treats collisions from any direction equally as "walls."Top-down RPGs, shooters, spaceship games

Grounded Mode: For Platformers

Grounded, as the name suggests, is for characters "with feet on the ground." In genres like Mario or Metroidvania where gravity is fundamental to gameplay, this is almost always the necessary choice.

Key Features and Benefits

  • Automatic Gravity Application: Gravity defined in project settings affects the character. Simply adding gravity to velocity.y achieves natural falling.
  • Reliable Floor Detection: The is_on_floor() function accurately determines whether the character stands on a surface defined as "floor." This easily prevents infinite jumping in mid-air.
  • Convenient API Set: Functions like is_on_wall() (wall contact), is_on_ceiling() (ceiling contact), and get_floor_angle() (floor slope angle) accelerate platformer development.
  • Smooth Slope Handling: move_and_slide() automatically adjusts velocity for characters to smoothly traverse slopes.

Practical Code Example

Here's a more practical Grounded mode code incorporating basic movement, jumping, and wall jumping:

@export var speed = 300.0
@export var jump_velocity = -400.0
@export var wall_jump_velocity = Vector2(400.0, -300.0)

# Get gravity from project settings
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")

func _physics_process(delta):
    # Apply gravity
    if not is_on_floor():
        velocity.y += gravity * delta

    # Jump handling
    if Input.is_action_just_pressed("jump"):
        if is_on_floor():
            velocity.y = jump_velocity
        elif is_on_wall():
            # Wall jump in opposite direction character is facing
            var wall_normal = get_wall_normal()
            velocity.x = wall_normal.x * wall_jump_velocity.x
            velocity.y = wall_jump_velocity.y

    # Horizontal movement
    var direction = Input.get_axis("move_left", "move_right")
    velocity.x = direction * speed

    move_and_slide()

Floating Mode: For Top-Down Games

Floating mode frees characters from gravity. It's ideal for top-down RPGs like The Legend of Zelda or omnidirectional shooters like Vampire Survivors, where characters move freely around the map.

Key Features and Benefits

  • Freedom from Gravity: Gravity isn't automatically applied in this mode. If velocity is Vector2.ZERO, the character stays stationary.
  • No Floor Concept: is_on_floor() always returns false. All collisions are treated equally regardless of direction.
  • Simple Movement Logic: Without needing to consider gravity or floor state, movement logic becomes very simple.

Practical Code Example

Here's Floating mode code implementing 8-directional movement and facing the mouse cursor:

@export var speed = 400.0

func _physics_process(delta):
    # Get normalized movement vector from input
    var direction = Input.get_vector("move_left", "move_right", "move_up", "move_down")
    velocity = direction * speed

    move_and_slide()

    # Face the mouse cursor
    look_at(get_global_mouse_position())

Advanced: Smooth Movement with Inertia

For spaceship games or characters sliding on ice—implementing inertia (continuing to slide after releasing input)—gradually decay velocity instead of zeroing it immediately:

@export var speed = 400.0
@export var friction = 0.05  # Friction coefficient (closer to 0 = more slippery)

func _physics_process(delta):
    var direction = Input.get_vector("move_left", "move_right", "move_up", "move_down")

    if direction != Vector2.ZERO:
        # Accelerate when there's input
        velocity = velocity.lerp(direction * speed, 0.1)
    else:
        # Gradually decelerate when no input (inertia)
        velocity = velocity.lerp(Vector2.ZERO, friction)

    move_and_slide()

Adjusting the friction value lets you express various textures from slippery ice to grippy ground.

Comparison with Alternative Patterns

For simple top-down movement, using Area2D instead of CharacterBody2D is another approach. Area2D doesn't perform physics collision, making it very lightweight. It may suit objects like enemy bullets that don't need to bounce off walls. However, for players and enemies requiring wall collision response, CharacterBody2D's Floating mode is the robust, optimal choice.


Common Mistakes and Best Practices

Here are common pitfalls when working with Motion Mode and best practices to avoid them:

Common MistakeBest Practice
Forgetting to manually add gravity in Grounded modeAlways add gravity to velocity.y when is_on_floor() is false in _physics_process.
Using Grounded mode for top-down gamesChoose Floating mode for games that don't need gravity. Code becomes simpler and prevents unintended falling.
Misunderstanding when to check is_on_floor()is_on_floor() is updated by move_and_slide() execution. This means it shows the ground contact state from the previous frame's move_and_slide(). The common pattern is to check is_on_floor() before move_and_slide() when detecting jump input, then call move_and_slide() afterward.
Excessive performance concernsmove_and_slide() is optimized. Unless you're moving hundreds of characters simultaneously, performance is rarely an issue. First, write code that works correctly.

Summary

CharacterBody2D's Motion Mode isn't just a configuration option—it's a design decision that defines your game's physical foundation.

  • For side-scrolling and platformers where gravity and floors play important roles → Grounded Mode
  • For top-down RPGs and shooters where you want free movement → Floating Mode

Making this choice correctly from the start prevents many character control issues and streamlines development.

Next Steps

You've mastered CharacterBody2D basics with this article. To deepen your understanding, explore these topics:

  • CharacterBody3D: Character control in 3D space. Basic concepts are shared with 2D.
  • up_direction Property: How to change gravity direction and implement special movement like walking on walls.
  • move_and_collide: A lower-level movement function than move_and_slide(). Use when you need more detailed control over collision information.