【Godot】インベントリシステム設計の基礎:Resourceとシグナルで実現するアイテム管理

作成: 2025-12-08

Godot EngineでResourceとシグナルを活用し、堅牢で拡張性の高いインベントリシステムの基礎設計を解説します。

導入:なぜインベントリ設計が重要か

ゲーム開発において、インベントリシステムはプレイヤーの体験を豊かにする上で欠かせない要素です。しかし、インベントリシステムは単にアイテムを格納する箱ではありません。 アイテムのデータ構造インベントリのロジック、そして プレイヤーに情報を伝えるUI という、三つの異なる要素が密接に連携して初めて機能します。

本記事では、Godotの強力な機能である Resourceシグナル を活用し、初心者から中級者向けに、堅牢で拡張性の高いインベントリシステムの基礎設計を解説します。

セクション1: アイテムデータの定義 (Resourceの活用)

インベントリシステムを設計する上で、まず最初に行うべきは「アイテムとは何か」を定義することです。アイテムのデータは、Godotでは Resource として扱うのが最適です。

ItemResource.gd のコード例

# ItemResource.gd
class_name ItemResource
extends Resource

@export var item_id: String = ""
@export var item_name: String = "New Item"
@export_multiline var description: String = ""
@export var icon_path: String = ""
@export var stackable: bool = true
@export var max_stack_size: int = 99

このResourceを継承した .tres ファイルを作成することで、具体的なアイテムの定義をデータとして管理できます。

セクション2: アイテム管理ロジックの実装

次に、アイテムの追加や削除といったインベントリの「動作」を管理するロジックを実装します。このロジックは、 シングルトン(オートロード) として実装することで、ゲーム内のどこからでもアクセスできるようにします。

Inventory.gd のコード例(アイテム追加・削除)

# Inventory.gd
extends Node

signal inventory_changed

var items: Dictionary = {}
const MAX_SLOTS: int = 20

func add_item(item_resource: ItemResource, count: int = 1) -> bool:
    if not item_resource:
        return false

    if item_resource.stackable and items.has(item_resource):
        items[item_resource] += count
        inventory_changed.emit()
        return true

    elif items.size() < MAX_SLOTS:
        items[item_resource] = count
        inventory_changed.emit()
        return true

    return false

func remove_item(item_resource: ItemResource, count: int = 1) -> bool:
    if not items.has(item_resource):
        return false

    items[item_resource] -= count

    if items[item_resource] <= 0:
        items.erase(item_resource)

    inventory_changed.emit()
    return true

func get_inventory_data() -> Dictionary:
    return items

ポイント: inventory_changed.emit() がアイテムの追加・削除のたびに呼び出されています。これがUI連携の鍵となります。

セクション3: UI連携の基礎

インベントリのロジックがアイテムデータを更新しても、UIがそれを知らなければ画面は変わりません。ここでGodotの シグナル が真価を発揮します。

InventoryUI.gd のコード例(インベントリ表示)

# InventoryUI.gd
extends Control

@export var inventory_logic: Inventory

const SLOT_SCENE = preload("res://scenes/inventory_slot.tscn")

func _ready():
    if inventory_logic:
        inventory_logic.inventory_changed.connect(_update_ui)
        _update_ui()

func _update_ui():
    for child in get_children():
        child.queue_free()

    var inventory_data = inventory_logic.get_inventory_data()

    for item_resource in inventory_data:
        var slot = SLOT_SCENE.instantiate()
        slot.set_item_data(item_resource, inventory_data[item_resource])
        add_child(slot)

    var empty_slots_count = inventory_logic.MAX_SLOTS - inventory_data.size()
    for i in range(empty_slots_count):
        var slot = SLOT_SCENE.instantiate()
        slot.set_empty()
        add_child(slot)

この実装により、アイテムが追加・削除されるたびにInventory.gdがシグナルを発し、それを受け取ったInventoryUI.gdが自動的に最新のデータに基づいて画面を更新します。

実践的な使用例:アイテムの獲得

# Player.gd 内の例
func _on_item_collected(item_resource: ItemResource):
    if Inventory.add_item(item_resource, 1):
        item_node.queue_free()

このように、プレイヤーノードはUIの存在を知る必要がなく、UIノードはプレイヤーノードの存在を知る必要がありません。すべてがインベントリロジックという中央のハブを介して、シグナルによって疎結合に連携しています。

まとめ:堅牢なインベントリ設計の要点

本記事で解説したGodot Engineにおけるインベントリシステムの基礎設計は、以下の三つの柱に基づいています。

要素Godotの機能役割
アイテムデータResourceアイテムの静的な情報を定義・保存
インベントリロジックシングルトン(Node)アイテムの追加・削除などの動作を管理
UI連携シグナルロジックの変更をUIに通知

この設計パターンを採用することで、ゲームの規模が拡大しても、アイテムの種類が増えても、UIのデザインが変わっても、システムの核となるロジックを安定して維持することができます。