UE Blueprintで作る○○なゲーム

UE Blueprintで作る拡張性の高い汎用インベントリシステム

Tags: Blueprint, インベントリ, UMG, データ構造, ゲームシステム

はじめに:Blueprintで汎用インベントリシステムを構築する意義

ゲーム開発において、インベントリシステムはプレイヤーの体験を豊かにする重要な要素です。アイテムの収集、管理、使用といった一連の流れは、RPG、サバイバル、アドベンチャーなど多くのジャンルで必要とされます。C++で複雑なシステムを構築することも可能ですが、Blueprintを活用することで、プロトタイピングから実装、イテレーションまでの開発サイクルを大幅に短縮できます。

本記事では、プログラミング経験をお持ちの読者の方々がBlueprintの強力な機能を最大限に活かし、拡張性と再利用性の高い汎用インベントリシステムを構築する手順をステップバイステップで解説します。構造体、データテーブル、Blueprintインターフェース、イベントディスパッチャといった要素を組み合わせることで、効率的かつ堅牢なシステムを実現します。

1. アイテムのデータ構造を定義する

まず、インベントリで管理するアイテムの基本的なデータ構造を定義します。C++のクラス定義や構造体定義に相当する概念として、Blueprintでは構造体(Structure)データアセット(Data Asset)を組み合わせるのが一般的です。今回は、アイテムの共通プロパティを構造体で定義し、具体的なアイテム情報をデータアセットとして管理する手法を採用します。

1.1. アイテム情報構造体の作成

インベントリ内の各アイテムが持つ共通の属性を定義する構造体を作成します。

  1. コンテンツブラウザで右クリックし、「Blueprint」-> 「構造体」を選択します。
  2. 名前を F_InventoryItemInfo とします。
  3. F_InventoryItemInfo を開き、以下の変数を作成します。
    • ItemID (Name型): 各アイテムを一意に識別するためのIDです。プログラミングにおけるenumstringキーのような役割を果たします。
    • DisplayName (Text型): UI表示用のアイテム名です。
    • Description (Text型): アイテムの詳細説明です。
    • Icon (Texture2D Object Reference型): インベントリUIで表示されるアイコン画像です。
    • bIsStackable (Boolean型): アイテムがスタック可能かどうかを示します。
    • MaxStackSize (Integer型): 最大スタック数です。bIsStackableがTrueの場合にのみ有効です。
    • ItemType (Enum型): アイテムの種類(例: 武器、防具、消耗品など)を分類します。事前にE_ItemTypeという名前でEnumを作成しておくと良いでしょう。

この構造体は、インベントリ内のスロットが保持する「アイテムそのもの」ではなく、「アイテムの定義」を表します。

1.2. アイテム定義用データアセットの作成

次に、個々のアイテム(例: ポーション、剣、コイン)の具体的なプロパティを定義するために、データアセットを使用します。これにより、アイテムの追加や変更をBlueprintのコードに触れることなく行えるようになります。

  1. コンテンツブラウザで右クリックし、「Blueprintクラス」を選択します。
  2. 親クラスとして DataAsset を検索して選択し、「選択」をクリックします。
  3. 名前を DA_InventoryItem とします。
  4. DA_InventoryItem を開き、以下の変数を作成します。
    • ItemInfo (F_InventoryItemInfo型): 先ほど作成した構造体をプロパティとして持ちます。これにより、このデータアセットがF_InventoryItemInfoで定義された全ての情報を持つことになります。

これで、コンテンツブラウザで DA_InventoryItem を右クリックし、「Blueprintクラスの作成」を選択することで、具体的なアイテムアセット(例: DA_PotionDA_Sword)を作成し、それぞれのItemInfo変数を設定できるようになります。これは、プログラミングにおける設定ファイルやインスタンス作成に似ています。

2. インベントリ管理コンポーネントの作成

プレイヤーやコンテナがインベントリを持つための中心的なロジックを管理するBlueprintコンポーネントを作成します。これにより、インベントリの機能が特定のBlueprintに依存せず、再利用可能な形で提供されます。

2.1. インベントリコンポーネントのBlueprint作成

  1. コンテンツブラウザで右クリックし、「Blueprintクラス」を選択します。
  2. 親クラスとして ActorComponent を検索して選択し、「選択」をクリックします。
  3. 名前を BPC_InventoryManager とします。

2.2. アイテム格納ロジックの実装

BPC_InventoryManager を開き、以下の変数と関数を作成します。

これらの関数は、プログラミングにおけるデータ構造(配列やリスト)へのアクセス、条件分岐、ループ処理といった基本的な操作をBlueprintノード(ForEach LoopBranchAddRemoveなど)で表現する良い例となります。

3. UI(UMG)との連携

インベントリシステムには、その内容をプレイヤーに視覚的に表示するためのUIが不可欠です。UMG (Unreal Motion Graphics) を用いて、インベントリUIを作成し、BPC_InventoryManagerと連携させます。

3.1. インベントリスロット用ウィジェットの作成

個々のアイテムスロットを表示するためのウィジェットを作成します。

  1. コンテンツブラウザで右クリックし、「ユーザーインターフェース」->「ウィジェットブループリント」を選択します。
  2. 親クラスとして「UserWidget」を選択し、名前を WBP_InventorySlot とします。
  3. WBP_InventorySlot を開き、以下の要素を追加します。
    • Image (アイコン表示用)
    • TextBlock (数量表示用)
    • Button (クリックイベント用)
  4. イベントディスパッチャへのバインド: WBP_InventorySlot には、表示するアイテムのF_InventoryItemInfoを受け取る「SetItemInfo」のような関数と、ボタンが押されたときに親ウィジェットに通知するためのOnSlotClickedといったイベントディスパッチャを作成します。

3.2. メインインベントリUIウィジェットの作成

複数のスロットを管理し、インベントリ全体を表示するウィジェットを作成します。

  1. 上記と同様に WBP_InventoryMain を作成します。
  2. WBP_InventoryMain を開き、WrapBoxUniformGridPanel などを用いて、複数の WBP_InventorySlot を配置できるレイアウトを作成します。
  3. WBP_InventoryMain のGraphタブで、BPC_InventoryManagerOnInventoryUpdatedイベントディスパッチャにバインドします。
    • Event BeginPlay (または、BPC_InventoryManagerが有効になったタイミング) で、プレイヤーキャラクターのBPC_InventoryManagerコンポーネントへの参照を取得します。
    • その参照から「Assign OnInventoryUpdated」ノードを呼び出し、カスタムイベントをバインドします。
    • このカスタムイベント内では、既存のWBP_InventorySlotを全てクリアし、BPC_InventoryManagerInventorySlots配列の内容に基づいて新しいWBP_InventorySlotを作成・追加・更新します。

この仕組みは、Web開発におけるデータバインディングやObserverパターンに似ています。データが更新されたときに、それに応じたUIの更新が自動的に行われるようになります。

4. ワールドでのアイテム拾得と使用

プレイヤーがワールド上のアイテムを拾い、インベントリに追加するロジック、およびインベントリからアイテムを使用して効果を発動するロジックを実装します。

4.1. 拾えるアイテムのBlueprint作成

ワールドに配置される「拾えるアイテム」は、専用のBlueprintで表現します。

  1. コンテンツブラウザで右クリックし、「Blueprintクラス」->「Actor」を選択し、名前を BP_PickupItem とします。
  2. BP_PickupItemStaticMeshComponent (アイテムの外観) と SphereCollisionComponent (プレイヤーとのインタラクション範囲) を追加します。
  3. DA_InventoryItem 型の変数 ItemData を追加し、インスタンス編集可能にします。これにより、ワールドに配置する際にどのアイテムかを指定できます。
  4. SphereCollisionComponentOnComponentBeginOverlap イベントで、オーバーラップしたActorがプレイヤーの場合、プレイヤーのBPC_InventoryManagerAddItemToInventory関数を呼び出します。
  5. アイテムが正常に追加されたら、DestroyActorノードでワールドからアイテムを削除します。

4.2. アイテム使用インターフェースの作成

アイテム使用時に様々な効果(回復、武器装備など)をBlueprintに依存せずに実行できるように、Blueprintインターフェースを活用します。これはプログラミングにおける「インターフェース」の概念と非常に似ており、多態性を実現します。

  1. コンテンツブラウザで右クリックし、「Blueprint」->「Blueprintインターフェース」を選択し、名前を BPI_UseItem とします。
  2. BPI_UseItem を開き、UseItem という関数を追加します。

    • 入力: UserActor (Actor Object Reference型), ItemInfo (F_InventoryItemInfo型)
  3. 各アイテム(例: ポーション、剣)の具体的な使用効果を持つBlueprintクラス(例: BP_PotionEffectBP_SwordEffect)を作成し、これらのBlueprintが BPI_UseItem インターフェースを実装するようにします。(クラス設定で「インターフェース」の項目に追加)

  4. BP_PotionEffectUseItem イベントでは、UserActorの体力回復ロジックなどを実装します。BP_SwordEffectでは、UserActorの装備スロットに剣を設定するロジックなどを実装します。

4.3. インベントリUIからのアイテム使用

WBP_InventorySlot のボタンクリックイベントで、以下の処理を行います。

  1. クリックされたスロットのItemInfoを取得します。
  2. ItemInfoが持つItemTypeに基づいて、適切なアイテムエフェクトのBlueprintクラスをスポーンするか、既に存在するエフェクトBlueprintへの参照を取得します。
  3. そのエフェクトBlueprintがBPI_UseItemインターフェースを実装しているかを確認します(Does Implement Interfaceノード)。
  4. 実装している場合、UseItemメッセージを送信します。
  5. アイテムが使用されたら、BPC_InventoryManagerRemoveItemFromInventoryを呼び出し、インベントリからアイテムを減らします。

5. 効率的なBlueprint構築のヒント

まとめ:Blueprintで実現する堅牢なシステム

本記事では、Blueprintのみを使用して拡張性の高い汎用インベントリシステムを構築する基本的なアプローチを解説しました。アイテムデータの定義からインベントリコンポーネント、UI連携、そしてワールド上のインタラクションまで、主要な要素をカバーしています。

プログラミング経験をお持ちの方であれば、Blueprintの「ノードとピン」という表現形式に慣れることで、C++で記述する際に設計するクラス階層やデータ構造、イベントシステムといった概念をBlueprintで直感的に実装できることがご理解いただけたのではないでしょうか。

このシステムを基盤として、セーブ/ロード機能、アイテムのソート、ドラッグ&ドロップ、装備システムなど、さらに多くの機能を拡張していくことが可能です。Blueprintの持つ柔軟性と可視性を活かして、あなた自身のゲーム開発に役立ててください。