PluginBench
Skill
Pass
Audit score 90

godot-gdscript

gamedev-skills/awesome-gamedev-agent-skills

Write idiomatic GDScript 2.0 for Godot 4.7 with static typing, lifecycle callbacks, and signals.

What is godot-gdscript?

Master GDScript for Godot 4.7, including static typing, node lifecycle (_ready/_process/_physics_process), @export/@onready annotations, signals, and await for async flow. Use when writing or debugging .gd scripts, or porting Godot 3.x scripts to 4.x.

  • Write statically typed GDScript with type inference and compile-time error checking
  • Use node lifecycle callbacks (_ready, _process, _physics_process) correctly for their intended purpose
  • Declare and connect signals with typed parameters using 4.x Callable syntax
  • Pause execution with await for timers and signals instead of 3.x yield
  • Expose inspector-editable variables with @export and resolve node references with @onready
  • Port Godot 3.x GDScript to 4.x (yield→await, export→@export, signal API changes)

How to install godot-gdscript

npx skills add https://github.com/gamedev-skills/awesome-gamedev-agent-skills --skill godot-gdscript
Prerequisites
  • Godot 4.7 installed with a project.godot file
  • Basic familiarity with GDScript syntax or similar dynamically-typed languages
Claude Code
Cursor
Windsurf
Cline

How to use godot-gdscript

  1. 1.Open or create a .gd script in your Godot project
  2. 2.Declare variables with explicit types (e.g., var hp: int = 10) and use @export for Inspector exposure
  3. 3.Implement _ready() for one-time initialization and _process(delta) or _physics_process(delta) for per-frame updates
  4. 4.Use @onready to resolve node references ($NodePath) after the node enters the tree
  5. 5.Define signals with typed parameters and emit them as methods (signal_name.emit(...))
  6. 6.Connect signals using Callables (signal_name.connect(callback_function)) and use await to pause for timers or signals

Use cases

Good for
  • Writing movement and physics code in _physics_process for frame-rate independent gameplay
  • Declaring health/damage systems with typed signals that emit and connect with Callables
  • Creating inspector-tunable game parameters with @export and @export_range annotations
  • Implementing async sequences like timed effects or waiting for player input with await
  • Debugging parse errors and type mismatches in the Godot Debugger panel
Who it's for
  • Game developers writing Godot 4.x gameplay scripts
  • Developers porting Godot 3.x projects to Godot 4.x
  • Game designers using @export to tune game balance in the Inspector
  • Anyone debugging GDScript parse or runtime errors in Godot 4.7

godot-gdscript FAQ

When should I use _process vs _physics_process?

Use _process(delta) for rendering and input-driven logic; use _physics_process(delta) for movement, move_and_slide(), and physics interactions. Physics runs on a fixed tick independent of frame rate.

How do I migrate yield() from Godot 3.x to 4.x?

Replace yield(obj, "signal") with await obj.signal and yield(get_tree(), "timeout") with await get_tree().create_timer(seconds).timeout.

Why does @onready fail in _init()?

Child nodes do not exist in the scene tree during _init(). Use @onready or initialize node references in _ready() instead.

How do I connect signals in Godot 4.x?

Use the Callable syntax: signal_name.connect(callback_function). The old string-based connect("signal", self, "_method") is deprecated.

What is class_name and when do I need it?

class_name registers a script as a global type usable in other scripts and the Inspector. It must be unique project-wide and is required to reference the type by name.

Full instructions (SKILL.md)

Source of truth, from gamedev-skills/awesome-gamedev-agent-skills.


name: godot-gdscript description: > Write idiomatic GDScript for Godot 4.7: static typing, the node lifecycle (_ready/_process/_physics_process), @export/@onready/@tool annotations, signals, and await for asynchronous flow. Use when editing .gd scripts in a Godot project (project.godot), writing or debugging GDScript, or porting 3.x GDScript to 4.x (function signatures, yield to await, export to @export).

Godot GDScript (4.x)

Write correct, statically typed GDScript and use the node lifecycle and signal system the way the engine intends. Targets Godot 4.7 (GDScript 2.0).

When to use

  • Use when writing or fixing .gd files: declaring variables, functions, classes, using @export/@onready, connecting signals, or awaiting coroutines/signals.
  • Use when porting Godot 3.x scripts to 4.x and the script no longer parses.

When not to use: scene/node structure and instancing questions → godot-nodes-scenes; signal architecture/decoupling patterns → godot-signals-groups; using C# instead of GDScript → godot-csharp.

Core workflow

  1. Type everything you can. GDScript 2.0 supports static types (var hp: int = 10, func add(a: int, b: int) -> int:). Types catch errors at parse time and speed up the VM. Use := for inferred types.
  2. Use the lifecycle callbacks for their purpose: _ready() once when the node and its children enter the tree; _process(delta) every rendered frame; _physics_process(delta) on the fixed physics tick (use it for movement/physics).
  3. Grab node references with @onready, not in _init() — children do not exist until the node enters the tree.
  4. Expose tunables with @export so designers edit them in the Inspector.
  5. React to events with signals + await, not polling, where it reads cleanly.
  6. Run and read errors. The Debugger panel prints typed errors with line numbers; fix the first error first (later ones are often cascades).

Patterns

1. A typed script with lifecycle, @export, and @onready

extends Node2D
class_name Spinner            # registers a global type usable in other scripts

@export var speed: float = 90.0          # editable in the Inspector (degrees/sec)
@export_range(0, 10, 0.5) var wobble := 2.0
@onready var sprite: Sprite2D = $Sprite2D # resolved when the node enters the tree

func _ready() -> void:
    # Runs once, after children are ready. Safe to touch $Sprite2D here.
    sprite.modulate = Color.AQUA

func _process(delta: float) -> void:
    # delta is seconds since last frame; multiply rates by it for FPS independence.
    rotation_degrees += speed * delta

2. Signals: declare, emit, connect (4.x Callable syntax)

extends Node

signal health_changed(current: int, maximum: int)   # typed signal params

var health := 100

func take_damage(amount: int) -> void:
    health = max(health - amount, 0)
    health_changed.emit(health, 100)     # 4.x: emit as a method on the signal

func _ready() -> void:
    # 4.x: connect with a Callable, not a string method name.
    health_changed.connect(_on_health_changed)

func _on_health_changed(current: int, maximum: int) -> void:
    print("HP: %d/%d" % [current, maximum])

3. await — pause until a timer or signal fires (replaces 3.x yield)

func flash_then_continue() -> void:
    modulate = Color.RED
    await get_tree().create_timer(0.2).timeout   # resume after 0.2s
    modulate = Color.WHITE
    # await any signal: var result = await some_node.some_signal

4. Lambdas, typed arrays, and safe access

var enemies: Array[Node] = []                    # typed array

func cull_dead() -> void:
    enemies = enemies.filter(func(e): return e.is_inside_tree())

func get_first_name(d: Dictionary) -> String:
    return d.get("name", "unknown")              # default avoids missing-key errors

Pitfalls

  • 3.x → 4.x signal API changed. emit_signal("x") still works but prefer x.emit(...); connect("x", self, "_on_x") is gone — use x.connect(_on_x) with a Callable. yield(obj, "sig") is now await obj.sig.
  • export var is now @export var (annotation). Likewise onready→@onready, tool→@tool, remote/master RPC keywords → the @rpc(...) annotation.
  • @onready and $NodePath in _init() fail — the node isn't in the tree yet. Initialize node references in _ready() or with @onready.
  • Integer division truncates. 5 / 2 == 2. Use 5.0 / 2 or cast to float.
  • _process vs _physics_process. Put move_and_slide() and physics in _physics_process(delta); using _process makes motion frame-rate dependent.
  • class_name must be unique project-wide and is required to use the type name in other scripts or as an Inspector type.

References

  • For the full annotation list, advanced typing, and style conventions, read references/annotations-and-typing.md.

Related skills

  • godot-nodes-scenes — the scene tree, instancing, and autoloads.
  • godot-signals-groups — event-driven architecture with signals and groups.
  • godot-resources — data-driven design with custom Resource types.
  • godot-csharp — the same engine concepts using C#/.NET.