読者です 読者をやめる 読者になる 読者になる

#memo

不正確な内容です、UE4についてが多い

オブジェクトマーカーの実装

正式名称謎だけど、こういうやつ

https://i.gyazo.com/182fde41e4837f26f221e32e1c0f7677.gif

とりあえず基本的な機能は

  • 画面内に収まっているマーカーは、3DWidgetを描画
  • 画面外のものは、画面端に方向を示すWidgetを描画
メインのマーカーWidget作る

https://i.gyazo.com/f24e10ae1294fe53567d2eedc9699f92.png
マーカー用アクタに3DWidgetで適当にやる

画面外の判定

次に、画面端の処理を作るにあたって、そのマーカーが画面内にあるのかどうかを判定する必要が出てくる
PlayerControllerに、ConvertWorldLocationToScreenLocationというノードがあり、ワールド座標を渡すとスクリーン座標を返してくれる
この時に帰ってきた座標が、ビューポートよりも大きいならば画面外という判定ができる

ただ、現在のビューポート(ウインドウサイズ)を取得する関数、BPには用意されておらず、C++で関数を用意する必要がある

UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Screen")
static FVector2D GetGameViewportSize()
{
	FVector2D Result = FVector2D(1, 1);

	if (GEngine && GEngine->GameViewport)
	{
		GEngine->GameViewport->GetViewportSize(Result);
	}

	return Result;
}

ファンクションライブラリにこんな関数を用意してノードを組んでいく

画面端の処理

重要なマーカーは、画面が外れてもその方向がわかるようになっていたりする
実装に入る前に、いろいろなパターンを考えてルールを決める必要がある

例えば、プレイヤーの後ろに高層ビルがあって、その屋上にマーカーがある場合、マーカー方向は画面上に置くのか、下に置くのか

分岐は

  1. マーカーがカメラの後ろ側にある時は、メインマーカーは非表示で画面端マーカーは下側に存在
  2. マーカーがカメラ正面にあり、マーカー座標がビューポート外ならメインマーカーは非表示で画面端マーカーが存在
  3. 上記以外のものはビューポート内にメインマーカーを描画

カメラの後ろ、正面を条件にしている理由は、ConvertWorldLocationToScreenLocationノードは指定座標がカメラの後ろ側だとスクリーン座標が帰ってこないので、後ろ側にある時は専用の処理を作らないといけないため
1に関しては、ConvertWorldLocationToScreenLocationで正常にスクリーン座標が取得できるよう、オブジェクトマーカーの座標を修正(とりあえずスクリーン平面に対してMirror位置に移動させている)している

UE4.13、WidgetでSpriteが使えるようになった

タイトルそのままなのだけれど、UE4.13ではWidgetのimageで、従来のTexture、Materialに加えてPaper2DのSpriteが指定できるようになった

https://i.gyazo.com/2f743b814ac05e328624a5f3d8b39461.png

今までは、例えばアイコンをまとめたアトラステクスチャからWidgetに個々を表示をやるときは、マテリアルを作成してUV座標を数式なり手入力なりで指定する必要があったのだけれど、Spriteを利用することで、エディタ側からパラメーターで個別にアイコンを管理できるようになって楽になった。更にSlateのCall数も減るみたいだけれど、Slateを触ったことがないのでなんとも言えない

https://i.gyazo.com/e08013b68a1ba3149e7e9eb817796043.png

UE4.13で追加されたメッシュデカールについて

デカール、これまでは平面投影するDeferredDecalしかなかったけれど、4.13でメッシュ形状でDecalを描写できる機能がついた
平面投影だと、柱の角とかをきれいに出すのは難しかったのだけれど、これを使うときれいな見た目になる

モデル用意

https://i.gyazo.com/477ae71aa712c96871dbfd8a6237eb8e.png
とりあえず柱のメッシュとMeshDecal用のメッシュを適当に作成する

テクスチャ作成

https://i.gyazo.com/3ec83ace7b773e0a7cb778255f0abce5.png
https://i.gyazo.com/72d849b1295df946c4bf9d26e44a9a24.png
柱のテクスチャはなんでもよく、MeshDecalの方はUVをきれいにやって、それ用のテクスチャを作成する
柱にブレンドするので、それっぽいマスクを作成しておく

マテリアル作成

UEでMeshDecal用のマテリアルを作成する、といっても通常のDeferredDecal用マテリアルと全く同じものを作成すればよく、MeshDecalの真髄はDecalDomainのマテリアルをStaticMeshに適用できるようになったという物っぽい
ちなみに、DBufferは有効にしてある

適用

作成したマテリアルをStaticMeshに設定してレベルに2つのメッシュを配置する

https://i.gyazo.com/ead8d08fdca426e804a1f2234193180b.png
通常のマテリアルでメッシュを重ねてしまうと、このようにヂラつきがひどい

https://i.gyazo.com/1736989509c179efe7ab4ebfe4fbdfe1.png
MeshDecalだとかなり綺麗に出ていて最高、下は通常のDeferredDecal、エッジが薄くなるのと、形状を制御するのが難しい

また、MeshDecalはプロジェクションしているわけではないので、ジオメトリが干渉したりずれるとかなりおかしくなるので、LOD変更とか注意とのことです
https://i.gyazo.com/b1ed3fe1b36ab878fc27e532843a4269.png

UE4、#IF DEBUGもどきマクロの作り方

色々やっているとShippingバージョンではやってほしくないノードとかが出てくる、C++の#IF DEBUGはDEBUGバージョンだけ指定コードをコンパイルしてくれる機能で、これと似たようなマクロがあったら便利
今回できるものは本家と違ってBPから除外するわけではないので、実際に処理が軽くなるみたいなのは薄いけど、見た目がわかりやすくなって良い

Configのビルド設定取得する

ビルド設定はDefaultGame.iniに書かれていて、C++でこれを取得する関数を用意すると今のビルド設定が見れる

DefaultGame.iniの

[/Script/UnrealEd.ProjectPackagingSettings]
BuildConfiguration=PPBC_Development

これがビルド設定の部分、エディタのビルド設定は "Debug", "Development", "Shipping" があり、これに対応するのは
"PPBC_DebugGame", "PPBC_Development", "PPBC_Shipping" となる(確認したのはwindowsなのでOSXとかなら変わるかも)

この設定を見る関数をFunctionLibrary辺りに作る

.h
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Configuration")
static void GetBuildConfiguration(FString& Type);
 
.cpp
void UBlueprintFunctionLibraryCpp1::GetBuildConfiguration(FString& Type)
{
	GConfig->GetString(
		TEXT("/Script/UnrealEd.ProjectPackagingSettings"),
		TEXT("BuildConfiguration"),
		Type,
		GGameIni
	);
}
エディタでマクロ組む

あとはエディタのMacroLibraryでこのようなマクロを作成すると、IFDEBUGもどきノードができる

https://embed.gyazo.com/4f36c3e9e3e01c664894a07fc6ec525f.png

SwitchOnStringノードはAdd pinで、文字列と一致した場合はこっちに進むみたいな処理を作れる

UE4、Inputの長押し処理の実装

十字キーでインベントリのリストを送るみたいな処理、長押しのときはループでやってほしい
これを作るためには、Inputの長押し判定を作る必要がある

https://i.gyazo.com/d23b61749e12bfdcd0ffc56c93b94738.png

PlayerControllerのGetInputKeyTimeDown()関数にKey構造体を渡すとそのボタンが何秒押されているかを返してくれる、リリースのたびに0に戻る
LongPressThresholdで指定した秒数以上長押ししているとループ内の関数が実行される、右端のDelayがループ間隔になる

マクロにするとこんな感じ

https://i.gyazo.com/6ae17a368976c3339d3bba66aa1ffe6b.png

UE4、KillZVolumeの挙動について

KillZVolumeは、触れたアクタの持つFellOutOfWorld()という関数を実行するように言う(これだけの実装)
FellOutOfWorld()はAActorに実装があり

  1. Physicsを切る
  2. ActorHiddenInGameをtrueに
  3. ActorEnableCollisionをfalseに
  4. Destroy()実行

という処理を行う

FellOutOfWorld()はBPでオーバーライドできるようにはなっておらず、C++側でオーバーライドする必要がある

UE4、BPでのデストラクタ処理の作り方

アクタ(AActor継承クラス)がDestroyされたときの流れ

  1. Destroy()呼ばれる
  2. Destroy()の中でDestroyed()呼ばれる
  3. Destroyed()の中でReceiveDestroyed()呼ばれる
  4. Destroyed()の中でOnDestroyed()呼ばれる

BPではReceiveDestroyedOnDestroyedを使用する、これらの関数はC++側には実装はない

ReceiveDestroyed
BlueprintImplementableEventとして定義されているので、BPでオーバーライドして使用する
DisplayName = “Destroyed”となっているので、BPでは"Event Destroyed"ノードとして現れる(C++のDestroyed()とは別)

参考
Unreal Engine | ゲームプレイ要素をブループリントに公開する

OnDestroyed
イベントディスパッチャー(DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam)として定義されていて、BPではバインドして使用する
ReceiveDestroyedとの違いは、DestroyedされたActorがポインタとして返ってくるのでどうこうしたいならこちらを使用する

参考
Unreal Engine | マルチキャスト デリゲート


実行順序は、ReceiveDestroyedのほうが一行だけ先に呼ばれる

https://i.gyazo.com/fdb8fe996a76e190560c43ad147aeccc.png