mcpField
I
inventory-system

inventory-system

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

inventory-system について

Godot 4.3+開発者向けのインベントリシステムスキルで、GDScriptとC#の実装指針を示します。アイテムとスロットの設計、スタック、装備拡張、UI連携、セーブデータのシリアライズを扱います。

主な機能

  1. 01Resourceによるアイテムデータ定義
  2. 02スロット管理とスタック操作
  3. 03インベントリと装備のシグナル
  4. 04グリッドUIとドラッグ&ドロップ連携
  5. 05アイテムIDによるセーブシリアライズ

活用シーン

  1. 01スタック上限付きの固定スロットバッグの実装
  2. 02インベントリ変更に応じたグリッドUI更新
  3. 03装備スロットの追加とステータス集計
  4. 04スロット内容の保存とロード時のアイテム復元

インストール

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

$npx skills add https://github.com/jame581/godotprompter --skill inventory-system

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

同梱ファイル

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

references/
core-classes.md
equipment.md
serialization.md
ui-binding.md

詳細

Godot 4.3+ のインベントリシステム

すべての例は、非推奨 API を使用せずに Godot 4.3+ を対象としています。このスキルでは設計上の判断を説明し、実装は references/ にあります(先に GDScript、その後に C#)。必要なものを読み込んでください。

関連スキル: カスタム Resource データコンテナについては resource-pattern、インベントリのシリアライズについては save-load、インベントリ変更通知については event-bus、インベントリ UI 表示については hud-system、アドベンチャーゲームのインベントリについては popochiu を参照してください。


1. アーキテクチャの概要

┌─────────────────────────────────────────────────────────┐
│                        UI Layer                         │
│   InventoryUI (Control)                                 │
│     └─ GridContainer                                    │
│           └─ SlotUI × N (Button)                        │
│                 └─ TextureRect (icon) + Label (qty)     │
│                                                         │
│   Connects to: inventory_changed signal                 │
│   Drag-and-drop via _get_drag_data / _drop_data         │
└───────────────────────┬─────────────────────────────────┘
                        │ reads / mutates
┌───────────────────────▼─────────────────────────────────┐
│                    Inventory (Node)                      │
│   slots: Array[InventorySlot]                           │
│   add_item(item, qty) → leftover: int                   │
│   remove_item(item, qty)                                │
│   has_item(item, qty) → bool                            │
│   get_item_count(item) → int                            │
│                                                         │
│   signals: inventory_changed                            │
│             item_added(item, quantity)                  │
│             item_removed(item, quantity)                │
└───────────────────────┬─────────────────────────────────┘
                        │ references
┌───────────────────────▼─────────────────────────────────┐
│                   Data Layer (Resources)                 │
│   ItemData (Resource)                                   │
│     id, name, description, icon, max_stack_size,        │
│     item_type enum                                      │
│                                                         │
│   InventorySlot (inner class / Resource)                │
│     item: ItemData, quantity: int                       │
└─────────────────────────────────────────────────────────┘

2. 重要な設計判断

すべてのインベントリを形作る選択肢は 3 つあります。明示的に選択し、どれを採用したかを記載してください。あとは機械的に決まります。

判断採用するもの理由
アイテムの識別方法:Resource と Dictionary / JSON のどちらか.tres の Resource@export スロットで型付きアイテムを受け付けられ、インスペクターで編集でき、共有インスタンスは参照で比較できます
スロットのコンテナ:Resource と RefCounted のどちらかRefCountedスロットは実行時の状態であり、作成するアセットではありません。Resource を使うと、スロットをディスクに保存して古いアイテムのコピーを再読み込みすることになりかねません
add_item の戻り値:bool と残りの個数のどちらか残りの int一部だけ追加されるケース(スタック上限、バッグ満杯)が一般的です。bool では、実際に何個入ったかを呼び出し側が再確認する必要があります

ゲームに別の仕組みが必要な場合(スロットなしの重量ベースのバッグ、形状のあるアイテムを扱うグリッドインベントリ、無限スタックのリストなど)は、実装前に明確にしてください。このスキルで説明する固定スロット配列は、これら 3 つのどれにも適した土台ではありません。

見落としやすい重要事項
  • 空きスロットより先に既存のスタックを埋めます — その順番で 2 回に分けて処理します。単純に 1 回だけ走査すると、同じ種類のアイテムが複数のスロットに分散し、空きが残っているのにバッグが満杯と報告されます。
  • 両方の処理が完了してから、操作ごとに 1 回だけ inventory_changed を発行します — 変更されたスロットごとには発行しません。スロットごとに発行すると、1 回の add_item で UI 全体が N 回再描画されます。
  • アイテムは参照で比較します。 Godot は読み込んだリソースをキャッシュするため、同じ .tres に対して load() を呼び出すと同じインスタンスが返されます。そのため、slot.item == item は正確かつ低コストです。実行時にアイテムを duplicate() すると、この方法は機能しなくなるため、代わりに ItemData.id を基準にしてください。
  • 数量が 0 になったら item を null にします。そうしないと、is_empty() が正しく判定できず、スロットを再利用できません。
  • 分岐ではなくデータでスタックを禁止します — add_item に個別処理を追加するのではなく、EQUIPMENT と KEY_ITEM アイテムの max_stack_size = 1 を設定してください。
  • C#:ItemData に [GlobalClass] を付けてください。付けないと、.tres ファイルの作成時にインスペクターで型として選択できません。
インベントリ API の契約
メンバー戻り値契約
add_item(item, quantity)int追加できなかった残りの個数。0 はすべて追加できたことを示します
remove_item(item, quantity)—quantity 個まで削除します。所持数がそれより少ない場合も、通知せずに削除します
has_item(item, quantity)boolget_item_count の便利なラッパーです
get_item_count(item)intすべてのスロットの合計数です
inventory_changedシグナル状態を変更する操作ごとに 1 回発行され、すべての UI を更新します
item_added(item, quantity)シグナル実際に追加された個数を渡します
item_removed(item, quantity)シグナル実際に削除された個数を渡します

GDScript および C# の ItemData、Inventory、InventorySlot の完全な実装については、references/core-classes.md を参照してください。


3. 装備機能の拡張

Inventory の隣に Equipment ノードを追加し、SlotType enum をキーとするスロットマップを保持させて、装備スロット(HEAD、CHEST、WEAPON など)を追加します。装備中のアイテムにある stats Dictionary(ItemData に追加するプロパティ)の値を合算してステータスを集計します。スロットが変更されたら equipment_changed シグナルを発行します。

SlotType enum、装備/解除 API、ステータス集計を備えた GDScript および C# の Equipment クラスの完全な実装については、references/equipment.md を参照してください。


4. UI バインディング

スロットグリッド UI:Button スロットウィジェットを並べた GridContainer で、各ウィジェットが 1 つの InventorySlot を表示します。ドラッグ&ドロップには、スロットウィジェットの _get_drag_data / _drop_data / _can_drop_data を使用します。Inventory は inventory_changed を発行し、UI は変更されたスロットを再描画します。

ドラッグ/ドロップ、ホバープレビューに対応した GDScript と C# のスロットウィジェット、インベントリのグリッドレイアウト、ツールチップの連携については、references/ui-binding.md を参照してください。


5. シリアル化

各スロットは {id, qty} のペア(空のスロットは null)として保存し、ItemData 自体やそのパスは決して保存しないでください。ItemRegistry のオートロードが起動時に res://items/ を読み込み、ロード時に ID をアイテムへ解決します。

serialize_inventory / deserialize_inventory を備えた GDScript と C# の ItemRegistry については、references/serialization.md を参照してください。結果はセーブファイルに保存します(version フィールドについては save-load を参照してください)。



実装チェックリスト

  • ItemData は Resource を継承し、Inspector で設定する安定した id 文字列を持つ
  • ItemData ファイルは res://items/ の下に配置し、バージョン管理にコミットする
  • Inventory.add_item() は残りの数量を返し、呼び出し側でインベントリが満杯の場合に対処する
  • inventory_changed シグナルですべての UI 更新を行う — UI はフレームごとにポーリングしない
  • InventorySlot.remove_from_stack() は、数量が 0 になったら item を null にする
  • 装備スロットは文字列ではなく SlotType enum をキーとして使い、コンパイル時にタイプミスを検出する
  • Equipment.get_total_stat() は、プロファイリングで必要性が確認されない限りキャッシュせず、ステータスが必要なときに呼び出す
  • シリアル化では id + quantity のみを保存し、ItemData オブジェクト全体やリソースパスは決して保存しない
  • ItemRegistry は起動時にアイテムを読み込み、すべてのデシリアル化はこれを介して行う
  • ドラッグ&ドロップではスロットの内容を直接入れ替え、その後 inventory_changed を 1 回だけ発行する
  • スタックを防ぐため、EQUIPMENT と KEY_ITEM タイプでは max_stack_size = 1 にする
  • トレースしやすいよう、すべての push_error() メッセージにクラス名とメソッド名を含める

コメント