基本方針
今回の仕掛けには3つのオブジェクトが関わっています。「アイテム」「ドア」そして「プレイヤーキャラクター」です。
アイテムとドアはName型によるIDを持っていることにします。プレイヤーはアイテムを入手してドアの場所まで持っていくと、アイテムとドアのIDを比較し、一致すればドアが開きます。

やることまとめると
- (キャラクターはすでにいるので)アイテムとドアのブループリントを作る
- アイテムとドアにそれぞれName型のID情報を持たせる
- ドアが開く機能を作る
- キャラクターがアイテムを入手する仕組み、アイテムとドアのIDを比較する機能を作る
と、このようにそれぞれの機能を作り、連携させる必要があります。まずはアイテムの作成から始めていきましょう。
アイテムの作成
サードパーソンのコンテンツドロワーの好きな場所にアイテムとしてActorの子ブループリントクラスを作成します。名前は「BP_KeyItem」としました。

このアイテムはオーブ的な見た目にしたいので、まずはSphereのコンポーネントを追加します。

また、持つのに手頃な大きさとしてScaleを0.1(直径10cmに相当)にします。この球は単に見た目を表現するだけものなのでCollision PresetsはNoCollision(判定なし)にしておきましょう。

ただの白い球体では寂しいので、マテリアルも追加します。光り輝くオーブを表現するためにEmissive Colorを大きく設定して自己発光させましょう。


次にIDとして使用するName型の変数を追加しましょう。「デフォルト値」を「key01」にしておきます。名前は「ItemID」としました。

プレイヤーがアイテムを回収するためにはプレイヤーがアイテムに重なったのかどうかを判定するコリジョンが必要です。SphereCollisionコンポーネントを追加します。判定は見た目よりやや大きめに作っておきます。

これでアイテムの作成は完了しました。テスト用にドラッグ&ドロップでマップ上に仮配置しておきましょう。

キャラクターのアイテム入手
ドアを作っていく前にプレイヤーがアイテムを拾えるようにしておきましょう。分かりやすいように手に入ったらそのアイテムを右手に持っているという状態にします。

アイテムを持つ場所を示すソケットとしてプレイヤーのブループリントにキャラクターメッシュの子としてSphereコンポーネントを追加します。アイテムのSphereと同じ数値でスケール調整します。

このソケットを右手の位置に追従させるためにParentSoketを「hand_r」に指定します。その後にLocationを手に持っている感じになるように調整しましょう。

このソケットはゲーム中は表示させず隠しておきたいので、DetailパネルからHidden in Gameにチェックを入れておきます。これでソケット完成です。

アイテムはキャラクターが重なると自動的に入手できるようにします。ComponentsタブからCapsuleComponent(CollisionCylinder)をクリックし、Detailパネルの下の方にあるOnComponentBeginOverlapの横の「+」ボタンを押します。

ノードが出てくるので、以下のようにしてキャラクターと重なった時にアイテム自体を右手のソケットにアタッチするという処理を書いていきます。

Location Rule、Rotation Rule、Scale Ruleを間違えると奇妙なところにアタッチされてしまったりするので注意しましょう。
ここで一度テストプレイをしてみると、すでにアイテムを持っている状態を作れていることがわかります。
ドアの作成
無事アイテム入手の仕組みができたので、続いてドアを作ります。
ドアのメッシュにはStarter Contentに含まれている「SM_Door」と「SM_DoorFrame」を使用します。どちらもStarterContent\Propsに入っています。

しかし、「SM_Door」には最初はコリジョン(衝突判定)が設定されていないので、このままだとプレイヤーキャラクターがすり抜けてしまい、扉の意味がありません。まずはこれを解決しましょう。
「SM_Door」を開き、DetailsパネルのCollision→Collision Presetsを「Use Complex As Simple」に変更します。これで簡単に見た目通りのコリジョンを設定することができます。

下準備が終わったら、ドアのブループリントを作成します。名前は「BP_Door]とします。

ドアにはStaticMeshコンポーネントとして「SM_DoorFrame」と「SM_Door」を追加し、Locationパラメーターで位置を調整します。ドアの構造としてフレームに扉の部分がくっついて動いているので、「SM_Door」は「SM_DoorFrame」にアタッチする形で追加するといいでしょう。

アイテムと同じく、識別用IDを作ります。デフォルト値はアイテムに合わせて「key01」にしておきます。

続いてドアが開く機能を作ります。Doorコンポーネントの回転の中心はちょうど本物のドアにおける蝶番の部分になっているので、90度回転させるだけでドアが開いたような見た目になります。
まずはイベントグラフ上の何もない場所を右クリックし、出てきたリストの中から「Add Custom Event」を選択します。これで自由に名前を付けられる赤いノードが出現しますので、これを「OpenDoor」と名付けましょう。


このノードにつなげて、Set Relative Rotation(Door)という名前のノードを繋げます。

最後にNew RotationのZを90.0に変更すれば完成です。これで「OpenDoor」が呼び出された時にドアが90度回転するようになりました。

一瞬で開いてしまうのではなく、もう少しドアの動きにこだわってみたいという人はTimelineを使ったやり方がおすすめです。詳しくはこちらの記事を参考にしてみるといいかもしれません。
完成したらこれもマップ上にドラッグ&ドロップしておきましょう。

アイテムとドアの識別
最後にプレイヤーが持っているアイテムとドアの識別IDが同じかどうか比較する部分を作っていきましょう。
まずは持っているアイテムのIDなどの情報をプレイヤーキャラクターが知っている必要があります。アイテムを一旦手に入れたら、変数としてそれを保存して持っておきましょう。
Cast To BP_KeyItemのノードから青いピンを伸ばし、Promote to variableを選択することで、アイテムの変数ノードを作成できます。

変数にアイテムを保存するために、以下のようにノードをつなぎ直しておきましょう。

処理はCapsuleComponentのOnComponentHitから始めます。ここにはキャラクターが何かにぶつかった際の処理を書くことができます。作り方は上のOnComponentOverlapと一緒です。


気を付けなければいけないこととして、プレイヤーはアイテムを持っていない可能性があります。持っていないアイテムのIDを調べようとするとエラーが出ますので、まずはアイテムを持っているのか、持っていないのかをIDを比較する前に判断する必要があります。
つまり、ゲーム中何かにぶつかったときには「ぶつかったのはドアか?」「アイテムを持っているか?」「アイテムとドアは同じIDか?」を順番に調べていき、全てYesならBP_DoorのOpenDoorを呼び出します。

さてOnComponentHitに続いて、次のようにノードを組んでいきます。

さきほど挙げたフローチャートの条件文をどのノードで表現しているかを見てみると以下のようになります。

OpenDoor後にドアに使ったアイテムは一度きりで失われることにしましょう。拾ったアイテムの変数を空にすることを忘れないでください。

これで今回の仕掛けは完成です!テストプレイして問題ないかどうか、確認してみましょう。
今回のシステムではItemIDやDoorIDをInstance Editableに設定することで、ビューポート上からそれぞれのIDを変更できます。

アイテムによって開けられるドアと開けられないドアを作ることでパズルや迷路のようなゲームマップも作れます。ここまでの基本的な内容が完成したらぜひ挑戦してみて下さい。それでは。
