【第10回】オーバーラップイベント
- 概要
- 行動不能(ゲーム失敗)になるアクタの作成
- コリジョン反応を作成する
- コリジョン反応について
- コリジョンのタイプを確認・変更する
- コリジョンのイベント
- On Component Begin Overlap イベント
- プレイヤーキャラクター側のイベントを作成する
- 衝突時のイベントからプレイヤーキャラクターのイベントを呼び出す
- 何がオーバーラップしたかを判別する
- 【補足】もうひとつの判別方法
- キャラクターを行動不能にする処理
- キャラクターの表示を消す
- 慣性を即座に止める処理を追加する
- 仮演出を入れる
- レベルを読み込みなおす
- レベルに配置する
- 変数フラグを作ってみる(使いたくないときは動作しないようにする)
- ここまでのプロジェクトをダウンロード
- 【補足】バウンドを続けるするアクタ
概要
今回からレベルに使用するギミックを作成していきましょう。あわせてステージの構成(レベルデザイン)も少しずつブラッシュアップして作り上げていきます。
まずは「アクタが触れると何らかのイベントが起きるエリア」を作って、当たり判定(コリジョン)について基本的なことを学んでいきましょう。
レベルのどこにでもある「行動不能になるエリア」を作成します。
また今回から、プロジェクトをアップロードしています(章末)。
参考にしてください。
行動不能(ゲーム失敗)になるアクタの作成
キャラクターが触れたら行動不能になる不可視の範囲(ボリューム)を作成しましょう。
新規アクタを作成します。
コンテンツブラウザの任意のフォルダを開いてください。
「追加/インポート」から「ブループリントクラス」を選択します。
親クラスは「Actor」を選択しましょう。
親クラス「Actor」タイプのブループリント(アクタ)は、これまで編集していた「Character」と同様にレベル上へ複数配置できるオブジェクトです。ただしそれ自体の機能はほとんど無く、一般的にはメッシュなどコンポーネントをくっつけて使います。
Actorは、CharacterMovement コンポーネントが無いので、「Character」のようにジャンプさせるノードなどは持っていません。
図では「Blueprints」というフォルダを新規作成して、そこに「BP_DeadArea」というブループリントを作成しています。
作成したアクタを開きましょう。
コリジョン反応を作成する
ひとまず「プレイヤー(のコリジョン)が、このアクタのコリジョンに接触したら」という状況を作るため、このアクタにコリジョン(当たり判定)を追加しましょう。
コンポーネントパネルの「コンポーネントを追加」から「Box Collision」を選びます。
図のようにコリジョンが追加されたでしょうか。
次項で、キャラクターがこのボックスに触れたらというトリガーイベントを作成していきます。
と、その前に、ここから少しだけ「コリジョン反応」について基本的な説明をしますのでお付き合いください。
初見のときは即座に理解しづらいかもしれません(自分はわかりませんでした…)。
なんとなくわかる程度で構いませんので、どんどん先へ進んでしまいましょう。
既に理解されている方は、読み飛ばしても構いません。
コリジョン反応について
コリジョン反応とは「アクタ同士が衝突するときにどのように処理するか?」を設定するもの、と考えてください。これは「相互作用を定義する」などと言われたりします。
言い換えれば、「ぶつかりあったときに相手のタイプがAだったらBする」設定です。
「どのように処理するか」という反応は3種類あります。
- ブロック(Blocking)
- オーバーラップ(Overlap)
- 無視(Ignore)
図のようにコリジョンではお互いの反応が重要です。
ちなみに、「自分と相手の関係によってコリジョン反応が定義される」とはいえ、当然ひとつひとつ独自の定義がされているわけではありません。
コリジョンは「オブジェクトタイプ」という名前で区分され、自身のタイプと相手のオブジェクトタイプによってどう反応するかがまとめられたプリセットごとに分類管理されています。
コリジョンのタイプを確認・変更する
実際に確認してみましょう。
先ほど作成した「BP_DeadArea」を開きます。
コンポーネントパネルからBoxCollisionを選択してください(デフォルト名:Box)。
詳細パネルを見てみましょう。
「Collision」項目からコリジョン設定が確認できるはずです。
コリジョンプリセット「OverlapAllDynamic」という設定がありますね。
これが前述した、自身と相手タイプによってどう反応するかをまとめたプリセットです。
「コリジョンプリセット」の左にある▷を押して詳細を確認できます。
コリジョンの状態設定(CollisionEnabled)という項目は、このコリジョンが総じてどのように動作するかを設定するもので、以下の4種類があります。
- No Collision:コリジョンを使用しないときに。これを選ぶと全て無視の状態になります。
- Query Only:オーバーラップで反応させたいときに設定します。
- Physics Only:物理シミュレーションに対してのみ使用します。
- Collision Enabled:すべてのコリジョン動作に反応させます。衝突させたいときに。
たくさんあって覚えづらいかもしれませんが、ひとまず無効にしたいときは「No Collision」、オーバーラップさせたいときは「Query Only」、ブロックさせたいときは「Collision Enabled」とだけ覚えておきましょう。
次に、オブジェクトタイプ(Object Type)を確認しましょう。
これが、コリジョンの種類です。
このプリセットのオブジェクトタイプは「WorldDynamic」になっていますね。
その下には、詳細となる相手タイプとその反応のリストを確認できます。ご覧の通り、このプリセットは相手オブジェクトタイプをすべて「オーバーラップ」する設定になっていますね。
確認してみましょう。
確認用の新規レベルを作成します。
既存レベルで確認しても良いのですが、作成したギミックの確認には別途確認用のレベルを作成してチェックする方法をオススメします。
メニューバーから「新規レベル」を選択して、「Default」を選びます。
作成したキャラクターを使いたいので「ワールドセッティング」からGame Modeを設定します。
ではドラッグ&ドロップで、アクタ(BP_DeadArea)を配置してみましょう。
プレイして確認してみましょう。
可視性のあるメッシュなどがないので、どこにコリジョンがあるかわかりませんね……。
コンソールコマンドでプレイ中にデバッグ表示して確認してみます。
プレイ中に「@」キーを押してください。
画面下部にコンソールコマンドを入力するボックスが表示されます。
もし表示されない場合は、メニューバーからプロジェクト設定を開き、インプット項目にある「コンソール」を確認してください。こちらに指定されたキーを使用します。
ボックスに「Show Collision」と入力してEnterを押して決定しましょう。
画面にコリジョンが表示されることが確認できるはずです。
設定通り素通りすることを視認できましたね。
衝突するプレイヤーキャラクター側のコリジョン設定も見ておきましょう。
「ThirdPersonCharacter」のブループリントを開きます。
コンポーネントパネルから「CapsuleComponent」を選択してください。
詳細パネルのコリジョン項目でキャラクターがメインで使用するコリジョンを確認しましょう。
ブロックなのに「BP_DeadArea」と衝突しないのはなぜ? と思うかもしれませんが、前述したとおり、衝突させたい場合は相手側の設定もブロックである必要があります。 Box がオーバラップ設定になっているため、衝突はしないんですね。
仮に、これらを衝突させたいときはどうすれば良いでしょうか?
やってみましょう。
「BP_DeadArea」を開きます。
「Box」を選択します。コリジョンプリセットを「Block All」に変更してみましょう。これはオブジェクトタイプ「World Static」で対Pawnタイプへの反応が「ブロック」です。
コンパイルしてプレイしてみましょう。
コリジョンに乗りました。
どちらのコリジョンも「ブロック」となるので、衝突することを確認できるはずです。
製作時は、このプリセット設定とオブジェクトタイプをうまく使って振り分けていき、
各々のコリジョン設定を管理していく必要があります。
ちなみにここでは割愛しますが、コリジョンのプリセット設定は詳細にカスタムしたり、独自に作成・追加することが可能です。興味がある方は調べてみましょう!
コリジョンのイベント
本題に戻ります。
これまで説明したコリジョン反応を使った「イベント」を作成していきます。
「ブロック」は衝突、「オーバーラップ」は重なりをトリガーにしてイベントを作成できます。
オーバーラップを起点としたイベントを作成してみましょう。
「BP_DeadArea」を開きます。
イベントグラフ上に、「On Component Begin Overlap」イベントが作成されたでしょうか。
これがBoxコリジョンに何かがオーバーラップしたときに実行されるイベントです。
では、イベントに処理を作っていきましょう。
On Component Begin Overlap イベント
手始めに「Print String」を設定してみます。
プレイして確認してみましょう。
想定通りですね。
イベントノードの出力ピンをひとつ使ってみましょう。
「Other Actor」ピンからは、オーバラップしたアクタの情報を取得することができます。
「Other Actor」出力ピンからワイヤーを伸ばして「Print String」のIn Stringピンに接続します。
想定通りですね。
イベントノードの出力ピンをひとつ使ってみましょう。
「Other Actor」ピンからは、オーバラップしたアクタの情報を取得することができます。
「Other Actor」出力ピンからワイヤーを伸ばして「Print String」のIn Stringピンに接続します。
ひとまずはこのピンだけでも覚えておけば大丈夫です!
プレイヤーキャラクター側のイベントを作成する
今後「BP_DeadArea」と似たような処理をするアクタを作成しないとも限りません。そのたびに同じような処理書くのは効率も良いとはいえません。また、アクタAの処理をアクタBに書くことを頻発させるのは管理しづらくなってしまうという理由もあります。
チェック用に「Print String」を接続しました。
コンパイルを忘れずにしておきましょう!(イベントを検索するため)
衝突時のイベントからプレイヤーキャラクターのイベントを呼び出す
「BP_DeadArea」のイベントグラフを開きます。
実際に検索するとわかりますが、「ThirdPersonCharacter」のイベントはこのイベントグラフに直接呼び出すことができません。
正確には「イベントグラフに呼び出すことはできるがコンパイルできない」(実行できない)状態です。これはターゲット(Target)に参照がないためです。
元々のブループリント上のイベントなら(それ自身のイベントであるため)参照は必要ありませんが、他のブループリントから呼び出す場合、かならず「参照」が必要になります。
言うなれば、宛名があっても住所がない状態のようなものですね。
そこでプレイヤーの参照を作成して、そこから処理を呼んでみましょう。
検索ウィンドウに「Player Pawn」と検索して配置します。
なんと、これだけでプレイヤーの参照ができました。
……が、実のところ、これだけでは十分とは言えません。
プレイヤーであることがわかっても、どのプレイヤーのブループリントなのかが、わからないのです。
「ThirdPersonCharacter」かもしれないし、「ThirdPersonCharacter_b」あるいはそれ以外かもしれません。上記のたとえで言うならば、住む町まではわかっているのに、詳細な番地や住所まではわからないようなものです。
「ThirdPersonCharacter」のみに書かれた処理を使うためには、さらに詳細な指定が必要です。
「Get Player Pawn」のReturn Valueからワイヤーを伸ばして、検索ウィンドウを開きます。
その中から「Cast To ThirdPersonCharacter」を検索して配置しましょう。
Cast To 以降の文字列は、そのブループリント名です。
もしキャラクターブループリントの名称を変えていたら、あわせて変更してください。
これで完璧な「プレイヤーの参照」が作成できました。
この「Cast(キャスト)」と呼ばれる方法は、様々な場所で使いますので覚えておきましょう。
Cast ノードは「実行ピン」が2種類あります。
上の実行ピンは正しく参照が作られたときに実行されるピン。下のCast Failed ピンは何らかの原因でCastがうまくいかなかったときに実行されるピンです。
また「As○○」ピンからはCast内容を参照・取得することができます。住所が判明しているので、その住所にあるものは何でも持ってこれるようなものですね。
通常、(Castが成功した)上側の実行ピンの処理を記述していきます。
「As○○」の出力ピンから情報を取得できるので、そこからワイヤーを伸ばします。
「ThirdPersonCharacter」の「Dead」イベントを検索して配置しましょう。
コンパイルして確認しましょう。
「Print String」以降がうまく実行されましたね。
何がオーバーラップしたかを判別する
別のブループリントにあるイベントを呼び出しす処理は完成です。
しかしこの処理には若干の問題点がありました。
こちらをご覧ください。
これは単調なバウンドするアクタを配置して「BP_DeadArea」にオーバーラップするように配置して確認したものです。「Print String」で処理の実行を見てみると、プレイヤーが触れていないにもかかわらずイベントが呼び出されていることがわかります。
単純バウンドするSphereは作成する必要ありません。こういう動作がおきるのかと確認できれば大丈夫です。もし作成してみたい方は、この章の最後に記述しますので作成してみてください(5分もかからず作成できます)
このままでは、プレイヤー以外のアクタがオーバーラップしたときにもプレイヤーが行動不能になってしまいます。プレイヤー以外触れないと決まっていればいいのですが、あまり安定したギミックとは言えませんよね。
このような状態を回避するため、プレイヤーのイベントを呼び出す前に「オーバーラップしたのがプレイヤーキャラクターか?」を判別する処理を差し込みます。
先ほど少しだけ触れた「Other Actor」ピンを使ってみましょう。
「BP_DeadArea」のブループリントを開きます。
「On Component Begin Overlap」の「Other Actor」出力ピンからワイヤーを伸ばします。
オーバーラップしたアクタの情報が取得できるので、アクタが「ThirdPersonCharacter」かどうかを「Cast」ノードで確かめます。
図では余計な「Print String」ノードは省きました(後ろに付け直しても構いません)。
「Get Player Pawn」との接続を外してOther Actorピンに接続しています。
慣れるまで難しいと思うかもしれませんが、この形は覚えておくと便利です。
「Get Player Pawn」からはプレイヤー情報を取得してCast(絞り込み)をしていました。
「Other Actor」ピンからはオーバーラップしたアクタ情報からCast(絞り込み))をしています。
ざっくりたとえるなら、前者は「確実に存在が確定している地域」から住所を絞り込んで、後者は「ある場所を通過したものの中」から絞り込んでいるようなものです。「Other Actor」ピンの場合、かなり広い範囲から絞り込んでいるようなイメージでしょうか。したがって、「Get Player Pawn」からのCastは基本的に失敗しません。
ほぼ存在が確定しているのでCast Failed 以降の実行ピンに処理がながれることはありません。
しかし「Other Actor」ピンからの場合、通過されたものが「ThirdPersonCharacter」とは限らないので、Castで指定したものであれば上の実行ピンが、それ以外であればCastは成功せず「Cast Failed」実行ピンが処理されることになります。
ではプレイして確認して、確認しておきます。
【補足】もうひとつの判別方法
受け取ったアクタが指定したものかどうかは、「=」(比較演算子)とブランチを使って判断することもできます。
「Other Actor」出力ピンからワイヤーを伸ばして「==」と検索して配置します。
これを「Get Player Pawn」の出力ピンと接続して比較しましょう。
キャラクターを行動不能にする処理
キャラクターのイベントを呼び出す処理は完成しました。
続けてキャラクターを行動不能にしてレベルをやり直す処理を作成してみましょう。
「ThirdPersonCharacter」のイベントグラフを開きます。
「Dead」イベントを編集します。
実行ピンからワイヤーを伸ばして「Disable Input」を検索してください。
これは名前のとおり、ターゲットを操作不可にするノードです。
「Disable Input」される対象は、「Player Controller」ピンに接続されたコントローラが対象となりますが、とくになにも接続していない場合はすべてのコントローラからの処理を受け付けなくします。
現状はこのままでOKです。
もし細かく指定しておきたいときは「Get Player Controller」を呼び出して接続しておきましょう。
プレイして確認してみます。
オーバーラップした瞬間に操作できなくなっているはずです。
キャラクターの表示を消す
操作できなくなっても、表示が残っていると少し違和感あるので消してみましょう。
「ThirdPersonCharacter」を開きます。
コンポーネントパネルを確認してください。
コンポーネントパネルにはアクタのコンポーネント(部品)の一覧が表示されていますが、このうち現状プレイ時に可視性を持つのは「Mesh」コンポーネントのみ。この見た目が非表示になる処理を実装すれば消えたように見えるはずです。
「Mesh」を対象にするということで、イベントグラフに「Mesh」の参照を設置します。
コンポーネントパネルからドラッグ&ドロップしましょう。
参照が設置できました。これをターゲットに処理を設置します。
「Mesh」の出力ピンからワイヤーを伸ばして「Set Visibility」を検索して配置します。
これはターゲットに指定されたコンポーネントの表示状態(Visibility)を設定するノードです。
引数の「New Visibility」チェックが「True」なら表示、「False」なら非表示になります。
「Propagate to Children」は、ターゲットの子コンポーネントに対しても処理するかのチェックです。ここではOFFでOKです。
プレイして確認してみましょう。
慣性を即座に止める処理を追加する
これでほぼ問題ありませんが、表示が消えていても移動慣性が残ってしまう点が少し気になります。
つくりによっては、行動不能になったときに視点(カメラ)を切り替えるなどで目立たなくなりそうではありますが、簡単に対応可能ですのでやっておきましょう。
もっとも簡単な方法は、以前学習した「Velocity」と「Gravity Scale」の上書きです。
作成してみましょう。
仮演出を入れる
行動不能になったことがわかるように、仮の演出処理も入れておきます。
「ThirdPersonCharacter」の「Dead」イベント最後にノードを追加します。
ワイヤーを伸ばして「Spawn Emitter at Location」を設置します。
これは指定した位置にエミッター(パーティクル)を出現させるノードです。
「Emitter Template」に生成したいパーティクルを指定します。
視覚効果には「Niagara」と「Cascade」とよばれる2種類の仕組みがありますが、本連載では、入手のしやすさから「Cascade」 パーティクルを使用します。
パーティクル作成方法は長くなるので割愛しますが、別途やるかもしれません。
テンプレートで入れたスターター・コンテンツの「P_Explosion」を指定しましたが、なにを指定しても構いません(内容はあとあと変更可能ですので気に入ったパーティクルを使いましょう)。
他の引数ピンでエミッターの出現する「Location(位置)」「Rotation(角度)」「Scale(大きさ倍率)」などの設定を行います。
キャラクターの位置に出現させるようにしましょう。
右クリックして「get actor location」と検索して設置します。
このノードからキャラクターのLocationを取得できます。
非常に使用頻度の高いノードなので覚えておきましょう。
情報を得るので「Get」
位置情報がほしいので「Location」
と、検索ワードの予想がつくようになれば完璧です。
プレイして確認しておきます。
サウンドも追加してみましょう。
最後の実行ピンからワイヤーを伸ばして「Play Sound at Location」ノードを配置します。
これは指定位置(Location入力ピンの位置)で指定サウンドを鳴らすものです。
Sound ピンに再生するサウンドを指定します。
ここでは「Explosion_Cue」を指定しています(なんでも構いません)。
また、Location入力ピンには配置済みの「Get Actor Location」ノードを接続します。
レベルを読み込みなおす
のちのちチェックポイントなどを入れてもいいですが、現時点ではキャラクターが行動不能になり消えたあと、レベルを読み込み直して最初からプレイさせることにします。
実行ピンからワイヤーを伸ばして「Get Current Level Name」と検索して配置します。
これは「ReturnValue」出力ピンから現在プレイしているレベルの名前を取得できるノードです。
つづけて、「Open Level」というノードを配置しましょう。
これは入力ピン「Level Name」に指定されたレベルを読み込むというノードです。
中間に変換するノードが自動的に作成されて、ノードが繋がりました。
「Get Current Level Name」から出力される文字列(レベル名)は「String型」というタイプ。
そして「Open Level」が受け取れる文字列(レベル名)は「Name型」というタイプになっており、広い意味ではどちらも「文字列」を扱う型です。
基本的に入力できる型は一致していなければならないという決まりがありますが、UE4では文字列を扱うピン同士の接続を自動で変換してくれます。ありがたいですね!
これでレベルを読み込み直す処理はできました。
しかし……
(プレイするとわかりますが)処理の関係上、即座にレベルの再読み込みが実行されてしまいます。
これではせっかく設定した演出を見ることもできませんね。
やり直しにキーやボタン入力を求めることも想定できますが、ここはひとまず間に「Delay」を挟んで対処しましょう。
レベルに配置する
使用するレベルを開いて仮配置します。
「DemoMap」を開いてください。
ここで一点、確認しておく設定があります。
UE4ではレベルごとに「このZ座標までアクタが移動したら自動で消す」という「Kill Z」という機能があり、これがテンプレートからコピーしたマップでは「Z=-1000」に設定されています。
現状「BP_DeadArea」にオーバーラップする前に消されてしまう可能性が高いのです。
設定を変更します。
ワールドセッティングパネルをひらきます。
「キルZ」という値をひとまず初期化しておきます。
これで、勝手に消されることはなくなるはずです。
「BP_DeadArea」を配置します。
サイズを変更するときは手動でスケール調整しても問題ありません。
詳細パネルから「Box」を選んで「Box Extent」で変更する方法もあります。
コンポーネント「Box」のコリジョン自体のサイズを変更していると考えてください。
ぜひこの機会に理解を深めてほしいのは、レベル上に配置したアクタのパラメータを調整しても、ブループリント側には反映されないということです。あくまでもブループリントはオリジナルの設計図。配置されたアクはそれをもとに作られたものだと考えてください。
すでにそう認識されている方にとってはもっともな事ですが…
学習初期では間違えることも往々にしてあるので、念のため。
そのため、逆にブループリント上でパラメータが変更されると、変更された初期値としてレベル上のアクタに反映されます。もし作成したアクタを複数置く場合は、置かれたアクタをひとつひとつ調整するのではなくブループリント側のパラメータを調整するべきでしょう。
すでにレベル上のアクタのパラメータを変更していた場合上書きされることはありません。
このアクタ「BP_DeadArea」は、今のところ複数個設置する予定もないので設置アクタ自体のパラメータを変更しています。
さて、あとあと調整すればいいので、ざっくりと配置していきましょう。
変数フラグを作ってみる(使いたくないときは動作しないようにする)
こういった「即死系のギミック」は、検証したり別ギミックを実装するとき案外邪魔になるものです。そういった時に動作しないようにする処理を入れておきましょう。
無敵になるフラグをつくり、特定のキーを押したときに、動作するようにします。
指定キーはいつでも変更できるので、ここではなんでも構いません。
ひとまずキーボード「1」キーを押したときに設定します。
「ThirdPersonCharacter」を開きます。
マイブループリントパネルから、変数を追加します。名前は「Is Invincible」としました。
変数の型は「Boolean」、コンパイルしてデフォルト値がFalseであることを確認します。
この変数がONのときはキャラクターが無敵状態と判断され、処理が行われないようにします。
キー入力で変数「Is Invincible」のON(True)とOFF(False)ができるようにします。
「1」キーイベントを配置し、変数「Is Invincible」のセットを2つ配置してください。
「Dead」イベントを確認して、付近に変数「Is Invincible」のゲットを配置します。
ブランチで変数「Is Invincible」が「False」のときに処理が流れるようにします。
正しく動作するかプレイ確認します。
「1」キーを押して変数をONにしてから、死亡エリア(BP_DeadZone)に侵入します。
オーバーラップしても行動不能にならないことを確認しましょう。
まあこの場合、ずっと落ちていくだけなのですが……。
とはいえ、この無敵になる変数はその他のギミックでも使う機会がありそうですね。
無敵である場合は「BP_DeadArea」コリジョンに触れたら元の場所に戻る、上方向にジャンプする、空中を自由に動けるといったチェック用の処理を作っても良いかもしれませんね!
なお、プレイするたびに無敵キーを押すのは面倒くさい!
と思う場合は、「変数のデフォルト値」を変更しましょう。
「Is Invincible」変数を選択して、詳細パネルのデフォルト値をTrue(ON)に。
オーバーラップ反応を無効にした状態でプレイを開始できます。
今回は以上です。
お疲れさまでした!
ここまでのプロジェクトをダウンロード
【補足】バウンドを続けるするアクタ
コンテンツブラウザの「追加/インポート」から親クラスActorでブループリントを作成します。
「Sphere」メッシュが追加されました。
これをルート(親)にします。
コンポーネントパネルから「Sphere」を「Default Scene Root」までドラッグ&ドロップします。
続けてコンポーネントパネルから、コンポーネントを追加します。
「Projectile Movement」を検索して追加します。
これは付与されたアクタに対して一方向に飛ばす処理を追加するものです。
コンポーネントパネルから「Projectile Movement」を選択しましょう。
詳細パネルで設定を行います。
Projectile Gravity Scale で動作時の重力を設定します。
0.5程度でゆっくり落下するようにしました。
Should Bounce にチェックを入れてバウンドするようにします。
バウンスは最大の「1.0」(Bounciness)
摩擦は「0」にします(Friction)
Velocity も設定できます。
落下すればいいので、すべて「0」に設定。
これで完成です!
レベルに配置して確認してみましょう。
Projectile Movement は今後学習する予定ですが、興味のある方はこの機会に調べてみてくださいね!