Godot Engine Guide — Getting Started with Game Development
Godot is a free, open-source game engine that uses a unique node-based architecture and a Python-like scripting language (GDScript) — perfect for beginners who want professional-quality 2D and 3D games.
What You’ll Learn
By the end of this tutorial, you’ll understand Godot’s node and scene system, write GDScript to control game objects, handle input, manage scenes, and build a simple platformer character with physics.
Why Godot Matters
Godot is the fastest-growing game engine in the world. It’s completely free with no royalties, the editor is lightweight (under 50MB), and it exports to Windows, Mac, Linux, Android, iOS, and web. At DodaTech, we’ve prototyped interactive UI concepts for Durga Antivirus Pro using Godot’s animation system.
Godot Learning Path
flowchart LR
A[Game Dev Overview] --> B[Godot Engine]
B --> C{You Are Here}
C --> D[2D Platformer]
D --> E[Export to Web/Mobile]
style C fill:#f90,color:#fff
What Is Godot? (The “Why” First)
Think of Godot as a hierarchy of nested boxes. Every object in your game is a node (a box with a specific purpose), and nodes are organized in a tree. A node might be a Sprite (shows an image), a CollisionShape2D (detects physics), or an AudioStreamPlayer (plays sounds). You combine these nodes into a Scene, which is like a prefabricated object you can reuse.
This node-scene system makes Godot incredibly modular. A “Player” scene contains movement, collision, and animation nodes. You can reuse that Player scene across multiple levels without copying anything.
Installation and Setup
Download Godot from godotengine.org (choose the standard version, not .NET unless you want C#). Extract the ZIP and run the executable. No installer needed.
Create a new project:
- Click New Project
- Name it
MyFirstGame - Choose a folder and click Create & Edit
Understanding Nodes and Scenes
Nodes are the building blocks. Each node has:
- A name (you set this)
- Properties (position, rotation, scale)
- Signals (events like “body entered” or “timeout”)
- Children (sub-nodes)
Scenes are collections of nodes saved as a file (.tscn). A scene can be a character, a level, a UI menu — anything reusable.
Common Node Types
| Node Type | Purpose | Icon |
|---|---|---|
Node2D | Base for 2D objects | Blue circle |
Sprite2D | Displays a texture/image | Green square |
CharacterBody2D | Player/enemy with movement | Red figure |
RigidBody2D | Physics-simulated object | Orange ball |
StaticBody2D | Non-moving collider (walls) | Gray brick |
Area2D | Detection zone (overlap) | Green outline |
CollisionShape2D | Shape for collision | Yellow outline |
AnimatedSprite2D | Animated sprites | Film strip |
Camera2D | Viewport following | Camera icon |
Your First Godot Script — Moving a Sprite
Let’s create a simple character that moves with arrow keys.
Step 1: Set Up the Scene
- In the Scene dock, click + (Other Node)
- Choose CharacterBody2D — this is our player root
- Rename it to
Player(right-click → Rename) - Right-click
Player→ Add Child Node → Sprite2D - In the Inspector (right panel), find the
Textureproperty of Sprite2D - Click
[empty]→ Quick Load → choose an image (or use Godot’s icon: dragicon.svgfrom FileSystem dock)
Step 2: Add Collision
- Right-click
Player→ Add Child Node → CollisionShape2D - In the Inspector, find
Shape→[empty]→ New RectangleShape2D - Adjust the rectangle size to match your sprite (about 64×64 pixels)
Step 3: Write the Movement Script
- Right-click the
Playernode → Attach Script - Name it
player.gdand click Create - Replace the template with:
extends CharacterBody2D
# Movement speed in pixels per second
@export var speed := 300
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
# Get input vector
var input_vector := Vector2.ZERO
input_vector.x = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
input_vector.y = Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")
# Normalize diagonal movement so it isn't faster
if input_vector.length() > 1.0:
input_vector = input_vector.normalized()
# Apply movement
velocity = input_vector * speed
move_and_slide()Step 4: Run the Game
Press F5 (or click the Play button in the top-right). Select Select Current Scene and click Play. Your character moves with arrow keys!
What’s happening:
@exportmakes thespeedvariable editable in the InspectorInput.get_action_strength()returns 0 or 1 for each directionvelocityis a built-in property ofCharacterBody2Dmove_and_slide()applies the velocity and handles collisions automatically
Adding Jumping and Gravity
Let’s convert this to a platformer with gravity and jumping:
extends CharacterBody2D
@export var speed := 300
@export var jump_velocity := -600 # Negative = upward in Godot
# Get the gravity from project settings
var gravity := ProjectSettings.get_setting("physics/2d/default_gravity")
func _physics_process(delta):
# Apply gravity
if not is_on_floor():
velocity.y += gravity * delta
# Horizontal movement
var direction := Input.get_axis("ui_left", "ui_right")
velocity.x = direction * speed
# Jump (only when on the ground)
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = jump_velocity
move_and_slide()Key changes:
_physics_processinstead of_process— use this for physics updates (runs at fixed 60 FPS)gravityfrom project settings ensures consistent physicsis_on_floor()checks if the character is standing on a surfaceInput.get_axis()returns -1, 0, or 1 for left/right
Save and run. Press Space or Up to jump. You’ll see gravity pull you down, and you only jump when grounded.
Scene Management — Switching Levels
Create a second scene (Level2.tscn) and use this script to transition:
# In your main game script
func _on_level_complete():
# Change to the next level scene
get_tree().change_scene_to_file("res://Level2.tscn")Or pass data between scenes using autoload (singleton):
# Create a new script: Global.gd
extends Node
var score := 0
var lives := 3
# In Project Settings → AutoLoad, add Global.gd as "Global"
# Now Global.score is accessible from any scriptSignals — Event-Based Communication
Signals are Godot’s way of communicating between nodes without direct coupling:
# In a coin script
extends Area2D
signal coin_collected
func _on_body_entered(body):
if body.is_in_group("player"):
coin_collected.emit()
queue_free() # Remove the coin# In the player script
func _ready():
# Connect to the coin signal
var coin = get_node("../Coin")
coin.coin_collected.connect(_on_coin_collected)
func _on_coin_collected():
Global.score += 10
print("Score: ", Global.score)Godot vs Other Engines
| Feature | Godot | Unity | Unreal |
|---|---|---|---|
| Price | Free (MIT) | Free tier | Free (5% royalty) |
| Installer size | ~50MB | ~3GB | ~30GB |
| 2D support | Excellent | Good | Limited |
| 3D support | Good | Excellent | Excellent |
| Scripting | GDScript, C#, C++ | C# | C++, Blueprints |
| Learning curve | Gentle | Moderate | Steep |
| Export targets | 6 platforms | 27 platforms | 14 platforms |
Godot wins for 2D games, beginners, and small teams who want full control without licensing fees.
Common Mistakes Beginners Make
1. Using _process Instead of _physics_process
_process runs every frame (variable rate). _physics_process runs at fixed 60 FPS. Use _physics_process for anything involving physics (movement, collisions).
2. Forgetting move_and_slide()
Setting velocity does nothing until you call move_and_slide(). This is the function that actually moves the character and handles collisions.
3. Not Checking is_on_floor() Before Jumping
Without this check, the player can jump infinitely in mid-air. Always check ground contact before allowing a jump.
4. Hardcoding Numbers Instead of Using @export
Hardcoded values require script edits to tune. @export exposes the variable in the Inspector for quick tweaking.
5. Creating Deeply Nested Nodes Without Organization
Keep your scene tree clean. Group related nodes, use meaningful names, and don’t nest more than 4-5 levels deep.
6. Ignoring Signals in Favor of get_node()
get_node("../path/to/node") creates fragile dependencies. Signals provide decoupled communication that survives scene changes.
7. Not Using the Built-in Documentation
Press F1 in the Godot editor to open the built-in reference. Every node, method, and signal is documented with examples.
Practice Questions
1. What’s the difference between _process(delta) and _physics_process(delta)?
_process runs every rendered frame (variable rate). _physics_process runs at a fixed 60 FPS. Use _physics_process for physics-based movement.
2. Why would you use signals instead of directly calling methods on another node?
Signals decouple the sender from the receiver. The coin doesn’t need to know who collects it — it just emits a signal and any connected node responds.
3. What does @export do in GDScript?
It exposes the variable in the Inspector panel, allowing designers to tweak values without editing code.
4. What is the purpose of move_and_slide()?
It applies the velocity to the character’s position while handling collisions automatically, sliding along walls and floors.
5. Challenge: Add a double-jump mechanic that allows one additional jump in the air.
Track jump_count. Allow jump when is_on_floor() OR jump_count < 2. Reset jump_count = 0 on landing.
Mini Project: Coin Collection Game
Combine everything into a complete mini-game:
# Coin.gd
extends Area2D
signal collected
func _ready():
body_entered.connect(_on_body_entered)
func _on_body_entered(body):
if body.is_in_group("player"):
collected.emit()
queue_free()
# Player.gd (add this to your existing player)
extends CharacterBody2D
@export var speed := 300
@export var jump_velocity := -600
var gravity := ProjectSettings.get_setting("physics/2d/default_gravity")
var score := 0
func _ready():
# Find all coins and connect
var coins = get_tree().get_nodes_in_group("coins")
for coin in coins:
coin.collected.connect(_on_coin_collected)
func _physics_process(delta):
if not is_on_floor():
velocity.y += gravity * delta
var direction := Input.get_axis("ui_left", "ui_right")
velocity.x = direction * speed
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = jump_velocity
move_and_slide()
func _on_coin_collected():
score += 1
print("Score: ", score)
# In the main scene script
extends Node2D
func _ready():
# Spawn coins at random positions
for i in range(10):
var coin = preload("res://Coin.tscn").instantiate()
coin.position = Vector2(randf_range(100, 700), randf_range(100, 500))
add_child(coin)
coin.add_to_group("coins")FAQ
Try It Yourself
Open the Godot editor and press F1 to open the documentation. Search for CharacterBody2D and browse its built-in methods and signals. Try:
- Changing the
speedandjump_velocityvalues in the Inspector - Adding a second
Sprite2Dchild for a hat on the player - Creating a
Camera2Das a child ofPlayerto follow movement
This hands-on experimentation builds intuition faster than any tutorial. The same approach applies when building tools at DodaTech — prototype first, then refine.
What’s Next
What’s Next
Congratulations on completing this Godot tutorial! Here’s where to go from here:
- Practice daily — Consistency is more important than long study sessions
- Build a project — Apply what you learned by building something real
- Explore related topics — Check out other tutorials in the same category
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro