A little monster.
A lot to learn.
Build its scene. Make it move. Give it something to collect.
Learn Godot one working idea at a time, then take it into your own game.

A player is a few nodes working together.
Build a scene tree and assign properties in a small editor model.
Give the monster an image and a body that can collide. Select a node to edit its properties, then test the scene.
Scene
Inspector Player
CharacterBody2D provides movement and collision support for a player.
Move the parent. Its image and collision shape move together.
An image makes it visible. A shape gives the body its collision boundary.
Simplified browser model with gravity and a floor supplied for the test. In Godot, a CharacterBody2D needs a movement script; it does not fall automatically.
Rebuild this in Godot
- Create a CharacterBody2D named Player. Add Sprite2D and CollisionShape2D children.
- Assign your image to Sprite2D’s Texture. Give CollisionShape2D a RectangleShape2D and size it around the image.
- Attach a movement script to Player. Add a StaticBody2D floor with its own CollisionShape2D.
- Save Player.tscn. Continue to the movement activity to learn what its script does.
Take this into your own game
Read the full explanation. Each tutorial links back here when you want to try it again.
Fix the code. See it move.
Edit speed and direction, then measure what the player actually does.
Move 300 pixels in one second, in either direction. This script always moves right. Test it, then fix the two editable lines.
player.gd Two editable lines
extends CharacterBody2D func _physics_process(delta):
var direction = Input.get_axis(
"move_left", "move_right") move_and_slide() These fields edit one line each. The preview supports the expressions in the hint below.

Try Test left first. Does the monster go where you expected?
I need a hint
Use var speed = 300. Left input is −1 and right input is +1. Multiply direction by speed: velocity.x = direction * speed.
Also try velocity.x = direction * speed * delta. It moves only 5 pixels in this one-second test at 60 physics ticks per second: move_and_slide() already handles the timestep.
JavaScript simulation of these expressions, not a GDScript runtime. In Godot, attach this horizontal movement script to a CharacterBody2D and create move_left / move_right actions in Project Settings → Input Map.
Take this into your own game
Read the full explanation. Each tutorial links back here when you want to try it again.
One coin. A signal. A changing score.
Connect the score handler and follow the code when a body enters the coin.
Make the coin increase the score for the player and ignore a crate. Test the missing connection, then wire it up and try both visitors.
◆▦coin.gd Attach to Area2D
extends Area2D
signal collected(value: int)
@export var value: int = 10
func _ready():
body_entered.connect(_on_body_entered)
func _on_body_entered(body):
if not body.is_in_group("player"):
return
collected.emit(value)
queue_free() level.gd Attach to the level root
extends Node2D
var score: int = 0
func _ready():
pass # No listener connected yet
func _on_collected(amount: int):
score += amount
$Score.text = str(score)Browser simulation of signal flow. The coin emits a value; the connected level script updates the Score label. A signal without a listener cannot update the score.
Set up this scene in Godot
Create a Node2D level root with Coin (Area2D), Score (Label), and Player (CharacterBody2D) children. Coin needs Sprite2D and CollisionShape2D children with their resources assigned; Player needs a collision shape too.
Add Player to the player group. Enable Coin’s Monitoring and make its collision mask include Player’s collision layer. Attach the two scripts to Coin and the level root. The example handles a single entering body; larger games may also need a guard against repeated collection in the same frame.
Explore complete player and coin scripts, line by line
extends CharacterBody2D@export var speed := 300.0@export var jump_force := -400.0var gravity: float = ProjectSettings.get_setting("physics/2d/default_gravity")func _physics_process(delta: float) -> void:# Apply gravityvelocity.y += gravity * delta# Jump when on floorif Input.is_action_just_pressed("jump") and is_on_floor():velocity.y = jump_force# Horizontal movementvar direction := Input.get_axis("move_left", "move_right")velocity.x = direction * speedmove_and_slide()
The script is the node
There is no component to add. This file is attached to a CharacterBody2D and becomes its behaviour, so velocity, is_on_floor() and move_and_slide() are simply available.
Unity: a MonoBehaviour plus GetComponent<CharacterController>() collapsed into one thing.
Jump to an explanation
Take this into your own game
Read the full explanation. Each tutorial links back here when you want to try it again.
Ready to try 3D?
Take the body, visual, and collision-shape idea into a real Godot project. Build a playable room, then use it to explore lighting and rendering.
More lessons & earlier saved progress
Short reference lessons for individual Godot concepts. Your earlier completions are still saved.
- A scene is a treeOpen lesson
- Read a real scriptOpen lesson
- Signals: one press, one methodOpen lesson
- Pick the root nodeOpen lesson
- Actions, not keysOpen lesson
- Where things liveOpen lesson
Before you start
- Do I need programming experience to learn Godot?
- No. Start by assembling a player, then edit two movement lines and connect a coin signal. Each activity includes a hint or a setup guide, plus a tutorial for the full explanation.
- Do these activities run Godot in my browser?
- These are focused JavaScript simulations of Godot concepts. They show the result of supported changes, not arbitrary GDScript execution. Each activity explains how to recreate the example in Godot.
- What happened to my earlier lessons?
- All earlier lesson URLs and saved completions remain available under More lessons below. Workshop activities have their own progress, earned by testing a working result.


