Your first Godot game should be small enough to finish in one sitting. Not a platformer with twelve systems. Not an RPG. Not a dream project wearing a beginner tutorial costume. We are going to build a tiny collect-and-score game because it teaches the parts of Godot you will use everywhere: scenes, nodes, input, collisions, signals, UI, and a clean loop.
The Game We Are Building
The player moves around a 2D arena, collects coins, and the score updates on screen. That sounds tiny, but it quietly covers the real Godot fundamentals: a Player scene, a Coin scene, a Main scene, collision signals, an input map, and a HUD label.
- Player: a CharacterBody2D that reads input and moves.
- Coin: an Area2D that detects when the player touches it.
- Main: the level scene that owns the score and spawns gameplay objects.
- HUD: a Label that shows the score without knowing how coins work.
Step 1: Make the Player Scene
Create a new scene with CharacterBody2D as the root and name it Player. Add a Sprite2D child for visuals and a CollisionShape2D child for physics. A colored square is fine. Fancy art can wait.
extends CharacterBody2D
@export var speed: float = 220.0
func _physics_process(delta: float) -> void:
var direction := Input.get_vector(
"move_left",
"move_right",
"move_up",
"move_down"
)
velocity = direction * speed
move_and_slide()If you are coming from Unity, this is your first important translation: the movement body is not a blank GameObject with several components glued on. The root node already has a job. The script extends that job instead of inventing one from scratch.
Step 2: Add Input Actions
Open Project Settings, go to Input Map, and add four actions: move_left, move_right, move_up, and move_down. Bind WASD or arrow keys. This makes your code talk about game intent instead of keyboard letters.
Step 3: Make the Coin Scene
Create a second scene with Area2D as the root and name it Coin. Add a Sprite2D and CollisionShape2D. In the Inspector, make sure the Area2D can detect bodies. Then attach this script:
extends Area2D
signal collected
func _ready() -> void:
body_entered.connect(_on_body_entered)
func _on_body_entered(body: Node) -> void:
if body.name == "Player":
collected.emit()
queue_free()The coin does not reach into the score label. It emits a signal and removes itself. That is the Godot way: small scene, clear responsibility, no weird dependency chain.
Step 4: Build the Main Scene
Create a Main scene with Node2D as the root. Instance your Player scene. Instance a few Coin scenes and place them around the level. Add a CanvasLayer child called HUD, then add a Label named ScoreLabel under it.
extends Node2D
var score: int = 0
@onready var score_label: Label = $HUD/ScoreLabel
func _ready() -> void:
for coin in get_tree().get_nodes_in_group("coins"):
coin.collected.connect(_on_coin_collected)
_update_score_label()
func _on_coin_collected() -> void:
score += 1
_update_score_label()
func _update_score_label() -> void:
score_label.text = "Score: %d" % scoreAdd each Coin root node to a group named coins. Groups are a clean beginner-friendly way to find a set of nodes without hardcoding every path in the level.
Step 5: Test Like a Developer
Run the Main scene. Move the player into a coin. If the coin disappears and the score increases, you have a real loop. If it does not work, check the boring things first: collision shapes exist, the coin is in the coins group, the player is named Player, and your input actions match the script.
- If the player does not move, print the input direction.
- If coins do not detect the player, enable Visible Collision Shapes from the Debug menu.
- If the score does not update, print inside
_on_coin_collected(). - If the label path fails, drag the ScoreLabel node into the script editor to get its exact path.
What You Learned Without Noticing
This little project teaches the core Godot mental model. Nodes are not just folders. Scenes are reusable objects. Signals keep objects from knowing too much about each other. The main scene coordinates the game loop, while smaller scenes stay focused.
That is enough to build your next prototype. Add a timer. Add enemies. Add a door that opens when the score reaches five. Keep the same pattern: one scene, one job, one clear signal when something important happens.
