gdscript-patterns について
Godot 4.3 以降の開発者向けGDScriptリファレンススキルです。型、コルーチン、ラムダ、パターンマッチ、アノテーション、一般的なイディオムを例とともに解説し、落とし穴や新しい言語機能も扱います。
主な機能
- 01静的型付けと型付きコレクション
- 02await とコルーチンの安全性
- 03ラムダ、match、一般的なイディオム
- 04エクスポートアノテーションとクラス定義
- 05よくある落とし穴と新言語機能
活用シーン
- 01型ヒント付き GDScript の作成
- 02シグナル待機とコルーチンのライフサイクル管理
- 03Inspector のプロパティとスクリプトクラスの整理
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jame581/ godotprompter --skill gdscript-patternsインストール後、Claude Code で/gdscript-patternsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/abstract-classes.mdcommon-idioms.mdexport-annotations.mdlambda-functions.mdsuper-in-virtual-methods.mdvariadic-functions.md詳細
Godot 4.3+ における GDScript のパターン
すべての例は、非推奨 API を使わずに Godot 4.3+ を対象としています。
関連スキル: 本番品質の深い知識(パフォーマンスの定石、メタプログラミング、@tool のライフサイクル、プロファイラーに基づく定石)については gdscript-advanced、スタイルルールとアンチパターンについては godot-code-review、GDScript から C# への変換については csharp-godot、ステートパターンについては state-machine、シグナルアーキテクチャについては event-bus を参照してください。
注: このスキルは、GDScript に特化して設計されています。C# のパターンについては、csharp-godot と csharp-signals を参照してください。
1. 静的型付け
型ヒント
型ヒントは常に追加してください。解析時にバグを検出でき、オートコンプリートが改善され、パフォーマンスも向上します。
# 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 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)
as と 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
厳密な型付けの警告を有効にする
Project > Project Settings > Debug > GDScript で設定します。
| 警告 | 効果 |
|---|---|
UNTYPED_DECLARATION | 型指定のない変数/パラメーターすべてに警告を表示します |
INFERRED_DECLARATION | := に警告を表示します(明示的な型を推奨します) |
UNSAFE_CAST | 型指定のない(Variant の)値を型にキャストすると警告を表示します |
UNSAFE_CALL_ARGUMENT | 引数の型がパラメーターの型の上位型である場合(Node を Node2D パラメーターに渡す場合など)に警告を表示します |
チームのプロジェクトで厳密に適用するには、警告を Error に設定してください。
オーバーライドにおける型付き戻り値の継承
⚠️ Godot 4.7 で変更: 型付き戻り値を持つメソッドをオーバーライドすると、戻り値の型が継承されるようになりました。そのため、明示的な
return文がないオーバーライドはエラーになります。オーバーライドの末尾にreturn null(または型付きの戻り値)を追加してください。4.7 移行ガイドを参照してください。
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 とコルーチン
シグナルの await
await はシグナルが発火するまで関数を一時停止し、その後再開します。関数はコルーチンになります。
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()
戻り値を伴う await
# 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")
タイマーパターン
# 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)
コルーチンの安全性
# 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
解放されたノード自身のコルーチンは再開されないため、await の後の is_instance_valid(self) は何も保護しません。
3. ラムダ関数
ラムダは、コールバック、ソート、フィルタリングに使うインラインの無名関数で、.call() で呼び出します。リファレンスでは、単一行と複数行の構文、CONNECT_ONE_SHOT を含むインラインのシグナル接続、Array のメソッド(filter、map、reduce、any、all、sort_custom)、およびローカル変数を値でキャプチャするクロージャーを解説しています。
構文、シグナル、
Arrayメソッド、クロージャーの例については、references/lambda-functions.md を参照してください。
4. Match/パターンマッチング
GDScript の match は、パターンをサポートする switch のようなものです。
基本的な 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)
パターンの種類
# 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 は、変数をインスペクターに公開します。ヒントのバリエーション(@export_range、@export_enum、@export_file)を使うと、エディターでの入力を制限できます。整理には @export_group と @export_subgroup を使用します。ノードとリソースのエクスポートには、NodePath または型付き Resource 参照を使用します。
エクスポートアノテーションの全カタログ(基本的なエクスポート、範囲/ヒントのバリエーション、グループ、ノードと Resource のエクスポート)については、references/export-annotations.md を参照してください。
6. 内部クラスと class_name
class_name
スクリプトをグローバルクラス名として登録すると、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] = []
内部クラス
# 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()
エンジンが呼び出す仮想メソッド(_ready、_process、_input など)をオーバーライドし、親クラスにも実装がある場合は、super() を呼び出して親クラスの動作を連鎖させます。super._ready() の呼び出しを忘れることは、「基底クラスの初期化が実行されない」というバグの最も一般的な原因です。
完全なパターン(問題/修正)、C# の
base.X()に相当する書き方、super の呼び出し漏れによるバグの一覧については、references/super-in-virtual-methods.md を参照してください。
8. よく使われるイディオム
繰り返し使われる小さなパターンです。三項式(value if cond else other)、printf 形式の文字列フォーマット("%s %d" % [a, b])、null/空のチェック(is_instance_valid と != null の使い分け、空の Array/String のチェック)、Dictionary へのアクセス(get(key, default))、Array の操作(Array.has、Array.find、Array.has_all)、set および get アクセサーを使った setget などがあります。
各イディオムの完全なコード例については、references/common-idioms.md を参照してください。
9. アノテーションのリファレンス
| アノテーション | 目的 |
|---|---|
@export | Inspector で変数を公開します |
@export_range | スライダー付きの数値を設定します |
@export_enum | 文字列リストからドロップダウンを作成します |
@export_file | ファイルパスの選択欄を作成します |
@export_dir | ディレクトリの選択欄を作成します |
@export_multiline | 複数行テキストボックスを作成します |
@export_group | Inspector にグループ見出しを表示します |
@export_subgroup | サブグループ見出しを表示します |
@export_category | カテゴリー区切りを表示します |
@onready | ノードの準備ができたとき、_ready() の本体が実行される直前に初期化します |
@tool | エディターでスクリプトを実行します |
@icon | スクリプトにカスタムアイコンを設定します |
@warning_ignore | 次の行に対する特定の警告を抑制します |
@static_unload | static 変数を解放できるようにします |
10. よくある落とし穴
| 症状 | 原因 | 修正方法 |
|---|---|---|
as キャストがエラーなく null を返す | 型が一致していません — as はエラーを出しません | 先に is でチェックしてからキャストします |
| await から再開しない | シグナルが発行されていないか、このノードが解放されています(コルーチンが破棄されています) | await の前に条件を確認します。応答の遅いシグナルはタイマーと競合させます |
| ラムダ式内での変数の変更が失われる | ローカル変数は値でキャプチャされます | 共有状態はメンバー変数、Array、または Dictionary に保持します |
UNTYPED_DECLARATION 警告が大量に表示される | 警告は有効ですが、コードベースに型が付いていません | 段階的に型を付けます。レガシーコードには @warning_ignore を使用します |
| 型付き配列への代入に失敗する | 型なしの Array、または Array[Subclass] を Array[Type] 変数に代入しています(共変性はありません。ただしサブクラスの 要素 は受け入れられます) | 最初から型付きで宣言するか、typed.assign(other) を使用します |
@onready が null になる | _ready() の実行前にアクセスしています | _init() や変数宣言で @onready 変数にアクセスしないでください |
| Match がどの分岐にも入らない | 一致するパターンがなく、_: ワイルドカードもありません | デフォルト分岐として常に _: を追加します |
class_name の競合 | 同じ class_name を持つスクリプトが 2 つあります | 一意な名前を使用し、Project で重複を確認します |
| エクスポートグループが誤った変数に適用される | グループのスコープは次のグループまで続きます | 新しい @export_group("") を追加してグループのスコープを終了します |
子クラスで親の _ready() の処理が実行されない | 子クラスの _ready() で super() を呼び出していません | 先頭行に super() を追加します。セクション 7 を参照してください |
type_exists() が非推奨として警告される | Godot 4.7 で非推奨になりました | 代わりに ClassDB.class_exists() を使用します |
⚠️ Godot 4.7 での変更: グローバル関数
type_exists()は非推奨です。type_exists("Sprite2D")をClassDB.class_exists("Sprite2D")に置き換えてください。GH-116899 を参照してください。
11. 可変長関数(Godot 4.5+)
Godot 4.5 では、...args による末尾引数配列が追加されました。引数は Array にまとめられます。printf 形式のヘルパーや、オーバーロードを使わずに柔軟な API を実現する場合に便利です。
完全な構文、よく使われるパターン、オーバーロードを優先すべき場面については、references/variadic-functions.md をご覧ください。
12. 抽象クラスとメソッド(Godot 4.5+)
@abstract アノテーションは、クラスの直接インスタンス化を禁止し、サブクラスに @abstract アノテーション付きメソッドの実装を義務付けます(C# の abstract キーワードに似ています)。
基底クラスのパターンとサブクラスの実装規則については、references/abstract-classes.md をご覧ください。
13. 実装チェックリスト
- すべての変数、パラメーター、戻り値の型に明示的な型ヒントが指定されている
- 可能な場合は、型指定のない
Arrayではなく型指定配列(Array[Type])を使用している -
awaitの後に使用するほかのノードは、is_instance_valid()で再確認している(selfの確認は不要) - シグナルに接続するラムダはシンプルにしている — 複雑なロジックは名前付きメソッドに記述している
-
matchステートメントに_:のデフォルト分岐を含めている -
@export変数に適切なヒント(@export_range、@export_enumなど)を使用している -
@export_groupでインスペクターのプロパティを論理的なセクションに整理している -
class_nameは、グローバルに参照する必要があるスクリプトにのみ使用している - 型が保証されていない場合は、
asキャストの前にis型チェックを行っている - セッターを持つプロパティで値を検証し、範囲内に制限している
- 組み込みではない基底クラスを拡張する場合、オーバーライドした仮想メソッドで
super()を呼び出している - 末尾引数の数に制限がない場合は、可変長関数(
...args)を使用している(Godot 4.5+) - インスタンス化を禁止する基底クラスには
@abstractを使用し、必須メソッドには@abstract funcを使用している(Godot 4.5+)