Godot Cheat Sheet
Overview
Godot is a free, open-source game engine that provides a comprehensive set of tools for 2D and 3D game development. It features its own scripting language (GDScript) designed specifically for game development, along with support for C#, C++, and community-maintained language bindings. Godot’s unique scene system treats every game element as a composable scene made of nodes, enabling a modular and reusable design approach that scales from simple prototypes to complex productions.
The engine includes a full-featured editor with visual scripting, animation tools, physics engines for both 2D and 3D, a particle system, shader editor, and tilemap tools. Godot 4.x introduced a Vulkan-based renderer with global illumination, signed distance field effects, and volumetric fog. The engine exports to Windows, macOS, Linux, Android, iOS, and HTML5, with console exports available through third-party providers. Its permissive MIT license means no royalties or subscription fees.
Installation
# Download from official site
# https://godotengine.org/download
# Linux (Flatpak)
flatpak install flathub org.godotengine.Godot
# Linux (Snap)
sudo snap install godot-4
# macOS (Homebrew)
brew install --cask godot
# Steam
# Available free on Steam store
# .NET version (for C# support)
# Download "Godot Engine - .NET" variant
# Command-line export (headless)
# Download Godot Server/Headless for CI/CD
./Godot_v4.3-stable_linux.x86_64 --headless --export-release "Linux" build/game.x86_64
# Verify
godot --version
GDScript Basics
# Variables and types
var health: int = 100
var speed: float = 5.0
var player_name: String = "Hero"
var position: Vector2 = Vector2(0, 0)
var is_alive: bool = true
var items: Array = ["sword", "shield"]
var stats: Dictionary = {"str": 10, "dex": 8}
# Constants
const MAX_SPEED: float = 10.0
const GRAVITY: float = 980.0
# Enums
enum State { IDLE, RUNNING, JUMPING, FALLING }
var current_state: State = State.IDLE
# Functions
func take_damage(amount: int) -> void:
health -= amount
if health <= 0:
die()
func get_damage_multiplier() -> float:
return 1.0 + (stats["str"] * 0.1)
# Signals (event system)
signal health_changed(new_health: int)
signal player_died
func _ready() -> void:
health_changed.connect(_on_health_changed)
func _on_health_changed(new_health: int) -> void:
print("Health: ", new_health)
Node Lifecycle
extends Node2D
# Called when node enters the scene tree
func _ready() -> void:
print("Node is ready!")
# Called every frame
func _process(delta: float) -> void:
# Game logic, UI updates
position.x += speed * delta
# Called at fixed intervals (physics)
func _physics_process(delta: float) -> void:
# Physics calculations
velocity += gravity * delta
# Called for input events
func _input(event: InputEvent) -> void:
if event.is_action_pressed("jump"):
jump()
# Called for unhandled input
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventKey and event.pressed:
if event.keycode == KEY_ESCAPE:
get_tree().quit()
# Called when node exits scene tree
func _exit_tree() -> void:
print("Node removed")
Common Node Types
| Node | Purpose |
|---|---|
Node2D | Base for 2D game objects |
Node3D | Base for 3D game objects |
CharacterBody2D | 2D physics character |
CharacterBody3D | 3D physics character |
RigidBody2D/3D | Physics-driven body |
StaticBody2D/3D | Non-moving collision body |
Area2D/3D | Detection zone (triggers) |
Sprite2D | 2D image display |
AnimatedSprite2D | Sprite with animations |
Camera2D/3D | Viewport camera |
TileMapLayer | Tile-based level |
CanvasLayer | UI layer |
AudioStreamPlayer | Sound playback |
Timer | Countdown timer |
RayCast2D/3D | Line-of-sight detection |
NavigationAgent2D/3D | Pathfinding agent |
2D Character Controller
extends CharacterBody2D
const SPEED = 300.0
const JUMP_VELOCITY = -400.0
const GRAVITY = 980.0
@onready var animated_sprite = $AnimatedSprite2D
func _physics_process(delta: float) -> void:
# Gravity
if not is_on_floor():
velocity.y += GRAVITY * delta
# Jump
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Horizontal movement
var direction = Input.get_axis("ui_left", "ui_right")
if direction:
velocity.x = direction * SPEED
animated_sprite.flip_h = direction < 0
animated_sprite.play("run")
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
animated_sprite.play("idle")
move_and_slide()
3D Character Controller
extends CharacterBody3D
const SPEED = 5.0
const JUMP_VELOCITY = 4.5
const MOUSE_SENSITIVITY = 0.002
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
@onready var camera_pivot = $CameraPivot
@onready var camera = $CameraPivot/Camera3D
func _ready() -> void:
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventMouseMotion:
rotate_y(-event.relative.x * MOUSE_SENSITIVITY)
camera_pivot.rotate_x(-event.relative.y * MOUSE_SENSITIVITY)
camera_pivot.rotation.x = clamp(camera_pivot.rotation.x, -PI/3, PI/3)
func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity.y -= gravity * delta
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
var input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()
Scene Management
# Change scene
get_tree().change_scene_to_file("res://scenes/level2.tscn")
# Preload scene
var enemy_scene = preload("res://scenes/enemy.tscn")
# Instance scene
var enemy = enemy_scene.instantiate()
enemy.position = Vector2(400, 300)
add_child(enemy)
# Remove node
enemy.queue_free()
# Pause/unpause
get_tree().paused = true
# Nodes with process_mode = PROCESS_MODE_ALWAYS still run when paused
# Groups
add_to_group("enemies")
get_tree().get_nodes_in_group("enemies")
get_tree().call_group("enemies", "take_damage", 10)
Signals and Communication
# Define custom signal
signal coin_collected(value: int)
signal game_over
# Emit signal
coin_collected.emit(10)
# Connect in code
func _ready():
var player = get_node("Player")
player.health_changed.connect(_on_player_health_changed)
# Lambda connection
player.coin_collected.connect(func(value):
score += value
update_score_display()
)
# Disconnect
player.health_changed.disconnect(_on_player_health_changed)
# Autoload (global) signals
# In an autoload script "Events.gd":
signal score_updated(new_score: int)
# Any script can emit/connect:
Events.score_updated.emit(100)
Events.score_updated.connect(_on_score_updated)
Animation
# AnimationPlayer
@onready var anim_player = $AnimationPlayer
anim_player.play("walk")
anim_player.play_backwards("walk")
anim_player.stop()
anim_player.queue("idle")
# Tweens (programmatic animation)
var tween = create_tween()
tween.tween_property(self, "position", Vector2(500, 300), 1.0)
tween.tween_property(self, "modulate:a", 0.0, 0.5)
tween.tween_callback(queue_free)
# Chained tweens
var tween = create_tween().set_trans(Tween.TRANS_BOUNCE)
tween.tween_property($Sprite, "position:y", 0.0, 0.5)
tween.tween_interval(0.2) # Wait
tween.tween_property($Sprite, "scale", Vector2(1.2, 1.2), 0.1)
tween.tween_property($Sprite, "scale", Vector2(1.0, 1.0), 0.1)
# Parallel tweens
tween.set_parallel(true)
tween.tween_property(self, "position:x", 100, 1.0)
tween.tween_property(self, "rotation", TAU, 1.0)
Configuration
; project.godot (key settings)
[application]
config/name="My Game"
run/main_scene="res://scenes/main.tscn"
[display]
window/size/viewport_width=1920
window/size/viewport_height=1080
window/stretch/mode="viewport"
window/stretch/aspect="keep"
[input]
move_left={ "deadzone": 0.5, "events": [InputEventKey(keycode=KEY_A)] }
move_right={ "deadzone": 0.5, "events": [InputEventKey(keycode=KEY_D)] }
[physics]
2d/default_gravity=980.0
3d/default_gravity=9.8
[rendering]
renderer/rendering_method="forward_plus"
Advanced Usage
# Shaders (visual shader or code)
# Save as .gdshader
shader_type canvas_item;
uniform vec4 flash_color : source_color = vec4(1.0, 1.0, 1.0, 1.0);
uniform float flash_amount : hint_range(0.0, 1.0) = 0.0;
void fragment() {
vec4 tex = texture(TEXTURE, UV);
COLOR = mix(tex, flash_color, flash_amount);
COLOR.a = tex.a;
}
# Resources and save/load
var save_data = {
"health": health,
"position": {"x": position.x, "y": position.y},
"inventory": inventory
}
var json = JSON.stringify(save_data)
var file = FileAccess.open("user://save.json", FileAccess.WRITE)
file.store_string(json)
file.close()
# State machine pattern
class_name StateMachine extends Node
var current_state: State
var states: Dictionary = {}
func _ready():
for child in get_children():
if child is State:
states[child.name.to_lower()] = child
child.transitioned.connect(_on_child_transition)
func _on_child_transition(new_state_name: StringName):
var new_state = states.get(new_state_name.to_lower())
if new_state and new_state != current_state:
current_state.exit()
current_state = new_state
current_state.enter()
Export and Build
# Export presets must be configured in Editor > Export
# Then use CLI:
godot --headless --export-release "Windows Desktop" builds/game.exe
godot --headless --export-release "Linux" builds/game.x86_64
godot --headless --export-release "macOS" builds/game.dmg
godot --headless --export-release "Android" builds/game.apk
godot --headless --export-release "Web" builds/index.html
Troubleshooting
| Issue | Solution |
|---|---|
Node not found (null) | Use @onready or access in _ready(); check node path |
| Physics not working | Ensure correct body type; check collision layers/masks |
| Exported game crashes | Check debug export first; verify export templates installed |
| Import errors with assets | Reimport in editor; check .import folder |
| GDScript errors on load | Check autoload order; avoid circular dependencies |
| Performance issues | Use _physics_process for physics only; profile with built-in profiler |
| Signals not connecting | Verify signal name spelling; check node is in scene tree |
| Animation not playing | Check AnimationPlayer has the animation; verify autoplay settings |
| Tilemap collision wrong | Re-setup collision polygons on tile set |
| 3D lighting looks flat | Add environment/sky; configure DirectionalLight3D shadows |