ブループリントのアクター関連の関数とイベント（Unreal Engine 4.25）

# 前提

身内用に書いたものを、暫定的に公開しているものです。何かおこったら閉じるかもしれません。

[前の記事](https://qiita.com/mml/items/5273a7699cdeb9ca21da)に書いた知識（ブループリントの最低限の知識）は持っている、という前提で書いてます。特に説明のない限り、Unreal Engine 4.25 で FirstPerson テンプレートで作成したプロジェクトのレベルブループリントのイベントグラフ上で操作をする前提です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/7689a532-411d-5340-427e-4fc497f9fa06.png)

# 準備

外部オブジェクト(ブループリント）の参照の例の説明のために、FirstPerson プロジェクトにブループリントを追加しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/51aac3d0-b2e5-e60e-b61f-69f6094f41c9.png)

キューブのアクターをひとつ画面内に配置して、右の詳細から「ブループリント/スクリプトを追加」を押して、ブループリントを追加してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/792f09d0-b866-b612-150c-2ce6ca8dd551.png)

デフォルトで Cube_Blueprint という名前のブループリントになりますが、ここではそのままの名前で作成したものとして説明します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/2a635e11-8f38-48e0-51f7-ee8346539cdc.png)

# アクターの重要な設定項目

主にスタティックメッシュかスケルタルメッシュを持つアクターについてです。メッシュを持たないアクターは、基本的に物理シミュレーション (Simulate Physics) ができないので、それ関係の設定はできません。

## アクターを動くようにする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/960278e4-9854-751a-b0f2-5839ea08a029.png)

「可動性」を「ムーバブル」に設定しないと、アクターを移動させるようなプログラムを書いても動きません。プログラムを書いても動かないときは、これが原因なことが多いです。

## アクターがぶつかったり力が加わったり動いたり転がるようにする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/6fc153d6-bed9-d9d9-2b76-69edd586db41.png)

「物理」の Simulation Physics にチェックを入れると、アクターが他のアクターにぶつかったり、何らかの力を加えられたときに、アクターが自動的に（物理シミュレーションで）鵜とくようになります。

![ue8.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/e1f02388-1770-b502-b299-fb4fe0fcfc13.gif)

Enable Gravity もチェックを入れると、重力の影響も受けるようになります。上のような坂道を作って、球体を配置して Simulation Physics と Enable Gravity にチェックを入れると、プログラムを何も書かなくても「プレイ」すれば玉が坂道を転がります。Simulataion Physics にチェックが入っている玉に、キャラクターを操作してぶつかれば、玉を押すこともできます。

後述する AddImpulse のような関数でアクターに力（厳密には力積）を加えて動かすときも、Simulation Physics にチェックを入れておく必要があります。チェックが入っていないと、AddImpulse で力積を加えてもアクターは動きません。

## アクターの衝突に関するイベントを拾えるようにする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/4c7252f5-dd58-30e8-981a-8169ebf7915b.png)

「コリジョン」の Simulation Generates Hit Events にチェックを入れることで、アクターがぶつかったときのイベント（Hitイベント）を拾えるようになります。アクターのブループリントに Hit イベントを配置しても、このチェックを入れておかないと、Hit イベントは拾えません。ぶつかる側のアクターも同じように Simulation Generates Hit Events にチェックが入っている必要があります。

Generate Overlap Events にチェックを入れると、OnActorBeginOverlap イベントと OnActorEndOverlap イベントを拾えるようになります。片方のアクターの内側に、他のアクターが入り込んだ時にイベントが呼び出されます。いろいろ試した限りでは、ぶつかっただけでは Overlap イベントは発生しないようです。

ぶつかりの判定をするための物理マテリアルを Phys Material Override に設定すれば、見かけの形状（メッシュの形状）とは異なるぶ形状でぶつかり判定をすることもできます。

イベントがどんな条件で呼び出されるかは、下記に詳しいドキュメントがあります（微妙にあてにならないところはありますが・・・）。

- [イベント](https://docs.unrealengine.com/ja/Engine/Blueprints/UserGuide/Events/index.html): 公式ドキュメント

# アクターに関連するイベントや関数



## 他のアクターと重なったときのイベントを拾う

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/1f6a4630-af02-9013-b744-e4aae05a5154.png)

上のように平面、球体、ボックストリガーを配置して、球は Simulation Physics と Enable Gravity と Generate Overlap Events にチェックを入れておきます。ボックストリガーのほうは Generate Overlap Events にだけチェックを入れておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/4975d6fc-55c7-e98f-b61b-080b6dcd3a12.png)

球のアクタに上のようにブループリントを追加してプレイすると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/7b63843d-a07d-c6dd-302b-3b55008d9099.png)

ボックストリガーに球が転がり込むと、OnActorBeginOverlap イベントが呼び出されて、Hello と文字が表示されます。ボックストリガーか球のいずれかの Generate Overlap Events にチェックが入っていないと、Hello は表示されません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b87f3a69-19b7-be95-7aac-6c4667a6419f.png)

Other Actor を使えば、オーバーラップした相手のアクタ（オブジェクト）を調べることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/c774fa4b-f274-afac-2a6b-f3cf2922adcf.png)

重なり状態が終了したイベントは、OnActorEndOverlap イベントで拾えます。

## 他のアクターとぶつかったイベントを拾う

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/464e7f89-285c-8b72-dfeb-2211a9f03bbc.png)

上のような感じで球、平面、キューブを配置して、球だけ Simulation Generates Hit Events にチェックを入れておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/9052686e-f709-6101-7aba-b1b48321ba72.png)

球をブループリントクラスにして、下記のようなコードを書くと、他のアクターと衝突したときのイベントを拾えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a066e8ff-bd20-5473-8909-43fa6be80abc.png)

大量にHitが表示されるのは、球が転がるたびに Hit イベントが発生しているからです。また、Hit イベントは、Simulation Generates Hit Events にチェックを入れると、ぶつかった相手側の Simulation Generates Hit Events にチェックが入っていてもいなくても発生します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/af36c45d-80c3-785f-f57b-076f6d2de71e.png)

Other パラメータを使うことで、特定のアクターとぶつかったときだけ処理をするようにできます。上の例では DisplayName を使って Cube にぶつかったときだけ画面に文字を表示するようにしています。

## ぶつかった位置や角度を調べる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/4f6cb2b0-e4de-6aa8-320d-49069ced7085.png)

ぶつかった位置や角度、ぶつかったときの力の強さなどのパラメータをイベントから取得できます。ぶつかった位置は HitLocation、ぶつかった角度は HitNormal、ぶつかったときの力の強さは  NormalImpulse でそれぞれ取得できます。

上の図は FirstPersonExample の FirstPersonProjectile クラスのイベントグラフです。コンテンツブラウザの「コンテンツ」「FirstPersonBP」「Blueprint」の中にある FirstPersonProjectile を開くとみることができます。Projectile はマウスの左ボタンをクリックすると発射される黄色い球で、Simulation Physics が ON になっているアクターにぶつかったときだけ、そのアクタに力を加えています。

HitLocation と HitNormal でぶつかった位置と角度を取得し、その方向に対して力を加えています。

## ぶつかったときにさらに力を加える

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/94eccee1-3558-dd04-d1c9-85f32bfd8f0f.png)
 
相手側だけでなく、ぶつかった自分自身に力を加えることもできます。上のコードを球側のブループリントに書くと、球が Cube にぶつかったときに、ものすごい勢いで反対側に飛んでいくはずです。

球の Simulation Physics を ON にしていれば、ぶつかったときの物理的な衝撃が球に加わるので、プログラムを書かなくても球は弾かれたような挙動をします。AAddImpulse  で10倍に増幅させた力積を加えると、球にはぶつかったときに受ける力に加えて、さらに10倍の力が加わってすっ飛ぶという感じです。

AddImpulse のかわりに AddForce というノードを使って、力（力積えではない）を加えることもできます。力と力積の違い、AddImpulse と AddForce の違いについて説明すると物理の、下記の記事がおもしろかったので参考にしてください。

- [第一次 Add Force / Add Impulse 戦争](http://ikagamedev.hatenablog.com/entry/2017/02/01/204221)

いずれも Simulation Physics が ON でないと機能しません。また、AddForce や AddImpulse の引数のターゲットのノード（Static Mesh Component）は、AddFOrce などのノードを追加すると自動的に追加されます。

## アクターを強制的に停止させたり加わった力をキャンセルしたりする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/6908baff-092e-762f-d6a8-db09467d1d56.png)

SetSimulationPhysics ノードを使うと、アクターの物理シミュレーションを強制的に停止させて、その場に停止させることができます。加わった力もキャンセルできます。落下中のアクタや転がっているアクタを強制的に止めたり、ぶつかったときに、いったん運動を停止させて改めて動かす方向を決めたいときなどに使えます。止まったアクタに力を加えるときは、改めて SimulationPhysics を ON にしてから加える必要があります。

なお、あくまで物理シミュレーションを止めるだけなので、次に書く SetActorLocation などで強制的に位置を移動させた場合は、それを止めることはできません。

## アクターの位置を取得したり設定したりする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/61b4e152-e991-04bc-5e3d-d1b179ef02ed.png)

GetActorLocation でアクターの三次元座標を取得できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/3b5ea2b6-4b6e-e5c8-c040-a4c43407fab0.png)

上のようなコードをかくと、位置座標を毎フレーム取得して画面に表示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/ad6d88cc-965a-2e6d-91e9-87972808a590.png)

球のブループリントにこんな感じのコードを書くと、アクターに毎フレームZ軸（上）方向に1㎝だけ移動させます。Simulation Physics と Enable Gravity が ON になっていると、球がぴょんぴょん跳ねながら移動するようになるはずです。

SetActorLocation は指定した座標に強制的にアクターを移動させることができますが、Simulation Physics でエンジンから与えられる物理的な力はそのままになるので、移動させたあとに重力にひかれて落ちてしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/acfef414-7f2e-f784-1fbe-b8620304bdb3.png)

Simulation Physics か Enable Gravity を OFF にすれば、空中にどんどん浮いていきます。

## アクターの角度や拡大率を設定したり取得したりする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/ca5c4e85-f7e0-5b98-d10c-21c3db00d05f.png)

回転角度は GetActorRotation で取得できます。SetActorRotation で回転角を設定することもできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b6748341-8d2d-ccaf-f080-461a16935344.png)

拡大率（Scale）は GetActorTransform と BreakTransform ノードを使って取り出します。拡大率の設定は MakeTransform と SetActorTransform を組み合わせて使います。SetActorTransform では、Location と Rotation も同時に設定できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a523f668-38e7-0f78-945f-3c8dee0a97b5.png)

上のコードを球のブループリントに設定して実行すると、やばい勢いで球がふくらんでいきます。

## アクタを新たに生成してレベル内に配置する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/3a99993d-2c74-f10b-4311-863e71fc2f85.png)

SpawnActorFromClass を使えばプログラム（ブループリント）でアクタを生成して、レベル内に配置することができます。上のコードはレベルブループリントに書いています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/6ad49d82-2f98-d1d1-af53-37f9d7dfa681.png)

ノードの検索では、SpawnActor と入力して「クラスからアクタをスポーンします」という項目を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/7d715948-790e-e847-6c46-51defcf9a1b2.png)

スポーンアクタ NONE というノードが配置されるので、Class のところから配置したいアクタのブループリントクラスを選びます。（ここでは、この記事の冒頭の説明で用意した Cube＿Blueprint を選んでいます）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/3099b19f-72b6-ca99-1014-21829e984710.png)

クラスを選ぶと、ノードの名前にクラス名が入ります（なぜか Spawn と英語表記になります）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/3a99993d-2c74-f10b-4311-863e71fc2f85.png)

Transform 変数で、出現する位置を指定できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/ebea605f-10d9-4fc6-d4c8-ff52b8545b3a.png)

Location を 0,0,300 くらいにすると、プレイヤーの目の前くらいに出現するはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/3341d550-a4f3-dded-0dd1-6df95a17938f.png)

上のコードを実行して左SHIFTキーをおしまくると、立方体が無限に出現するはずです。Cube_Blueprint の Simulation Physics と Enable Gravity が ON になっていれば、Cube は出現した瞬間にしたに落ちたり、他のアクタにぶつかったら跳ね返ったりします。

## アクタを消滅させる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/53998232-b905-5d06-0960-4c0a0f1905e0.png)

DestroyActor ノードを使えば、画面内に配置されているアクタを消滅させることができます。SpawnActor で出現させられた側（Cube_Blueprint）に上のようなコードを書くと、左SHIFTキーでCubeのアクタが出現したあと、そのアクタは6秒後に問答無用で消滅します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/96de37df-bad6-4b6b-9aa9-1fefd9c7ef3e.png)

何かがぶつかったら消滅するようにするには、例えば上のようにします。ぶつかった相手のアクターを名前で判別しています （FirstPersonProjectile_C はプレイヤーが発射した球のクラス名です）。

DestroyActor を消滅するアクター自身で使用すると、そのノードの後ろに何か実行するノードを配置した場合、実行されるかどうかは保証されないようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/bf58a4bc-035c-a7be-d76a-8380ddfbbcf1.png)

例えば上のように、DestroyActor の次に PrintText ノードをつなげた場合、だいたいの環境では PrintText が実行されて Hello と表示されます（実行されない場合もあります）。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/c05e5e2e-956c-ba89-1386-b28af8ab14c2.png)

このように Delay を入れると、ほとんどの環境で PrintText は実行されません。DestroyActor を使用した後のどこかの時点で、UE がアクタを破壊してしまうので、その破壊されたタイミングより後は、プログラムに書かれたノードでも実行されないということのようです。

アクターを消滅させるときに、爆発のアニメーションや音をつけたりするときは、DestroyActor の実行を最後にするか、レベルブループリントのような消滅させる側のコードとして記述するのがよさそうです。

# 続くかも

次回があるならウィジェットの予定です