mcpField
G
gdscript-patterns

gdscript-patterns

github.com/jame581開発889198 回インストール5 日前に更新
リポジトリ

gdscript-patterns について

Godot 4.3 以降の開発者向けGDScriptリファレンススキルです。型、コルーチン、ラムダ、パターンマッチ、アノテーション、一般的なイディオムを例とともに解説し、落とし穴や新しい言語機能も扱います。

主な機能

  1. 01静的型付けと型付きコレクション
  2. 02await とコルーチンの安全性
  3. 03ラムダ、match、一般的なイディオム
  4. 04エクスポートアノテーションとクラス定義
  5. 05よくある落とし穴と新言語機能

活用シーン

  1. 01型ヒント付き GDScript の作成
  2. 02シグナル待機とコルーチンのライフサイクル管理
  3. 03Inspector のプロパティとスクリプトクラスの整理

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jame581/godotprompter --skill gdscript-patterns

インストール後、Claude Code で/gdscript-patternsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
abstract-classes.md
common-idioms.md
export-annotations.md
lambda-functions.md
super-in-virtual-methods.md
variadic-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. アノテーションのリファレンス

アノテーション目的
@exportInspector で変数を公開します
@export_rangeスライダー付きの数値を設定します
@export_enum文字列リストからドロップダウンを作成します
@export_fileファイルパスの選択欄を作成します
@export_dirディレクトリの選択欄を作成します
@export_multiline複数行テキストボックスを作成します
@export_groupInspector にグループ見出しを表示します
@export_subgroupサブグループ見出しを表示します
@export_categoryカテゴリー区切りを表示します
@onreadyノードの準備ができたとき、_ready() の本体が実行される直前に初期化します
@toolエディターでスクリプトを実行します
@iconスクリプトにカスタムアイコンを設定します
@warning_ignore次の行に対する特定の警告を抑制します
@static_unloadstatic 変数を解放できるようにします

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+)

コメント