inventory-system について
Godot 4.3+開発者向けのインベントリシステムスキルで、GDScriptとC#の実装指針を示します。アイテムとスロットの設計、スタック、装備拡張、UI連携、セーブデータのシリアライズを扱います。
主な機能
- 01Resourceによるアイテムデータ定義
- 02スロット管理とスタック操作
- 03インベントリと装備のシグナル
- 04グリッドUIとドラッグ&ドロップ連携
- 05アイテムIDによるセーブシリアライズ
活用シーン
- 01スタック上限付きの固定スロットバッグの実装
- 02インベントリ変更に応じたグリッドUI更新
- 03装備スロットの追加とステータス集計
- 04スロット内容の保存とロード時のアイテム復元
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jame581/ godotprompter --skill inventory-systemインストール後、Claude Code で/inventory-systemを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/core-classes.mdequipment.mdserialization.mdui-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) | bool | get_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 シグナルを発行します。
SlotTypeenum、装備/解除 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にする - 装備スロットは文字列ではなく
SlotTypeenum をキーとして使い、コンパイル時にタイプミスを検出する -
Equipment.get_total_stat()は、プロファイリングで必要性が確認されない限りキャッシュせず、ステータスが必要なときに呼び出す - シリアル化では
id + quantityのみを保存し、ItemDataオブジェクト全体やリソースパスは決して保存しない -
ItemRegistryは起動時にアイテムを読み込み、すべてのデシリアル化はこれを介して行う - ドラッグ&ドロップではスロットの内容を直接入れ替え、その後
inventory_changedを 1 回だけ発行する - スタックを防ぐため、
EQUIPMENTとKEY_ITEMタイプではmax_stack_size = 1にする - トレースしやすいよう、すべての
push_error()メッセージにクラス名とメソッド名を含める