unity-patterns について
Unity 開発者向けに、設計パターンが必要かを具体的な課題に沿って検討し、実装案とトレードオフを比較するスキルです。パターンを一律に勧めず、根拠のある少数の案に絞ります。
主な機能
- 01パターンの適用妥当性を評価
- 02Unity の主要な設計パターンを網羅
- 03実装コストとリスクを比較
- 04最小の実装範囲とトレードオフを提示
活用シーン
- 01疎結合システムのパターン選定
- 02イベント、ステートマシン、プールの比較
- 03複数の敵 AI を停止する方式の検討
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ besty0728/ unity-skills --skill unity-patternsインストール後、Claude Code で/unity-patternsを入力して読み込まれたか確認します。
詳細
このモジュール内のスキルを呼び出す前に: スキル名や説明から推測したパラメーターを指定してスキルを呼び出そうとしている場合は、いったん停止し、まずこのファイルを読むか、
GET /skills/recommend?includeSchema=trueでスキーマを取得してください。recommend/schema からパラメーター定義をすでに取得している場合は、そのまま dryRun に進めます。
トリガー
- 問題に適したパターンを判断する
- 疎結合システムを構成する
- イベント/ステートマシン/オブジェクトプールのアプローチから選択する
Unity パターンセレクター
パターンの採用が妥当かどうかを判断するために、このスキルを使用してください。すべてのパターンを一度に推奨しないでください。
ガードレール
モード:ドキュメントのみ — 制限対象となる REST スキルはありません。どの動作モード(Approval / Auto / Bypass)でも自由に読み込めます。
- 推奨するパターンは最大1~3個にし、より単純な選択肢では不十分な理由を説明してください。
パターンガイド
-
ScriptableObject- 作成者が設定する構成、共有される静的データ、イベントチャネル、再利用可能なデータアセットに使用します。
- 実行ごとに変化するゲームプレイ状態を保持するデフォルトの場所として使うのは避けてください。
-
C# events / delegates- 所有者と登録解除のタイミングが明確な、一対多の通知に使用します。
- 順序制御、戻り値、複雑なデバッグが必要な命令型フローには使用しないでください。
-
Global event bus / observer hub- 多くのシステムが広範な疎結合通知を本当に必要とする場合に限り、慎重に使用してください。
- 結合の解決策としてデフォルトで選択するのは避けてください。所有権が不明確になり、デバッグが難しくなることがよくあります。
-
Interfaces- 複数の実装が必要な場合や、依存関係の境界を明確にしたい場合に使用します。
- 実際に分離すべき境界がないのに、すべてのクラスにインターフェースを追加するのは避けてください。
-
State machine- 相互に排他的な状態と明示的な遷移を持つアクターに使用します。
- 少数のブール値や小規模なコマンドフローで十分な場合には使用しないでください。
-
Object pool- 弾丸、VFX、敵、UI 項目などを頻繁に生成・破棄する場合に使用します。
- オブジェクトの生成頻度が低い場合や、ライフタイムが単純な場合には使用しないでください。
-
Service layer- 明示的なブートストラップとインターフェースを備えた、少数のシーン横断システムに使用します。
- あらゆるものを、隠れたシングルトンやサービスロケーターにするのは避けてください。
-
Generics / custom attributes- 明確な型安全性やエディターメタデータの価値を保ちながら、繰り返しの定型コードを減らせる場合に使用します。
- ゲームプレイコードが、単純なコードの重複よりも読みにくくなる場合には使用しないでください。
判断ラボ:同じ目標、複数の実装
上記のパターンガイドでは「どのパターンか」に答えます。ほとんどの重要な設計判断では、より有効な演習は、実現可能な実装を2~3個選んで並べ、切り替えコスト、問い合わせコスト、コードの複雑さ、障害モードを比較することです。以下は具体例です。他の判断にも答えとしてそのまま適用するのではなく、同じ形式で検討してください。
具体例:「カットシーン中、100体の敵の AI を一時停止する」
| 実装 | 切り替えコスト(カットシーン開始/終了) | 一時停止中のフレームごとのコスト | コードの複雑さ | 失敗モード |
|---|---|---|---|---|
フィールドフラグ:各 EnemyAI.Update の先頭で if (_paused) return; を実行し、マネージャーがフラグを設定します | O(N) 回の書き込み、アロケーションなし | フレームごとに N 回の分岐テストとディスパッチのオーバーヘッド | 最も低い — bool が 1 つ、ガード節が 1 つ | 開発者が新しい Update を追加してガードを忘れると、気づきにくいバグが発生します |
enabled = false:マネージャーがすべての敵の MonoBehaviour を無効にします | O(N) 回の書き込み、アロケーションなし | ゼロ — Unity はメッセージリスト内の無効な Behaviours をスキップします | 低いものの、状態がコンポーネント間に分散します | OnDisable / OnEnable の副作用(コルーチンの停止、リスナーの登録解除)が予期せず発生する可能性があります |
サブセットリスト:マネージャーが _active / _frozen リストを保持します。敵ごとの Update はなく、マネージャーが _active のみを更新します | 切り替え時に O(N) 回のリスト移動 | _active の数にのみ比例 — 早期カリングに最適です | 最も高い — 所有権の唯一の情報源となり、管理された更新が必要です | 敵に新しい Update を追加すると、フレームごとのコストが再び発生します。また、ほかのコードが敵を直接リスポーンすると、リストとの不整合が起きやすくなります |
使い方
- トレードオフが問題になる最小の規模を選びます。N=5 では 3 つの方法に違いはありませんが、N=5000 ではサブセットリストだけがコストを一定に保ちます。
- 各選択肢で改善する点だけでなく、悪化する点も明記します。メリットしか書かれていない表は、まだ十分に検討できていない証拠です。
- ECS から得られる教訓は、同じ 3 つの形(値の変更、構造の変更、切り替え可能な要素)があらゆる場所に現れるということです。フレームワークが異なっても、それぞれの名称は応用できます。出典:
Dots101/Entities101/Assets/HelloCube/13. StateChange/SetStateSystem.cs:42-80— 1 つのシステムがconfig.Modeに応じて 3 つの実装にディスパッチし、それぞれプロファイラーで測定可能なコストの違いがあります。
この演習を省略する場合
ある選択肢の規模が明らかに限定的な場合(N ≤ 10、状態変更がセッションごとに 1 回、または起動時に 1 回だけ実行されるコードなど)は、「最もシンプルなので X を選びました」という 1 段落で十分です。Decision Lab は、現在のタスクが終わった後も影響が続く選択のためのものです。
出力形式
- 推奨するパターン
- このケースに適している理由
- よりシンプルな代替案を選ばない理由
- 最小限の実装境界
- 既知のトレードオフ