【第17回】インタラクトするギミック②
概要
前回はプレイヤーがインタラクトできるレバーハンドルの処理を作成しました。
今回はそのインタラクトをトリガーにして、レベル上にアクタを生成する処理を作成します。
生成したアクタは移動させながらアイテム付近まで移動させて、画面外まで移動した足場は消してしまうことにします。また、レバーハンドルの処理を何度も実行できるようにも調整しましょう。
移動する足場に乗って移動しすぎないよう、レベルの配置を少し調整しました。
トリガーによってアクタを生成する
特定の場所にアクタを生成して、指定した位置まで動かします。
メッシュを作成しておきます。
その上に乗って移動できるようにしたいので、ひとまずメッシュにコリジョンを付与します。
生成する対象となるブループリントを作成します。
ブループリントは「Actor」クラスです。
ブループリントを開いて、Static Meshコンポーネントを設定してください。
つづいて、落下ポイントのブループリントを作成します。
このブループリントが指定した場所に、上記で作成したブループリントアクタを生成させます。
「Actor」クラスブループリントで作成してください。
ブループリントを開きます。
コンポーネントパネルで「コンポーネントを追加」します。
「Arrow」コンポーネントを追加してください。
これはプレイ時に表示されない「見えない目印」として機能します。位置を指定するのに使ったり、ルートからの相対距離を参照するなど、使い勝手の良いコンポーネントです。
続けて、イベントグラフを開きます。
カスタムイベントを作成しましょう。
右クリックして、Spawn Actor と検索します。
「クラスからアクタをスポーンします」というノードを配置しましょう。
これは特定のアクタを生み出す(スポーンする)処理です。
このノードを使用するときは必ず生成するブループリント(Class)と、生成する位置角度スケール(Transform)を指定しなければなりません。
Classのドロップダウンから、先ほど作成したブループリントを指定しましょう。
Tranform(位置、角度、スケール)は、ArrowコンポーネントのTransformを参照して使います。
Arrowコンポーネントの参照をゲットしてください。
そこからワイヤーを伸ばし「Get World Transform」を配置して接続しましょう。
これで生成イベントができましたね。
生成タイミングは、レバーを下ろしきったタイミングにしたいと思います。
「Finished」時に発行するイベントディスパッチャーがあるのでそちらを使いましょう。
イベントディスパッチャーをバインドするための参照を得る方法はなんでも構いません。
レベル上にひとつしかないので、ここでは「Get All Actors of Class」で検索して受け取ったものを変数に代入します。複数ある場合は、区別する変数を作成して判断しましょう。
「For Each Loop」のCompleted以降で、バインドを呼び出します。
Spwanするイベントに接続しましょう。
念のためSpawn時にコリジョンが衝突していても生成されるよう、引数「Collision Hnading Override」を「Always Spawn」に変更しておきました。
確認用のレベルに配置してテストしてみます。
無事生成されるようになりました。
生成したアクタを動かす
次に、生成されたアクタを動かす処理を入れてみたいと思います。
動かし方はどのような方法でも構いません。
Tickで単純に動かす方法や「Interp Movement」を使っても良いですし、タイムラインや、Splineを活用しても良いかもしれません。
いくつかの方法を検討してみましょう。
物理落下を試してみる
ひとまず、(プレイヤーから見えない位置で生成しますので)生成後はプレイヤーが移動可能な位置まで移動させたいですね。
ためしに物理機能を使って、生成したアクタを自由落下させてみましょう。
落下するアクタのブループリントを開きます。
準備としてコンポーネントパネルのRoot(親)をメッシュにしておきます。
メッシュを選択した状態で詳細パネルの「物理」項目にある「Simulate Physics」のチェックをONにします。これで、このブループリントの物理機能が有効になりました。
プレイして落下することを確認してください。
あとは、生成したアクタだけを受け止める(=プレイヤーを無視する)地面を設置すれば足場として機能しそうですね。
コリジョンだけのブループリントを作成して地面とするのもいいでしょう。
プレイヤーを受け止めないコリジョン設定は、上図のようにコリジョンの「コリジョンプリセット」を「Custom」に変更して、「Collision Enabled」を「Collision Enabled(Query and Physics)」に。コリジョンレスポンスのチェック項目を「Spawnしたアクタのみをブロック」するように変更するだけです。
ちなみに物理機能がONになるとコリジョンは自動的に「PhysicsBody」に変更されます。
うまく停止しましたね(プレイヤーはコリジョンを素通りすることも確認できました)。
このように、コリジョン反応の分類をルールにあわせて適宜カテゴライズする方法は今後も使う機会が多いので覚えておきましょう。
もっと簡単な方法としては、適当なメッシュを置き、コリジョンの設定を変更して「Visibility」をOFFにするだけでも同じように機能させることが可能です。余裕があれば、どちらもためしてみてください。
つづいて、落下完了したら物理を停止させておきましょう。
アクタがバウンドしなくなり、物理による予想外の動きが起きなくなります。
その後、移動させる処理を実行するためにも必要です。
落下(の衝突)を検知するイベントを作成します。
今まではOverlapを検知してイベントにしていましたが、ここではHitイベントを使ってみます。
コンポーネントから「StaticMesh」を選択してください。
詳細パネルのコリジョン項目にある「Simulation Generates Hit Events」をONにします。
これでヒットイベントを検知できるようになりました。
イベントから「On Component Hit」を選択してヒット時に通知されるイベントを生成します。
ヒットイベントの「Other Actor」ピンからワイヤーを伸ばします。
ヒットしたものが指定のものであれば、処理を継続するようCastで判断しましょう。
上記でブロック用のブループリントを作成しましたので、それを選択しました。
念のため、ヒット後の処理が何度も呼ばれないように「Do Once」をはさみます。
これは以降の処理を一度だけ使用できるようにするノードですね。
そして、ヒットが実行されたら物理機能を切ります。Static Meshコンポーネントの参照をゲットして、そこからワイヤーを伸ばして「Set Simulate Physics」ノードを検索して配置します。
さて、ひとまずこれで任意の位置まで生成したアクタを移動させることができましたね。
メインでプレイするレベルに置いて、確認していきましょう。
ここから画面外に移動させます。
今まで学習したどの移動方法でも実現できそうですが、今回は開始時点やアイテムの足場付近では移動速度を落とすようなユーザビリティにも気を配ってみましょう。
どんな移動方法がベターでしょうか?
できなくもなさそうですが、「Interp Movement」コンポーネントや「Tick」イベントのみを使って移動させる方法では、調整が少々面倒そうです。
簡単なのはタイムラインによる移動、次にスプライン移動でしょうか。
作成してみます。
タイムラインによる移動
タイムラインを作成します。
タイムラインエディタを開きます。
X方向に動かしながらZ方向に動かしますので、今回は「Vector」値のグラフを作成しましょう。
「V+」を選択します。
グラフ左上にある目や鍵アイコンを使ってX値とZ値を設定していきます。
値は後々調整することになりそうですが、ひとまずプレイに支障がでない程度に。
グラフは面倒にも思えますが、慣れれば短時間で設定できるようになります。
X軸
00秒:0
05秒:0.175
11秒:0.45
40秒:1.0Z軸
00秒:0
08秒:0.45
11秒:0.5
20秒:0.6
40秒:1.0
それぞれのLerpに使用するAlpha値を設定しました。
タイムラインはカスタムイベントで呼び出します。
Update部分の処理を書いていきましょう。
Physicsを切ったあとにその地点の座標を取得(Default Location変数に代入)し、タイムライン実行時に差分を加算した値に書き換えています。タイムラインを稼働させるまでに若干のディレイを設けます。
そして、Finish部分で「Destroy Actor」ノードを使い、アクタを削除します。
「Get Actor Forward Vector」と「Get Actor Up Vector」は足場アクタの前方と上方のVectorを取得するノードです。アクタの向きにそって動かすために使用します。
もしワールド軸で移動させる場合には不要です。
確認してみましょう。うまく動いているでしょうか?
Spline Actor を使った移動方法も章の最後に記載しています。
興味があればチャレンジしてみましょう。
レバーハンドルを戻して再度使えるようにする。
足場の出現が一度だけでは難易度が高すぎます。
生成後、一定時間経過したら再度レバーハンドルを操作できるようにしましょう。
レバーハンドルのブループリントを開きましょう。
タイムラインの「Reverse(巻き戻し)」機能を使います。
Fnished時、順再生のときだけイベントディスパッチャーが呼ばれるようにします。
早く戻りすぎるとアクタが重なってしまうので、ディレイをかけて「Reverse」を実行します。
「Set Play Rate」で、戻りレバー速度を調整してメリハリもつけました。
順再生でないときは、実行フラグの変数(Is Interacted)を「False」に戻します。
テストプレイで確認してみましょう。
今回は、これで以上です!
現時点ではアニメーションとの連動もなく、負荷なども想定せず単純にイベントを呼び出しただけですが、改良すればよりスマートで汎用的なイベントに改良できますので、これで完成とせず、さまざまな方法をためしてみてください。
お疲れさまでした!
プロジェクトのダウンロード