mcpField
G
godot-game-loop-waves

godot-game-loop-waves

github.com/thedivergentai開発907292 回インストール2 週間前に更新
リポジトリ

godot-game-loop-waves について

敵のウェーブを実装する Godot 開発者向けスキルです。WaveResource と管理ノードでスポーン時刻やクリア条件を扱い、密度に応じて SceneTree ノードからサーバー側 RID までの構成を選べます。

主な機能

  1. 01WaveResource による遭遇データ定義
  2. 02管理ノードによる時刻とクリア条件の制御
  3. 03Marker と重み付きスポーン位置
  4. 04密度に応じたノード、MultiMesh、RID の構成
  5. 05プールと非同期パス検索のパターン

活用シーン

  1. 01ストーリーミッションの敵ウェーブ構築
  2. 02難易度が上昇するエンドレスモード作成
  3. 03プレイヤーの Area3D 進入を契機に遭遇開始
  4. 04大規模な敵群に適したスポーン構成の選択

インストール

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

$npx skills add https://github.com/thedivergentai/game-dev-agentic-skills --skill godot-game-loop-waves

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

同梱ファイル

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

references/
migration-notes.md
wave-expert-patterns.md
scripts/
wave_loop_patterns.gd
wave_manager.gd
wave_resource.gd
wave_spawner.gd
wave_weighted_spawner.gd

詳細

アーキテクチャ設計: 「Wave-State」パターン

マスター実装では、ウェーブをデータ駆動型の遷移として扱います。スポーン数をハードコードするのではなく、WaveResource を使用して「エンカウント」を定義し、WaveManager が順番に処理します。

主な役割
  • マネージャー:タイムラインを統括します。ウェーブ間の遅延を処理し、「勝利」条件(敵がすべて倒されること)を追跡します。
  • スポナー:敵が出現する位置の空間情報を提供する、疎結合のノードです(wave_spawner.gd / wave_weighted_spawner.gd)。
  • リソース:コードに触れずにデザイナーがゲームのバランスを調整できる、不変のデータコンテナーです。

密度の判断ツリー(コーディング前に規模を選択)

実行中の密度アプローチ必須の読み込み
SceneTree の敵が約 80 体未満ノードマネージャー + Marker スポナーwave_manager.gd、wave_spawner.gd、wave_resource.gd
群れのビジュアル/数百体MultiMesh + 重み付け構成wave_loop_patterns.gd(MultiMesh / 非同期パス)、wave_weighted_spawner.gd
約 10,000 体PhysicsServer / NavigationServer の RID(モブごとの Node なし)wave_loop_patterns.gd のサーバー RID パターン。wave_manager のノードスポーンでスケールさせないでください

wave_manager.gd は SceneTree の標準的な方法です(add_child を遅延実行し、グループ/シグナルでクリア数を追跡、オプションでプールを使用)。プロトタイプから中規模までを対象とします。RID 群れの場合は、数千のノードをインスタンス化せず、wave_loop_patterns.gd に従ってください。

構成の標準的な手順

  1. wave_resource.gd の構成テーブルを作成します。
  2. wave_spawner.gd の Marker を配置します(バリエーションの重み付けが必要な場合は wave_weighted_spawner.gd を使用します)。
  3. wave_manager.gd の spawner にその Marker を指定します。マネージャーはスポーンを遅延実行し、&"enemies" グループとシグナルを使ってクリアを判定します。
  4. 固定数を重み付けに置き換える場合は、構成ループから WaveWeightedSpawner.spawn_enemy() を呼び出します(または、マネージャーの spawner に重み付けノードを設定します)。

エキスパート向けコードパターン

1. 非同期ウェーブトリガー

カスタムタイムラインを作成する前に必ず読むこと。wave_manager.gd の await タイマーを使用します。スポーンには call_deferred(&"add_child", …) を使い、シグナル/グループでクリアを判定します(get_children() による走査は使用しません)。

2. 構成ベースのスポーン

wave_resource.gd でバリエーションを定義し、wave_spawner.gd / wave_weighted_spawner.gd でユニットを配置します。マネージャー内にシーンのパスをハードコードしないでください。

マスター判断マトリクス:進行方式

パターン最適な用途ロジック
リニアストーリーミッション手作業で作成した WaveResource のリスト。
エンドレスサバイバルモード乗数計算を用いてコードで生成する WaveResource。
トリガー式RPG のエンカウントプレイヤーが Area3D に入ったときのみウェーブを開始します。

絶対に避けること

  • 敵をすべて探すために get_children() を繰り返し呼び出さないでください — これは非常に低速です。敵は必ず「enemies」グループに追加し、効率的にアクセスするには get_tree().get_nodes_in_group(&"enemies") を使用してください。
  • 数百体の敵に対して、常に instantiate() と queue_free() を繰り返さないでください — これによりガベージコレクションによるカクつきが発生します。オブジェクトプールを使用して、既存の敵インスタンスを再利用してください。
  • 群れを表現するために、個別の MeshInstance3D ノードを何千個も生成しないでください — ドローコールが大幅に増加します。MultiMeshInstance3D を使用して、何千ものメッシュを単一の GPU 呼び出しにまとめてください。
  • 何百ものエージェントの経路探索をメインスレッドで計算しないでください — ゲームがフリーズします。ナビゲーション領域で use_async_iterations を有効にするか、NavigationServer3D.query_path() を使用してください。
  • 子ノードを追加する前に is_inside_tree() を確認し忘れないでください — スポナーが削除待ち状態の場合、子ノードの追加時にクラッシュします。スポナーが引き続きツリー内でアクティブであることを必ず確認してください。
  • プリロードしたリソース(stats.tres など)を、生成したモブに直接割り当てないでください — すべてのモブで同じヘルス値やステータスが共有されます。各モブに固有のデータを持たせるため、必ず base_stats.duplicate_deep() を呼び出してください。
  • 頻繁に呼び出すグループ処理に標準の文字列を使用しないでください — ハッシュ性能を最適化し、不要な文字列の割り当てを避けるため、必ず StringName(&"enemies"、&"take_damage")を使用してください。
  • 物理コールバック内でエンティティを同期的に直接生成しないでください — 物理処理中にノードをインスタンス化すると、物理状態が破損する可能性があります。必ず call_deferred(&"add_child", enemy) を使用してください。
  • 死亡した敵の CollisionShapes を有効なままにしないでください — 死体がタワーやナビゲーションを妨げます。死亡時にすぐ set_deferred("disabled", true) を使用してください。
  • 複雑な Object 型を MultiplayerSynchronizer で同期しないでください — サポートされているのはプリミティブ型のみです。複雑なデータを同期する場合は、UID または ID を同期し、クライアント側でデータをローカル検索してください。
  • プレイヤーへのフィードバックなしにウェーブを自動開始しないでください — プレイヤーが自分で判断できるよう、UI のカウントダウン、視覚的な「ウェーブ接近中」エフェクト、または開始ボタンを必ず用意してください。
  • スポーン位置を (0,0,0) にハードコードしないでください — エディターで Marker3D ノードを使用すれば、コードを調べずにスポーンポイントを視覚的に調整できます。
  • 毎フレーム、子ノードを数えてウェーブの完了を確認しないでください — 処理コストが高すぎます。ローカルカウンターを維持するか、シグナルベースのシステムを使用して、アクティブな敵の数を追跡してください。
  • すべてのエンティティタイプに同じナビゲーションマップを使用しないでください — 飛行する敵と歩行する敵がいる場合は、経路探索の問題を防ぐため、別々のナビゲーションマップを使用してください。
  • スポナーのコリジョンシェイプを不均等にスケーリングしないでください — コリジョン検出の計算が破綻します。代わりにシェイプリソースのプロパティを調整してください。

利用可能なスクリプト

必須:対応するパターンを実装する前に、適切なスクリプトを読んでください。

wave_loop_patterns.gd

エキスパート向けパターン 10 種:MultiMesh による群れ、非同期経路探索、バックグラウンドでのプリロード、サーバー側の物理モブ。

wave_manager.gd

タイムラインとウェーブ間の遅延を管理し、グループ数とシグナルを使って全滅を追跡します。call_deferred による add_child を使用し、use_pool / recycle_enemy によるプールは任意です。

wave_resource.gd

ウェーブの構成と難易度設定のデータコンテナー。

wave_spawner.gd

Marker3D の空間ポータル — オプションで半径方向のジッターを加えた get_spawn_position() を使用します。WaveManager.spawner として接続してください。

wave_weighted_spawner.gd

Marker で重み付きランダム選択によって敵を選びます。固定数ではなく、確率に基づいて構成にバリエーションを持たせる場合に使用してください。


エキスパート向けウェーブパターン

1. 群れのオクルージョンカリング

何百もの敵がいる場合のパフォーマンスを最適化するには、オクルージョンカリングを有効にします。

  • 設定:アリーナに OccluderInstance3D を追加してベイクします。
  • 結果:壁や柱の背後に完全に隠れた敵は GPU で処理されなくなり、FPS が大幅に向上します。
2. ウェーブ UI アーキテクチャ

CanvasLayer とシグナルを使用して、ウェーブデータと UI を分離します。

  • ウェーブカウンター:現在のウェーブ数と合計ウェーブ数を表示します。
  • ヘルスバー:ボスには CanvasLayer 上の TextureProgressBar を使用するか、個々の敵のヘルスバーにはビューポートテクスチャを使った Sprite3D を使用します。

必要に応じて参照する専門知識

LLM の無知に関するルール: 一般的なエージェントが読む前に知らない情報は、参照資料を読み込んでください。専門的な差分は決して削除しないでください。

参考資料

段階的な情報開示:特定の API を調査するときにのみ公式ドキュメントのリンクを開き、関連分野へ案内するときにのみ関連スキルを読み込んでください。関連情報をすべて事前に読み込まないでください。

公式ドキュメント
  • リソース — WaveResource の構成と遅延をデザイナーが編集できるようにし、マネージャーにスポーンテーブルをハードコードせずに済みます。
  • ノードとシーンインスタンス — PackedScene.instantiate() と add_child / call_deferred を組み合わせる方法は、ウェーブの敵を安全にスポーンする手段です。
  • グループ — 毎フレーム子ノードを走査する代わりに、StringName グループと get_node_count_in_group を使って生存中の敵を追跡します。
  • アイドル処理と物理処理 — タイミング制御にはタイマー/await を使用します。遅延処理せずに物理コールバック中にインスタンス化しないでください。
  • SceneTreeTimer — ウェーブ開始前の遅延やスポーン間隔には create_timer を使用し、終了しない _process のカウントダウンは避けます。
  • シグナルの使用 — wave_started / wave_cleared / all_waves_complete により、UI、オーディオ、戦闘処理をマネージャーのタイムラインから分離できます。
  • バックグラウンド読み込み — ボスや負荷の高いウェーブには ResourceLoader.load_threaded_request を使用し、最初のスポーン時に処理が停止するのを防ぎます。
  • 乱数生成 — RandomNumberGenerator.rand_weighted を使用して、重み付きの構成とスポーンの揺らぎを設定します。
  • MultiMesh の使用 — ミニオンが何百体もいてドローコールが急増する場合は、群れのビジュアルをまとめて描画します。
  • オクルージョンカリング — カメラ外のアリーナの敵を非表示にし、密集したウェーブでも GPU の負荷を抑えます。
  • ナビゲーションの概要(3D) — 非同期のエージェント経路と、飛行ユニット用・歩行ユニット用に分けたマップを使用します。
  • サーバーの使用 — SceneTree のノードでは拡張性が足りない場合は、PhysicsServer3D/NavigationServer3D の RID で群れを管理します。
関連スキル
前提条件
  • godot-project-foundations — WaveManager をアリーナに組み込む前に、シーンツリー、エクスポート、グループについて確認します。
  • godot-gdscript-mastery — 非同期のウェーブトリガーが依存する、型付き await、シグナル、call_deferred のパターンを扱います。
  • godot-resource-data-patterns — Resource/@export による構成と duplicate_deep を扱い、スポーンした敵同士でステータスが共有されないようにします。
補完
  • godot-signal-architecture — ウェーブ/UI/戦闘シグナルの所有権を扱い、カウントダウンとクリアイベントでリークが発生しないようにします。
  • godot-combat-system — ウェーブの敵ユニットが倒れた際にアクティブな敵のカウンターを減らす、ヒットボックス、死亡、ダメージを扱います。
  • godot-navigation-pathfinding — 数百体のウェーブエージェントの経路探索に使う、NavigationServer のクエリ、回避マスク、マップを扱います。
  • godot-scene-management — ウェーブで PackedScenes が頻繁に入れ替わる際の、プール、スレッド化された読み込み、安全な追加/削除を扱います。
  • godot-performance-optimization — 群れの密度予算に向けた MultiMesh、オクルージョン、サーバー側ボディを扱います。
  • godot-monte-carlo-balancer — エンドレスモードのリリース前に、スタイルマトリックスを使ってスポーン数、出現率、難易度カーブをサンプリングします。
下流/利用側
  • godot-genre-tower-defense — WaveResource のシーケンスとクリア勝利条件で駆動する、レーン/ポータルウェーブを扱います。
  • godot-genre-shooter — ウェーブ制シューターのアリーナ/大群のスポーンペースと敵の多様性を扱います。
  • godot-genre-survival — 同じマネージャーループを基盤とする、エンドレスの倍率ウェーブと圧力の上昇を扱います。
マスター
  • godot-master — スキル横断での検索に使う、ライブラリのルーターとミラー化されたモジュールエントリです。

コメント