Godot 4 Complete Beginner Tutorial: Build Your First Tiny Game

A practical first-game tutorial for Godot 4 beginners. Build a tiny collect-and-score game while learning scenes, nodes, input, signals, collisions, and export-ready habits.

Godot 4 beginner tutorial showing a small 2D game project

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.

gdscript
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:

gdscript
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.

gdscript
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" % score

Add 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.

👤
Godot Learning Team Helping developers transition to Godot with practical tutorials and comparisons.
Practice This Next

Turn the article into a working habit

Read for context, then open the guide or tool and rebuild the idea with your own hands.