本文へ移動
cccskills
無料GitHub で公開

gdscript-patterns

Use when writing GDScript — static typing, await/coroutines, lambdas, match patterns, export annotations, inner classes, and common idioms

インストール方法を見る

含まれるファイル(7)

  • SKILL.md13.8 KB
  • references/abstract-classes.md2.4 KB
  • references/common-idioms.md2.5 KB
  • references/export-annotations.md1.8 KB
  • references/lambda-functions.md2.2 KB
  • references/super-in-virtual-methods.md2.7 KB
  • references/variadic-functions.md1.8 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

GDScript Patterns in Godot 4.3+

All examples target Godot 4.3+ with no deprecated APIs.

Related skills: gdscript-advanced for production-grade depth (performance idioms, metaprogramming, @tool lifecycle, profiler-driven idioms), godot-code-review for style rules and anti-patterns, csharp-godot for GDScript-to-C# translation, state-machine for state patterns, event-bus for signal architecture.

Note: This skill is GDScript-specific by design. For C# patterns, see csharp-godot and csharp-signals.


1. Static Typing

Type Hints

Always add type hints — they catch bugs at parse time, improve autocomplete, and boost performance.

# Variables
var health: int = 100
var speed: float = 200.0
var player_name: String = "Hero"
var direction: Vector2 = Vector2.ZERO

# Constants
const MAX_HEALTH: int = 100
const GRAVITY: float = 980.0

# Functions — parameters and return type
func take_damage(amount: int) -> void:
    health -= amount

func get_direction() -> Vector2:
    return Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")

# Inferred typing with :=
var pos := Vector2(100, 200)     # inferred as Vector2
var items := []                  # inferred as Array (untyped)
var count := 0                   # inferred as int

Typed Collections

# Typed arrays — only accepts the specified type
var enemies: Array[Enemy] = []
var scores: Array[int] = [10, 20, 30]
var names: Array[String] = ["Alice", "Bob"]

# Typed dictionaries (Godot 4.4+)
var inventory: Dictionary[String, int] = {"sword": 1, "potion": 5}

# Typed loop variable
for enemy: Enemy in enemies:
    enemy.take_damage(10)

# Typed array methods work with type safety
var filtered: Array[Enemy] = enemies.filter(func(e: Enemy) -> bool: return e.health > 0)

Casting with as and is

# 'is' — type check (returns bool)
func _on_body_entered(body: Node2D) -> void:
    if body is Player:
        var player: Player = body as Player
        player.take_damage(10)

# 'as' — cast (returns null on failure, no error)
var sprite := get_node("Sprite") as Sprite2D
if sprite:
    sprite.modulate = Color.RED

# Prefer 'is' check + cast over bare 'as' to avoid null surprises

Enabling Strict Typing Warnings

In Project > Project Settings > Debug > GDScript:

WarningEffect
UNTYPED_DECLARATIONWarns on any untyped variable/parameter
INFERRED_DECLARATIONWarns on := (prefers explicit types)
UNSAFE_CASTWarns on unsafe as casts
UNSAFE_CALL_ARGUMENTWarns when passing wrong type to a function

Set warnings to Error for strict enforcement in team projects.

Typed Return Inheritance in Overrides

⚠️ Changed in Godot 4.7: Methods that override a method with a typed return now inherit the return type, so an override without an explicit return statement becomes an error. Add return null (or a typed return value) at the end of the override. See the 4.7 migration guide.

class Enemy:
    var weapon: Node
    func get_weapon() -> Node:
        return weapon

class UnarmedEnemy extends Enemy:
    func get_weapon():  # 4.7+: inherits -> Node from Enemy
        return null     # explicit return now required — omitting it is an error

2. Await & Coroutines

Awaiting Signals

await pauses the function until a signal fires, then resumes. The function becomes a coroutine.

func death_sequence() -> void:
    $AnimationPlayer.play("death")
    await $AnimationPlayer.animation_finished  # pauses here

    $Sprite2D.visible = false
    await get_tree().create_timer(1.0).timeout  # wait 1 second

    queue_free()

Awaiting with Return Values

# Signal that passes data
signal dialogue_choice_made(choice: int)

func show_dialogue(options: Array[String]) -> int:
    # ... display UI ...
    var choice: int = await dialogue_choice_made
    return choice

# Caller:
func _on_npc_interact() -> void:
    var result := await show_dialogue(["Yes", "No"])
    if result == 0:
        print("Player said yes")

Timer Patterns

# One-shot delay
await get_tree().create_timer(0.5).timeout

# Repeating with await (simple but blocks the function)
for i in 5:
    do_something()
    await get_tree().create_timer(0.2).timeout

# Non-blocking timer — use SceneTreeTimer or Tween instead
get_tree().create_timer(2.0).timeout.connect(_on_delayed_action)

Coroutine Safety

# DANGER: `target` may be freed while this coroutine waits
func unsafe_coroutine(target: Node2D) -> void:
    await get_tree().create_timer(5.0).timeout
    target.position = Vector2.ZERO  # error: previously freed instance

# SAFE: re-check other objects after every await
func safe_coroutine(target: Node2D) -> void:
    await get_tree().create_timer(5.0).timeout
    if not is_instance_valid(target):
        return
    target.position = Vector2.ZERO

A freed node's own coroutine never resumes, so is_instance_valid(self) after await guards nothing.


3. Lambda Functions

Lambdas are inline anonymous functions for callbacks, sorting, and filtering, called with .call(). The reference covers single- and multi-line syntax, inline signal connections including CONNECT_ONE_SHOT, Array methods (filter, map, reduce, any, all, sort_custom), and closures, where locals are captured by value.

See references/lambda-functions.md for the syntax, signal, Array method, and closure examples.


4. Match / Pattern Matching

GDScript's match is like switch but with pattern support.

Basic Match

match state:
    State.IDLE:
        play_idle()
    State.RUNNING:
        play_run()
    State.JUMPING, State.FALLING:  # multiple patterns
        play_air()
    _:  # default (wildcard)
        push_warning("Unknown state: %s" % state)

Pattern Types

# Literal patterns
match value:
    42:
        print("The answer")
    "hello":
        print("Greeting")
    true:
        print("Boolean true")

# Binding pattern — captures value into a variable
match command:
    ["move", var direction]:
        move(direction)
    ["attack", var target, var damage]:
        attack(target, damage)

# Array pattern
match input:
    [1, 2, 3]:
        print("Exact match")
    [1, ..]:
        print("Starts with 1")
    [var first, _, var last]:
        print("First: %s, Last: %s" % [first, last])

# Dictionary pattern
match event:
    {"type": "damage", "amount": var amt}:
        take_damage(amt)
    {"type": "heal", "amount": var amt}:
        heal(amt)

# Nested condition inside a branch
match enemy_type:
    "boss":
        if health < 50:
            enter_rage_mode()
        else:
            normal_attack()

5. Export Annotations

@export exposes a variable to the Inspector. Hint variants (@export_range, @export_enum, @export_file) constrain editor input. Use @export_group and @export_subgroup to organize. Node and Resource exports use NodePath / typed Resource references.

See references/export-annotations.md for the full export annotation catalog (basic exports, range/hint variants, groups, node and Resource exports).


6. Inner Classes & class_name

class_name

Register a script as a global class name — available everywhere without preload.

# item_data.gd
class_name ItemData
extends Resource

@export var name: String
@export var icon: Texture2D
@export var value: int

# Now usable anywhere:
# var item: ItemData = ItemData.new()
# var items: Array[ItemData] = []

Inner Classes

# Define a class inside another script
class HitResult:
    var damage: int
    var critical: bool
    var knockback: Vector2

    func _init(dmg: int, crit: bool, kb: Vector2 = Vector2.ZERO) -> void:
        damage = dmg
        critical = crit
        knockback = kb

# Usage
func calculate_hit() -> HitResult:
    var crit := randf() < 0.2
    var dmg := 10 * (2 if crit else 1)
    return HitResult.new(dmg, crit, Vector2.RIGHT * 50)

7. super() in Virtual Methods

When you override a virtual method that the engine calls (_ready, _process, _input, etc.) and your parent class also implements it, call super() to chain the parent's behavior. Forgetting to call super._ready() is the most common cause of "my base class init didn't run" bugs.

See references/super-in-virtual-methods.md for the full pattern (problem / fix), the C# base.X() equivalent, and a catalog of bugs from missing super calls.


8. Common Idioms

The recurring small patterns: ternary expressions (value if cond else other), printf-style string formatting ("%s %d" % [a, b]), null/empty checks (is_instance_valid vs != null, empty Array/String checks), Dictionary access (get(key, default)), Array operations (Array.has, Array.find, Array.has_all), setget via set and get accessors.

See references/common-idioms.md for full code examples of each idiom.


9. Annotations Reference

AnnotationPurpose
@exportExpose variable in Inspector
@export_rangeNumeric with slider
@export_enumDropdown from string list
@export_fileFile path picker
@export_dirDirectory picker
@export_multilineMulti-line text box
@export_groupGroup heading in Inspector
@export_subgroupSubgroup heading
@export_categoryCategory divider
@onreadyInitialize when node enters tree, just before _ready() body runs
@toolRun script in editor
@iconCustom icon for the script
@warning_ignoreSuppress specific warning on next line
@static_unloadAllow static variables to be freed

10. Common Pitfalls

SymptomCauseFix
as cast silently returns nullType mismatch — as doesn't errorUse is check first, then cast
Await never resumesSignal never emitted, or this node was freed (coroutine dropped)Check the condition before awaiting; race slow signals against a timer
Lambda's change to a variable is lostLocals are captured by valueKeep shared state in a member, Array or Dictionary
UNTYPED_DECLARATION warnings floodWarning enabled but codebase isn't typedType incrementally; use @warning_ignore for legacy code
Typed array rejects valid itemsItem type doesn't match exactlyEnsure items match the declared type (no implicit upcasting)
@onready is nullAccessed before _ready() runsNever access @onready vars in _init() or variable declarations
Match doesn't enter any branchNo matching pattern and no _: wildcardAlways add _: default branch
class_name conflictTwo scripts with same class_nameUse unique names; check for duplicates in Project
Export group applies to wrong varsGroup scope continues until next groupAdd a new @export_group("") to end the group scope
Parent _ready() logic doesn't run in childMissing super() call in child's _ready()Add super() as first line; see Section 7
type_exists() flagged as deprecatedDeprecated in Godot 4.7Use ClassDB.class_exists() instead

⚠️ Changed in Godot 4.7: The global type_exists() function is deprecated — replace type_exists("Sprite2D") with ClassDB.class_exists("Sprite2D"). See GH-116899.


11. Variadic Functions (Godot 4.5+)

Godot 4.5 added trailing-argument arrays via ...args. The args are collected into an Array. Useful for printf-style helpers and flexible APIs without overloads.

See references/variadic-functions.md for the full syntax, common patterns, and notes on when to prefer overloads.


12. Abstract Classes and Methods (Godot 4.5+)

The @abstract annotation prevents direct instantiation of a class and forces subclasses to implement any @abstract-annotated method (similar to C#'s abstract keyword).

See references/abstract-classes.md for full base-class patterns and subclass implementation rules.


13. Implementation Checklist

  • All variables, parameters, and return types have explicit type hints
  • Typed arrays (Array[Type]) are used instead of untyped Array where possible
  • Other nodes used after an await are re-checked with is_instance_valid() (self needs no check)
  • Lambdas connected to signals are simple — complex logic goes in named methods
  • match statements include a _: default branch
  • @export variables use appropriate hints (@export_range, @export_enum, etc.)
  • @export_group organizes Inspector properties into logical sections
  • class_name is only used for scripts that need global visibility
  • is type check precedes as cast when the type isn't guaranteed
  • Properties with setters validate and clamp values
  • Overridden virtual methods call super() when extending non-built-in base classes
  • Variadic functions (...args) used when the number of trailing arguments is open-ended (Godot 4.5+)
  • Base classes that must not be instantiated use @abstract; required methods use @abstract func (Godot 4.5+)

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Use when working with 2D-specific systems — TileMaps, parallax scrolling, 2D lights and shadows, canvas layers, particles 2D, custom drawing, and 2D meshes in Godot 4.3+

日本語の概要は準備中です。原文の説明を表示しています。

jame581/GodotPrompter8082026年10月11日 更新

Use when working with 3D-specific systems — materials, lighting, shadows, environment, global illumination, fog, LOD, occlusion culling, and decals in Godot 4.3+

日本語の概要は準備中です。原文の説明を表示しています。

jame581/GodotPrompter8082026年10月11日 更新

Use when building character abilities — Resource-based abilities with cost/cooldown/cast, buffs/debuffs, stat modifiers, gameplay tags, and HUD binding

日本語の概要は準備中です。原文の説明を表示しています。

jame581/GodotPrompter8082026年10月11日 更新

Use when creating Godot editor plugins — EditorPlugin, @tool scripts, custom inspectors, and dock panels

日本語の概要は準備中です。原文の説明を表示しています。

jame581/GodotPrompter8082026年10月11日 更新

Use when implementing AI movement — NavigationAgent2D/3D, steering behaviors, behavior trees, and patrol patterns

日本語の概要は準備中です。原文の説明を表示しています。

jame581/GodotPrompter8082026年10月11日 更新

Use when implementing animations — AnimationPlayer, AnimationTree, blend trees, state machines, sprite animation, and code-driven animation

日本語の概要は準備中です。原文の説明を表示しています。

jame581/GodotPrompter8082026年10月11日 更新

jame581 のスキルをすべて見る

このスキルの問題を報告する