Lesson 4: Player Character and Movement System
In Lesson 3 you set up your art pipeline and folder structure. Now you will put a playable character in the game and give it responsive 2D movement. This lesson focuses on one goal: a character that moves, jumps (if your design needs it), and feels good to control.
You will use Godot 4's CharacterBody2D, Input Map, and a simple movement script so that by the end you have a character you can run around the scene with keyboard or gamepad.
What You Will Build
- A Player scene with a CharacterBody2D root and a sprite (or placeholder)
- Input actions for move_left, move_right, jump (optional)
- A GDScript that reads input, applies velocity, and uses
move_and_slide()for movement and collisions - Smooth, responsive movement you can tune with a few variables
Step 1 – Create the Player Scene
- In the Godot 4 project you set up in Lesson 1, create a new scene.
- Choose Other Node and add a CharacterBody2D as the root. Name it
Player. - Add a CollisionShape2D as a child of
Player. Give it a simple shape (e.g. rectangle or capsule) that matches the size you want for the character. You can resize it in the editor. - Add a Sprite2D (or AnimatedSprite2D if you already have frames). Assign a texture from your
art/orsprites/folder, or use a placeholder. Center it so the sprite aligns with the collision shape.
Your node tree should look like:
Player (CharacterBody2D)
├── CollisionShape2D
└── Sprite2D
Save the scene as scenes/player/player.tscn (or under whatever folder structure you defined in Lesson 3).
Step 2 – Define Input Actions
Godot 4 uses an Input Map so you can refer to actions like move_left instead of raw key codes.
-
Go to Project → Project Settings → Input Map.
-
Add these actions (if your game is a platformer or top-down with jump):
move_leftmove_rightmove_up(optional, for top-down or jump)move_down(optional, for top-down)jump(optional)
-
For each action, add the keys you want (e.g. A/Left, D/Right, W/Up, S/Down, Space for jump). You can also add gamepad axes or buttons.
Using the Input Map keeps your script clean and makes it easy to support gamepad or remapping later.
Step 3 – Write the Movement Script
Attach a new script to the Player node (CharacterBody2D). Below is a minimal movement script you can adapt.
For a side-scrolling platformer (horizontal movement + jump):
extends CharacterBody2D
@export var move_speed := 280.0
@export var jump_velocity := -420.0
@export var gravity := 980.0
func _physics_process(delta: float) -> void:
# Apply gravity when in air
if not is_on_floor():
velocity.y += gravity * delta
# Jump
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = jump_velocity
# Horizontal movement
var direction := Input.get_axis("move_left", "move_right")
velocity.x = direction * move_speed
move_and_slide()
For a top-down game (no gravity, 8-direction or 4-direction):
extends CharacterBody2D
@export var move_speed := 200.0
func _physics_process(_delta: float) -> void:
var direction := Vector2(
Input.get_axis("move_left", "move_right"),
Input.get_axis("move_up", "move_down")
)
direction = direction.normalized()
velocity = direction * move_speed
move_and_slide()
- @export lets you tweak
move_speed,jump_velocity, andgravityin the Inspector without editing code. - move_and_slide() handles collision and sliding along surfaces; call it once per frame after setting
velocity.
Step 4 – Place the Player in a Test Room
- Open or create a test room (e.g. your first level scene).
- Instance the Player scene into the room. Place it above the floor so it can land (for platformer) or anywhere (for top-down).
- Ensure the room has a StaticBody2D or TileMapLayer with a CollisionShape2D so the player has something to stand on or collide with.
- Run the scene. You should be able to move (and jump if you used the platformer script).
If the character falls through the floor, check that the floor has a collision layer and that the player's collision mask includes that layer (default is usually correct).
Pro Tips
- Tuning feel: Adjust
move_speed,jump_velocity, andgravityin the Inspector. Slightly higher jump and lower gravity often feel better for platformers. - Coyote time: To allow a short window to jump after leaving a ledge, use a timer that keeps “was on floor” true for a few frames after leaving the floor, and allow jump while that timer is active.
- Jump buffer: To make jump feel responsive when pressing jump just before landing, buffer the jump input for 1–2 frames and apply it when you land.
Common Mistakes to Avoid
- Forgetting to set collision layers: If the player does not collide with the level, check both the player and the level collision layers and masks in the Inspector.
- Using _process instead of _physics_process: Movement and
move_and_slide()should run in_physics_processso they stay in sync with the physics engine. - Not normalizing direction: In top-down movement, if you do
velocity = direction * move_speedwithoutdirection.normalized(), diagonal movement will be faster than horizontal or vertical.
Mini-Task
Create smooth character movement for your 2D action game:
- Build the Player scene with CharacterBody2D, collision shape, and sprite.
- Add input actions and the movement script (platformer or top-down).
- Place the player in a test room and tune speed and jump until it feels good.
- Optionally add one small polish (e.g. a simple animation when moving or a dust effect when landing).
Troubleshooting
- Player does not move: Confirm input actions are named exactly as in the script (
move_left,move_right, etc.) and that keys are assigned in Project Settings → Input Map. - Player slides or sticks: Reduce move_speed or ensure you are not applying velocity twice. For platformers, make sure gravity is applied only when not on floor.
- Jitter on slopes: CharacterBody2D with
move_and_slide()is designed for this; if you still see jitter, check that the floor collision shape is not too thin or overlapping.
Recap and Next Steps
You now have a playable character with input-driven movement and (optionally) jump. The same pattern—read input, set velocity, call move_and_slide()—will carry through the rest of the course.
In Lesson 5: Combat System and Weapons you will add attacks, damage, and weapon logic so the player can interact with enemies. Before that, spend a few minutes getting the movement feel right; it will make every later lesson more enjoyable.
Found this useful? Bookmark this lesson and share your movement demo in the community. Next up: Lesson 5: Combat System and Weapons.