UE Blueprintで作る汎用的なオブジェクトインタラクションシステム
はじめに
Unreal Engine (UE) を用いたゲーム開発において、プレイヤーがゲーム世界のオブジェクトとどのように関わるかは、ゲームプレイの面白さを左右する重要な要素です。ドアを開ける、アイテムを拾う、スイッチを押すといった様々なインタラクションを、汎用性を持たせて効率的に実装することは、開発の生産性を高める上で非常に重要になります。
この記事では、Blueprintのみを使用して、プレイヤーキャラクターがゲーム内の様々なオブジェクトとインタラクションするための、拡張性の高い汎用システムを構築する方法をステップバイステップで解説します。特に、プログラミング経験のある読者の方々には馴染み深い「インターフェース」の概念をBlueprintでどのように活用するかを中心に据え、効率的かつ整理されたBlueprintの組み方を習得していただくことを目指します。
1. インタラクションシステムの基本設計とインターフェースの導入
汎用的なインタラクションシステムを構築する上で最も重要なのが、「どのようなオブジェクトでもインタラクション可能にするための共通の接点」を用意することです。これはプログラミングにおける「インターフェース」の概念に他なりません。Blueprintでは「Blueprint Interface」としてこの機能が提供されています。
1-1. Blueprint Interfaceの作成
まず、インタラクション可能なオブジェクトが共通して持つべき機能を定義するインターフェースを作成します。
- コンテンツブラウザ内で右クリックし、
Blueprint
->Blueprint Interface
を選択します。 - 名前を
BPI_Interactable
とします。 BPI_Interactable
をダブルクリックして開きます。- 「関数」セクションで、デフォルトで作成されている
NewFunction_0
の名前をInteract
に変更します。 Interact
関数を選択し、詳細パネルで必要に応じて引数を追加できます。例えば、Interactor
(インタラクションを行ったActor、通常はプレイヤーキャラクター)としてObject
型の引数を追加しておくと、後々の処理で便利です。- 引数名:
Interactor
- 型:
Object Reference
- 引数名:
1-2. インターフェースの役割とメリット
BPI_Interactable
を作成することで、私たちは以下のメリットを享受できます。
- 汎用性: どのActorもこのインターフェースを実装するだけでインタラクト可能になります。
- 疎結合: プレイヤーキャラクターは特定のActor型を知る必要がなく、
BPI_Interactable
を実装しているかどうかだけをチェックすれば良いため、依存関係を減らせます。 - 拡張性: 将来的に新たなインタラクションが必要になった場合でも、インターフェースを拡張するだけで対応が容易になります。
2. インタラクト可能オブジェクトの実装
次に、作成した BPI_Interactable
インターフェースを実際にActorに実装し、具体的なインタラクションロジックを記述します。ここでは例として「開閉するドア」を作成します。
2-1. ドア用Actorの作成
- コンテンツブラウザ内で右クリックし、
Blueprint Class
を選択します。 Actor
を親クラスとして選択し、名前をBP_Door
とします。BP_Door
をダブルクリックして開きます。- Componentsパネルで
Static Mesh
コンポーネントを追加し、ドアのメッシュを設定します。
2-2. BPI_Interactable
の実装と Interact
イベントの処理
BP_Door
のClass Settings
を開きます。- 「Interfaces」セクションの「Implemented Interfaces」で
Add
ボタンをクリックし、BPI_Interactable
を選択します。 - これにより、
BPI_Interactable
で定義したInteract
関数がBP_Door
のEvent Graph内でイベントとして利用可能になります。 - Event Graphに戻り、右クリックして
Event Interact
と検索し、イベントノードを追加します。 -
この
Event Interact
ノードからドアの開閉ロジックを実装します。ここでは簡略化のため、ドアの回転アニメーションを例とします。blueprint Event Interact (Interactor) ├── Branch (Is Door Open?) │ ├── True (ドアが開いている場合) │ │ └── Timeline (ドアを閉じるアニメーション) │ │ └── Update -> Set Relative Rotation (Static Mesh Component) │ └── False (ドアが閉じている場合) │ └── Timeline (ドアを開くアニメーション) │ └── Update -> Set Relative Rotation (Static Mesh Component)
* Timelineの作成: Event Graph内で右クリックし、Add Timeline
を選択します。タイムラインエディタを開き、Vector Track
を追加してドアの回転値(YawまたはZ軸の回転)を時間経過で変化させます。例えば、0秒で0度、1秒で90度になるようにカーブを設定します。 * Set Relative Rotation: TimelineのUpdate
ピンからSet Relative Rotation
ノードを接続し、対象をドアのStatic Mesh Component
に設定します。回転値はTimelineのVector Trackから取得します。 * 状態管理:bIsOpen
といったBoolean変数を作成し、ドアの開閉状態を管理します。Event Interact
が呼ばれるたびにこの変数をトグルし、Timelineの再生方向 (Play
またはReverse
) を切り替えます。
3. プレイヤーキャラクターからのインタラクション実行
プレイヤーキャラクターがゲーム世界でインタラクト可能オブジェクトを検出し、そのオブジェクトに対して Interact
関数を呼び出すロジックを実装します。
3-1. プレイヤー入力とLine Trace
ここでは、キーボードの E
キーを押した際にプレイヤーの視線の先にインタラクト可能なオブジェクトがあるかを検出するロジックを BP_ThirdPersonCharacter
(またはご自身のプレイヤーキャラクターBlueprint)に実装します。
BP_ThirdPersonCharacter
のEvent Graphを開きます。Input Action E
イベントを追加します。Pressed
ピンからLine Trace By Channel
ノードを接続します。- Start:
Get Actor Location
(Self) にGet Forward Vector
(Camera/FollowCamera) を乗算したものを加算し、カメラの少し前からスタートさせます。 - End:
Start
地点からGet Forward Vector
(Camera/FollowCamera) をさらに乗算(距離分)したものを加算し、ある程度離れた位置を終点とします。(例: Start + ForwardVector * 500) - Trace Channel:
Visibility
など、適切なコリジョンチャンネルを選択します。 - Draw Debug Type:
For Duration
に設定すると、デバッグ用の線が表示され、トレースの動作確認に役立ちます。
- Start:
3-2. 検出したオブジェクトのチェックとインタラクションの実行
Line Trace By Channel
の Out Hit
から、検出したオブジェクトが BPI_Interactable
インターフェースを実装しているかを確認します。
Line Trace By Channel
のOut Hit
ピンからBreak Hit Result
を接続します。Break Hit Result
のHit Actor
ピンからDoes Implement Interface
ノードを接続します。Does Implement Interface
のInterface
にBPI_Interactable
を設定します。Return Value
がTrue
の場合、つまりインタラクト可能なオブジェクトである場合にのみインタラクションを実行します。-
Does Implement Interface
のReturn Value
がTrue
であれば、Hit Actor
ピンからInteract
(Message) ノードを呼び出します。Interact
ノードは、インターフェースを実装しているActorに対して「メッセージ」を送信する形で関数を呼び出します。これがBlueprint Interfaceの仕組みです。Interactor
引数にはSelf
(プレイヤーキャラクター自身)を渡します。
blueprint Input Action E (Pressed) ├── Line Trace By Channel (Start, End, Trace Channel=Visibility, Draw Debug Type=For Duration) │ ├── On Hit (True) │ │ └── Break Hit Result │ │ ├── Hit Actor │ │ │ └── Does Implement Interface (Interface=BPI_Interactable) │ │ │ └── Branch (True) │ │ │ └── Interact (Message) (Target=Hit Actor, Interactor=Self)
これで、プレイヤーが E
キーを押すと、視線上のインタラクト可能なオブジェクト(この場合はドア)が開閉する基本的なシステムが完成しました。
4. 応用と発展
この汎用インタラクションシステムは、様々な方法で拡張可能です。
4-1. インタラクション可能な範囲の表示(HUD/Widget)
プレイヤーがインタラクト可能なオブジェクトに近づいた際、画面に「Eで開ける」といったヒントを表示するUIは、ゲームのユーザビリティを高めます。
- プレイヤーキャラクターにSphere Collisionなどのトリガーを追加し、
On Component Begin Overlap
/On Component End Overlap
イベントで、インタラクト可能なオブジェクトの検出とUIの表示/非表示を制御します。 - 検出したActorが
BPI_Interactable
を実装しているかをチェックし、実装している場合はWidget
を作成して表示します。
4-2. 複数のインタラクションタイプ
単一の Interact
関数だけでなく、「Look (調べる)」「Use (使う)」「Pick Up (拾う)」など、複数のインタラクションタイプを持たせたい場合は、BPI_Interactable
インターフェースに関数を追加するか、別のインターフェースを作成します。
例: BPI_Usable
, BPI_Pickuppable
といったインターフェースを分けて、オブジェクトの特性に応じて実装します。あるいは、Interact
関数に InteractionType
(Enum型) の引数を追加し、イベント内でその型に応じて処理を分岐させることも可能です。
4-3. 構造体を使ったインタラクション情報の受け渡し
より複雑なインタラクション情報を渡したい場合(例: 拾うアイテムのID、ダメージ量など)、Struct
を作成して Interact
関数の引数として渡すことが非常に有効です。これにより、単一の引数で複数の関連情報を一括で渡すことができ、Blueprintグラフを簡潔に保てます。
結論
この記事では、Unreal EngineのBlueprint Interfaceを活用することで、汎用的かつ拡張性の高いオブジェクトインタラクションシステムを構築する方法を解説しました。プログラミング経験のある読者の方々にとって、Blueprint Interfaceはオブジェクト指向プログラミングにおけるインターフェースの概念と非常に似ており、疎結合なシステム設計を実現するための強力なツールであることをご理解いただけたかと思います。
このシステムを基盤として、HUDによるインタラクションヒントの表示、複数のインタラクションタイプの追加、構造体を用いた詳細な情報の受け渡しなど、様々な機能を追加することで、よりリッチでインタラクティブなゲーム体験を創出することが可能です。ぜひ、ご自身のプロジェクトでこの知識を応用し、効率的なゲーム開発を進めてください。