Godot
Godot is a free, open-source game engine with its own scripting language (GDScript) and a node-based scene system. Lightweight, MIT-licensed, fast iteration loop.
Player + signals + scene composition
EXAMPLE
# Player.gd — attached to a CharacterBody2D
extends CharacterBody2D
@@export var speed: float = 200.0
@@export var jump_velocity: float = -380.0
var gravity: float = ProjectSettings.get_setting("physics/2d/default_gravity")
@@onready var sprite: AnimatedSprite2D = $Sprite
@@onready var jump_sound: AudioStreamPlayer = $JumpSound
signal died # custom signal
signal coin_grabbed(amount: int)
func _physics_process(delta: float) -> void:
# 1) Gravity
if not is_on_floor():
velocity.y += gravity * delta
# 2) Jump
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = jump_velocity
jump_sound.play()
# 3) Horizontal input
var dir: float = Input.get_axis("move_left", "move_right")
if dir != 0:
velocity.x = dir * speed
sprite.flip_h = dir < 0
sprite.play("run")
else:
velocity.x = move_toward(velocity.x, 0, speed)
sprite.play("idle" if is_on_floor() else "jump")
move_and_slide()
# 4) Handle damage from outside
func take_damage(amount: int) -> void:
$Health.value -= amount
if $Health.value <= 0:
died.emit()
queue_free()
# 5) Connecting signals
# In another script (e.g. Main.gd):
# func _ready():
# $Player.died.connect(_on_player_died)
# $Player.coin_grabbed.connect(_on_coin_grabbed)
# func _on_player_died() -> void:
# get_tree().reload_current_scene()
# func _on_coin_grabbed(amount: int) -> void:
# hud.set_score(hud.score + amount)
# 6) Input mappings — Project → Project Settings → Input Map
# Add actions: move_left, move_right, jump
# Bind to keys / gamepad buttons
# 7) Scene composition — every scene can be instanced into another
var coin_scene: PackedScene = preload("res://Coin.tscn")
func spawn_coin(pos: Vector2) -> void:
var c = coin_scene.instantiate()
c.position = pos
add_child(c)
# 8) Singletons (Autoload) — global game state
# Project → AutoLoad → register Game.gd
# extends Node
# var score: int = 0
# Access anywhere as Game.score
# 9) Common gotchas
# • _process(delta) runs every render frame; _physics_process(delta) runs fixed (60Hz)
# • Use @export to expose vars in the Inspector
# • signal naming: past tense (died, grabbed, scored) — clearer at call sites
# • Prefer signals + composition over inheriting from a massive base node
# 10) Export to web
# Project → Export → Add HTML5/Web preset → Export to a folder
# Serve over HTTPS; the WASM build is ~30MB for a small game
Why it matters
Godot signals are events — loose-coupled callbacks across scenes. Pair them with composition (instance scenes into scenes) and you get a code base where the inspector is the architecture.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
# Godot 4 (GDScript) — drop on a Node2D
extends Node2D
@export var speed := 200.0
func _process(delta: float) -> void:
var direction := Input.get_axis("ui_left", "ui_right")
position.x += direction * speed * delta
Try it Yourself »
Exercise
Godot per-frame override.
func _process(
): pass
Five letters.
Discussion
Loading…