Install Godot, build a 2D scene from nodes, and attach a GDScript that moves a character with gravity and input.
Why this matters
Your canvas prototypes taught you the moving parts of a game: a loop, state, input, collision and gravity. An engine packages those parts so you can spend your time on design. Godot is a good first engine for a designer: it is free and open source, the download is small, it runs on modest laptops, and its language, GDScript, reads like Python. In this lesson you will map what you already know onto Godot's concepts and build a playable scene.
Getting Godot
Download the standard build of Godot 4 from godotengine.org/download (the ".NET" build is only needed for C#). On Windows and Linux it is a single executable you can run without installing; on macOS it is an app bundle. Steam and itch.io also distribute it. Use the latest stable 4.x release. Checked on 2026-10-23.
Nodes and scenes
Everything in Godot is a node: a sprite, a camera, a sound, a collision shape, a timer. Nodes form a tree. A saved tree is a scene (.tscn file). A scene can be a whole level, or a single reusable thing like a player or a coin, and scenes can be placed inside other scenes (called instancing). This replaces most of the hand-rolled structure you wrote in JavaScript.
A typical 2D player scene:
Player (CharacterBody2D) <- moves and collides; holds the script
├── Sprite2D <- the picture
└── CollisionShape2D <- the hitbox (a RectangleShape2D or CapsuleShape2D)
A floor:
Floor (StaticBody2D) <- does not move, but others collide with it
├── Sprite2D (or ColorRect)
└── CollisionShape2D
Mapping to what you know:
| your canvas code | Godot |
|---|---|
player = { x, y, w, h } | a CharacterBody2D with position and a CollisionShape2D |
update(dt) | _physics_process(delta) (called at a fixed 60 Hz by default) |
draw() | automatic: nodes draw themselves |
keys.ArrowLeft | Input.is_action_pressed("ui_left") or Input.get_axis(...) |
| AABB + landing code | move_and_slide() and is_on_floor() |
Your first script
Select the Player node and click the Attach Script button. Godot creates a file starting with extends CharacterBody2D. Replace its contents with:
extends CharacterBody2D
const SPEED := 220.0
const JUMP_SPEED := 450.0
const GRAVITY := 1200.0
func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity.y += GRAVITY * delta
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = -JUMP_SPEED
var direction := Input.get_axis("ui_left", "ui_right")
velocity.x = direction * SPEED
move_and_slide()
Read it next to your JavaScript from module 2. velocity is a built-in Vector2 on CharacterBody2D. Gravity is added only in the air. ui_accept is a built-in input action (Enter and Space by default). Input.get_axis returns -1, 0 or 1 from two actions, so opposite keys cancel exactly as yours did. move_and_slide() moves the body by velocity, handles collisions with the floor, and updates is_on_floor(). GDScript uses tabs for indentation, like Python uses indentation for blocks.
Input actions
Hard-coding keys is the mistake you avoided in the input lesson. Godot builds that idea in: Project > Project Settings > Input Map lets you define actions such as jump and bind several keys and gamepad buttons to each. Your code then asks for "jump", and players or designers can remap without code changes.
Running and iterating
- F5 runs the main scene (Godot asks you to choose one the first time). F6 runs the scene you are editing.
- Change
SPEEDwhile the game runs and save: many changes apply live. Even better, mark tuning values with@export var speed := 220.0and they appear in the Inspector, where a designer can tweak them without opening the script. - Use
print()for quick debugging; output appears in the bottom panel.
Common mistakes
- Forgetting the CollisionShape2D (Godot shows a yellow warning triangle on the node). Without it, the player falls through the floor.
- Moving a CharacterBody2D by setting
positioninstead of usingvelocityandmove_and_slide(), which skips collision. - Mixing tabs and spaces in GDScript.
- Writing physics in
_processinstead of_physics_process. - Not setting a main scene, so F5 asks every time.
Quick recap
- Godot organises everything as nodes in trees saved as scenes.
CharacterBody2D+CollisionShape2D+Sprite2Dis a typical player._physics_process(delta)is your update;move_and_slide()does movement and collision.- Use the Input Map and
@exportvariables to keep controls and tuning editable.
Try it
Open the Do tab and build the scene step by step. It takes about 30 minutes with the editor open.