Reference quest

GDScript Cheat Sheet. Use syntax reference as a practice companion, not a replacement for tiny scripts.

10-20 min · Godot 4.7
gdscript
# Using $ shorthand (recommended)
var player = $Player

# Using get_node()
var player = get_node("Player")

# Get parent
var parent = get_parent()

# Get root of current scene
var root = get_tree().current_scene
gdscript
# Get all nodes in group "enemies"
var enemies = get_tree().get_nodes_in_group("enemies")

# Add node to group
add_to_group("enemies")

# Check if in group
if is_in_group("enemies"):
    print("I'm an enemy!")
gdscript
# Preload at top of script (recommended)
var BulletScene = preload("res://bullet.tscn")

# Or load at runtime
var BulletScene = load("res://bullet.tscn")

# Create instance
var bullet = BulletScene.instantiate()

# Add to scene tree
get_parent().add_child(bullet)

# Set position
bullet.global_position = global_position
gdscript
# Queue for deletion (safe, end of frame)
queue_free()

# Remove another node
enemy.queue_free()

# Remove after delay
await get_tree().create_timer(2.0).timeout
queue_free()
gdscript
func _process(delta):
    # Check action (defined in Project > Input Map)
    if Input.is_action_pressed("move_right"):
        position.x += speed * delta
    
    # Check just pressed (single frame)
    if Input.is_action_just_pressed("jump"):
        velocity.y = jump_force
gdscript
func _physics_process(delta):
    var direction = Input.get_vector(
        "move_left", "move_right",
        "move_up", "move_down"
    )
    velocity = direction * speed
    move_and_slide()
gdscript
# Change scene by path
get_tree().change_scene_to_file("res://levels/level2.tscn")

# Reload current scene
get_tree().reload_current_scene()

# Quit game
get_tree().quit()
gdscript
# Pause
get_tree().paused = true

# Unpause
get_tree().paused = false

# Make a node ignore pause (e.g., pause menu)
# Set in Inspector: Process Mode = Always
gdscript
# Define signal at top of script
signal health_changed(new_health)
signal died

# Emit signal
func take_damage(amount):
    health -= amount
    health_changed.emit(health)
    
    if health <= 0:
        died.emit()
gdscript
# Connect in code
player.health_changed.connect(_on_health_changed)
player.died.connect(_on_player_died)

# Handler functions
func _on_health_changed(new_health):
    health_bar.value = new_health

func _on_player_died():
    show_game_over()
gdscript
# 4.6+ adds new GDScript warnings:

# 1. Never-emitted signals
signal unused_signal  # Warning: signal is never emitted

# 2. Bad export defaults
@export var speed: float = "not_a_float"  # Warning

# 3. Unresolvable node paths
@onready var missing = $NonExistentNode  # Warning

# Fix: emit your signals or remove unused ones
signal health_changed(new_health)
func take_damage(amount):
    health -= amount
    health_changed.emit(health)  # Good: signal is emitted
gdscript
# Using await (recommended for simple delays)
await get_tree().create_timer(2.0).timeout
print("2 seconds passed!")

# In a function
func spawn_enemy():
    await get_tree().create_timer(1.0).timeout
    var enemy = EnemyScene.instantiate()
    add_child(enemy)
gdscript
# In _ready(), start the timer
$Timer.start()

# Connect timeout signal in code
$Timer.timeout.connect(_on_timer_timeout)

# Or connect in Editor, then:
func _on_timer_timeout():
    spawn_wave()
    
# One-shot timer (doesn't repeat)
$Timer.one_shot = true
gdscript
# Create a tween
var tween = create_tween()

# Animate position over 1 second
tween.tween_property($Sprite, "position", Vector2(200, 100), 1.0)

# Chain multiple animations
tween.tween_property($Sprite, "modulate:a", 0.0, 0.5)
tween.tween_callback(queue_free)  # Delete after fade
gdscript
var tween = create_tween()

# Set easing for smooth motion
tween.set_ease(Tween.EASE_OUT)
tween.set_trans(Tween.TRANS_ELASTIC)

# Animate with easing
tween.tween_property($Sprite, "scale", Vector2(2, 2), 0.5)

# Parallel animations (run at same time)
tween.set_parallel(true)
tween.tween_property($Sprite, "position:x", 200, 0.5)
tween.tween_property($Sprite, "rotation", PI, 0.5)
gdscript
# Add to group in code
add_to_group("enemies")
add_to_group("damageable")

# Check if in group
if is_in_group("enemies"):
    print("I'm an enemy!")

# Remove from group
remove_from_group("enemies")
gdscript
# Get all nodes in group
var enemies = get_tree().get_nodes_in_group("enemies")

for enemy in enemies:
    enemy.take_damage(10)

# Call method on all (shorthand)
get_tree().call_group("enemies", "take_damage", 10)

# Notify group (deferred, safer)
get_tree().notify_group("enemies", NOTIFICATION_PAUSED)
gdscript
# Save dictionary to JSON
var save_data = {
    "player_name": "Hero",
    "score": 1000,
    "level": 5
}

var file = FileAccess.open("user://save.json", FileAccess.WRITE)
file.store_string(JSON.stringify(save_data))
file.close()
gdscript
# Load JSON save file
if FileAccess.file_exists("user://save.json"):
    var file = FileAccess.open("user://save.json", FileAccess.READ)
    var json = JSON.new()
    json.parse(file.get_as_text())
    var save_data = json.data
    
    player_name = save_data.player_name
    score = save_data.score
gdscript
# Lambdas now properly capture outer variables (4.6+)
var multiplier = 3
var scale_func = func(value): return value * multiplier

print(scale_func.call(10))  # 30

# Works in signal connections
var damage = 50
$Area2D.body_entered.connect(
    func(body):
        if body.has_method("take_damage"):
            body.take_damage(damage)
)

# Array operations with lambdas
var enemies = get_tree().get_nodes_in_group("enemies")
var alive = enemies.filter(func(e): return e.health > 0)
var names = enemies.map(func(e): return e.name)
gdscript
# NEW in 4.6: Drag a node from the Scene Tree
# directly into the script editor to auto-create:

@export var player: CharacterBody2D
@export var health_bar: ProgressBar
@export var spawn_point: Marker2D

# Also works with resources from FileSystem:
@export var enemy_scene: PackedScene
@export var hit_sound: AudioStream
Tutor Checkpoint

Lock the pattern in

Before jumping to the next page, turn the idea into one tiny scene or script. That is where the Godot habit sticks.

Unity habit

Look up the GDScript shape of familiar C# ideas.

Unreal habit

Find the compact code version of common Blueprint flow.

Godot habit

Copy syntax, then rename it into your own gameplay context.

Try this

Take one snippet and add an exported tuning value plus a signal.

Frequently asked questions

What does the GDScript Cheat Sheet cover?
Variables, functions, signals, exports, types, control flow, classes, arrays, dictionaries, and common patterns — all with copy-paste code examples for Godot 4.
Is this cheat sheet for Godot 4 or Godot 3?
This cheat sheet covers Godot 4 and GDScript 2.0 syntax, including typed variables, @export annotations, and the await keyword.
Can I use this cheat sheet offline?
The site works in any browser. You can bookmark the page or use your browser's save feature for offline reference.