PaperSloth’s diary

主にゲーム開発関連についての記事を書きます。

UE4 個人開発メモ

最終更新日:2017/12/03

概要

 個人開発でのUE4のEditor Preference, Project Settings等のメモ
 随時更新していきます。
 基本はWindowsPC向けの内容。
 家庭用ゲーム機、アーケードゲーム、モバイル、XR(AR / VR)でも役立つ内容も含みます。
 各項目には確認時のバージョンを記載しています。
 バージョンが古かったり新しかったりすると
 項目がなくなったり、場所や名前が変わったりしている可能性があります。

環境

・Platform : Windows
・Unreal Engine4.17.2~
Visual Studio Community 2015


Project Settings

Windowタイトルの変更方法(UE4.17.2)

 WindowタイトルとはPC向けに作成した際のWidnowの左上に出るタイトルです。
f:id:PaperSloth:20171130003303p:plain

 何も指定していない場合はProject名が表示されます。

 設定は下図のProject - Description - Displayed
 「Project Displayed Title」から変更できます。
f:id:PaperSloth:20171130004532p:plain

 試しに"Example Window Name"と入れてみました。
f:id:PaperSloth:20171130004635p:plain

Application名の変更方法(UE4.17.2)

 上記Windowsタイトルとよく間違えやすいのがこれです。
 設定は下図のProject - Description - About
 「Project Name」から変更できます。
 デフォルトではUE4Gameと入っています。
f:id:PaperSloth:20171130005438p:plain

 よくWindowタイトルを変更しようとしますが、ここを変えても上手くいきません。
 この名前はタスクマネージャー等で表示されるアプリの名前です。
f:id:PaperSloth:20171130005618p:plain

 ちょっと図がわかりにくいのですがProject Nameがあって、その下にWindowTitleがくるようになっています。
 編集をしていない場合だと、UE4Gameの下にProject名がくるようになっています。
f:id:PaperSloth:20171130010129p:plain

シェーダーモデルの制限によるメモリ容量削減(UE4.17.2)

 設定は下図のPlatforms - Windows
 「Targeted RHIs」から変更できます。

 UE4Windows向けに作成している場合
 デフォルトのRHI(Rendering Hardward Interface)はDX10, DX11が有効になっています。
f:id:PaperSloth:20171130220108p:plain
 これをDX11(ShaderModel5)のみにすることで不要なシェーダーが減り、パッケージ容量を削減できます。
 ThirdPersonTemplate等で試してみてもほぼ全く変わらないのですが
 規模が大きく、マテリアルが増えるほど効果が現れやすい部分です。

 試しに自分のゲームで比較してみた結果
 DX10, 11だと242KBのシェーダー
f:id:PaperSloth:20171130221048p:plain
 DX11のみだと124KBと約半分の容量になりました。
f:id:PaperSloth:20171130221057p:plain

 このように数百KB程度だと微々たる差ですが、これが数百、数千のマテリアルとなると話が変わってきます。
 また、シェーダーも1つで数百MBだと半分ほどの容量になるのは大きな変化ですね。

パッケージング関連

 項目が多いので、細かく分けます。
 設定箇所はProject - Packaging以下のものになります。

PakFileの使用(UE4.17.2)

 「Use Pak File」にチェックを入れると有効になります。
 説明の前に図で見てもらうと分かりやすいと思います。
 Pak Fileを使用した場合
f:id:PaperSloth:20171130222234p:plain
 中には.pakの形式でContent以下のAssetが1つのデータに圧縮されています。

 Pak Fileを使用しない場合
f:id:PaperSloth:20171130222333p:plain

 Pakファイルの使用は容量の削減になり
 転送ファイル数が減るので配布時のダウンロードも早くなり
 ロードも早くなるため使用することを推奨します。
 容量の参考までに自分のプロジェクトで使用した場合の容量を載せておきます。
 使用した場合  :532MB
 使用しない場合 :786MB

パッケージの圧縮(4.17.2)

 「Create compressed cooked packages」にチェックを入れると有効になります。
 f:id:PaperSloth:20171203220605p:plain
 なお、このオプションの効果を有効にするにはUse Pak Fileにチェックを入れておく必要があります。
 容量の参考までに自分のプロジェクトで使用した場合の容量を載せておきます。
 使用した場合  :547MB
 使用しない場合 :950MB

 さて、パッケージの圧縮はDLで配信するPC向け等にはオススメですが、
 一部プラットフォームは注意が必要です。
 PlayStation 4の場合
  PlayStation 4 の圧縮と重複し、ファイル サイズは減らずにロード時間が長くなってしまいます。
 Nintendo Switchの場合
  ロード時間が早くなる場合と遅くなる場合があります。
 詳しくは下部の参考資料のリンクを見てください。


Editor Preference

Blutilityの有効化(UE4.17.2)

 BlutilitはBlueprintをEditor上で呼び出すことでお手軽にEditor拡張が出来る機能です。
 UE4.17.2現在は実験的な機能として提供されています。
 この機能に関しては不安定というよりは、機能がまだ足りないため実験的な機能なのだと思います。

 設定は下図のEditor Preference - General - Experimental - Tools
 「Editor Utility Blueprints(Blutility)」から有効に出来ます。
 有効にした際のEditorの再起動は不要です。
f:id:PaperSloth:20171130011354p:plain

EQS(Environment Querying System)の有効化(UE4.17.2)

 EQSはAIが目的に応じた位置を探す時に使われる機能です。
 この位置は動的に生成され、その中から最もスコアの高い位置を選択します。

 こちらも実験的な機能として提供されていますが
 EpicGamesの開発タイトルである「Robo Recall」でも採用されており、信頼性は高いです。

 設定は下図のEditor Preference - General - Experimental - AI
 「Environment Querying System」から有効に出来ます。
 有効にした際のEditorの再起動は不要です。
f:id:PaperSloth:20171130012353p:plain

参考資料

シェーダーモデルの制限によるメモリ容量削減
バイキング様のスライド63ページ付近に該当箇所の説明があります。
マジシャンズデッド ポストモーテム ~マテリアル編~ (株式会社Byking: 鈴木孝司様、成相真治様) #UE4DD

パッケージング関連
パッケージの圧縮によるプラットフォームごとの注意点等詳しくはドキュメントに載っています。
Unreal Engine | プロジェクトのパッケージ化

UE4 C++でTimerを使用した処理の書き方

環境

Visual Studio Community 2017
・Unreal Engine4.20.3

SetTimer by Eventについて

指定時間の経過後に処理を呼び出せる便利なノードです。
f:id:PaperSloth:20180924153029p:plain

こういったLatentノードではDelayなんかをよく使うと思います。
SetTimer系の便利なとこはループさせたり
任意のタイミングでループを終了させたりできることですね。

似た関数でSet Timer by Function Nameというのがあります。
今回はこちらの解説は端折ります。
個人的に関数名を文字列で渡したりするのはあんまり好きではないですね。
f:id:PaperSloth:20180924153036p:plain

Unreal C++での実装について

FTimerManagerについて

こういったタイマー系の処理は素直にC++で組むと結構面倒です。
ですが、Unreal C++は色々と便利な関数を用意してくれています。

先ずはSetTimer関数を呼び出すためにFTimerManagerを取得します。
TimerManagerはWorldが保持しており、このように取得できます。

FTimerManager& timerManager = GetWorld()->GetTimerManager();

また、Actorを継承したクラスであれば下記のように取得できます。

FTimerManager& timerManager = GetWorldTimerManager();

SetTimerについて

TimerManagerの中にSetTimer関数があるのでこちらを使用します。
今回は例としてActorからの呼び出しを行っています。

FTimerHandle handle;

// Function:デリゲートとして渡す関数
// Duration:遅延させる秒数
// InLoop  :処理をループさせるか
GetWorldTimerManager().SetTimer(handle, this, /*Function*/, /*Duration*/, /*InLoop*/);

簡単な例として0.2秒後にLogを出す処理を書いてみます。

void AExampleActor::BeginPlay()
{
    Super::BeginPlay();
    FTimerHandle handle;
    GetWorldTimerManager().SetTimer(handle, this, &AExampleActor::OutputLog, 0.2f, false);
}

void AExampleActor::OutputLog()
{
    UE_LOG(LogTemp, Log, TEXT("Call SetTimer"));
}

また、SetTimerはいくつか種類があり、ラムダ式を使用することもできるため
簡単な処理であれば直接書いてしまってもいいかもしれません。
この場合は引数としてthisポインタを渡しておらず、引数が違う点に注意です。

void AExampleActor::BeginPlay()
{
    Super::BeginPlay();
    FTimerHandle handle;
    GetWorldTimerManager().SetTimer(handle, []()
        {
            UE_LOG(LogTemp, Error, TEXT("Log message"));
        } , 0.2f, false
    );
}

タイマーの停止、再開について

処理をループさせている場合のタイマーの停止、再開は下記のように行います。

FTimerHandle handle;
FTimerManager& timerManager = GetWorldTimerManager();

// タイマー停止
timerManager.PauseTimer(handle);
// タイマー再開
timerManager.UnPauseTimer(handle);

これで任意のタイミングでタイマーを操作できます。

タイマーの終了処理について

タイマーを使用した場合は終了処理も合わせて書くようにしましょう。

void AExampleActor::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
    Super::EndPlay(EndPlayReason);

    FTimerManager& timerManager = GetWorldTimerManager();

    // Handleに登録されたTimerの解放
    timerManager.ClearTimer(handle);
 
    // このActorが所有するタイマーの解放
    timerManager.ClearAllTimersForObject(this);
}

引数付きの関数を渡す場合について

関数にパラメーターを渡す場合はFTimerDelegateのBindUFunctionを使用します。
このBindUFunctionを使用する場合はUFUNCTIONマクロがないとエラーになるので注意です。
UFUNCTIONの説明の際に軽く触れています。
UE4 UFUNCTIONの種類について - PaperSloth’s diary

// Header
// BindUFunctionに渡す関数はUFUNCTIONの定義がないとエラーになる
UFUNCTION()
void InitializeTransform(const int32 Id, const FVector& Location, const FQuat& Quat);

// cpp
void AExampleActor::InitializeTransform(const int32 Id, const FVector& Location, const FQuat& Quat)
{
    UE_LOG(LogTemp, Error, TEXT("Call InitializeTransform"));
}
FTimerHandle handle;
FTimerManager& TimerManager = GetWorldTimerManager();

FTimerDelegate TimerDelegate;
// BindUFunctionで使用する関数名、引数に渡す値を入れる
TimerDelegate.BindUFunction(this, FName("InitializeTransform"), 100, FVector::ZeroVector, FQuat::Identity);
TimerManager.SetTimer(handle, TimerDelegate, 1.0f, false);

BindUFunctionは文字列で関数名を渡すため、関数名や引数を変更する際は漏れが発生しやすく注意が必要です。

参考資料

Delay in C++ - UE4 AnswerHub
Using SetTimer() on a Function with Parameters - UE4 AnswerHub


とりあえずはこれでC++側でも簡単に時間を遅らせて処理をすることができますね。
最後にコードを全て載せておきます。

VisualStudio UE4のCode Snippets登録について

環境

Visual Studio Community 2017
・Unreal Engine4 git release branch(4.20.2)


Code Snippetsについて

簡単に言ってしまうとよく使うコードのテンプレートを簡単に呼び出せるものです。
Visual C++ のコード スニペット - Visual Studio | Microsoft Docs

例えばUE4の場合はマクロが多く、都度入力するのが結構な手間だったりします。
特にstruct, enum, property, functionあたりが定義が面倒で使用頻度が高いですね。


UE4のCode Snippetsについて

以前に何度か使うといいですよとは書いたものの…
UE4 Unreal C++を書くための環境構築 - PaperSloth’s diary
UE4 UFUNCTIONの種類について - PaperSloth’s diary
使い方が書いていなかったため、今回改めてまとめてみました。

GitやPerforceからエンジンコードを取得した際に
Engine\Extras\VisualStudioSnippets の中にCodeSnippetsが保存されています。
4.20.2現在で64種類あるようです。

GitHub経由でのダウンロード方法についてはこちら
Unreal Engine | アンリアル エンジン ソースコードのダウンロード


Code Snippetsのインポート方法

Visual Studioのツールの中にコードスニペットマネージャーがあるので、それを開きます。
(CtrlK, CtrlBでも開けます)

コードスニペットマネージャーを開いたら言語をVisual C++に変更します。
f:id:PaperSloth:20180919221736p:plain

続いてインポートを押下します。
その後、Engine\Extras\VisualStudioSnippets 以下のコードスニペットを全て選択します。
すると下図のようにインポート画面が開くため、My Code Snippetsにチェックを入れて完了します。
f:id:PaperSloth:20180919221949p:plain

インポートが正常に完了していれば
Visual Studio (VersionName)\Code Snippets\Visual C++\My Code Snippets 以下に
先程インポートしたCode Snippetsがコピーされています。
直接ここにSnippetsをコピーしてVisual Studioを再起動でも動作すると思います。


Code Snippetsの使い方

SnippetのShortcutに登録された名前を入力してTabで使用できます。
よく使うのはuproperty, ufunction, ue4log, ue4enum, ue4structあたりでしょうか。

私の場合はue4enum, ue4logとかは少し編集しています。
是非とも自分の使いやすいように気軽にsnipettを編集してみてください。
f:id:PaperSloth:20180919223732g:plain

UE4 UFUNCTIONの種類について

環境

Visual Studio Community 2017
・Unreal Engine4.20.2


概要

UFUNCTIONの呼び出しについて日本語でまとまった情報が少なく
毎回BlueprintImplementableEventとBlueprintNativeEventあたりがごっちゃになるのでまとめる。

この記事で説明しないこと
メタデータ指定子(BlueprintAutocast, BlueprintInternalUseOnlyとかとか)
 Metadata Specifiers
・RPC(Client, Server, NetMulticast, Reliable, Validation)について
 RPCs | Unreal Engine



C++関数とBlueprintの連携について

BlueprintCallable

Blueprintからの呼び出しが可能になる。
UPROPERTYの場合はCategoryがなくてもエラーにならないが
UFUNCTIONはCategoryの指定がない場合エラーとなる。

UFUNCTION(BlueprintCallable, Category="Transformation")
void UpdateActorTransform(const FTransform& Transform);

f:id:PaperSloth:20180919193059p:plain

BlueprintPure

Blueprintからの呼び出しが可能。
実行ピンを持たないノードになる。
Pure関数の作成方法は下記の2種類がある。

①通常のPure関数

UFUNCTION(BlueprintPure, Category="Transformation")
FTransform GetTransformPure();

f:id:PaperSloth:20180919193139p:plain

②const指定した場合はBlueprintCallableであっても
Pure関数となり、実行ピンを持たない。

UFUNCTION(BlueprintCallable, Category="Transformation")
FTransform GetActorTransform() const;

f:id:PaperSloth:20180919193214p:plain

BlueprintImplementableEvent

Blueprintからの呼び出しが可能でC++側での実装は持たない。
BlueprintCallableを指定しない場合はBlueprint側で呼び出しはできない
C++側からは呼び出しが可能なため
意図的にBlueprintのみにロジックを書くこともできる

UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category="Vehicle")
void SpawnVehicle();

f:id:PaperSloth:20180919193324p:plain

BlueprintCallableを指定していればBlueprintからも呼び出しが可能
f:id:PaperSloth:20180919193740p:plain

戻り値がvoidの場合はEventNodeが生成されるが
戻り値を持つ関数の場合はEventではなく関数として生成される

UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category="Vehicle")
bool CanSpawnVehicle();

処理を記述する場合はOverrideして使用する
f:id:PaperSloth:20180919193434p:plain

f:id:PaperSloth:20180919193456p:plain

BlueprintNativeEvent

Blueprintからの呼び出しが可能でC++側での実装を持つ
BlueprintCallableを指定しない場合はBlueprint側で呼び出しはできない
C++で基本的な実装を行い、Blueprintでロジックを拡張する場合等に使う

UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category="Job")
void UpdateCharacterJob();

f:id:PaperSloth:20180919193927p:plain

C++側での実装は「"関数名"_Implementation」という書き方でなければならない

void AExampleActor::UpdateCharacterJob_Implementation()
{
}

C++側で関数を呼び出す場合は注意が必要
呼び出し時に_ImplementationをつけるとC++側の実装のみが呼び出される

呼び出し時に_ImplementationをつけなければBlueprint側の実装のみが呼び出される
この時にNode側でParentを呼び出していないとC++側の処理は実行されない

void AExampleActor::BeginPlay()
{
    Super::BeginPlay();
    // C++側の実装のみ呼び出し
    //UpdateCharacterJob_Implementation();

    // Blueprintの実装呼び出し
    UpdateCharacterJob();
}

その他

Categoryの階層構造について

UPROPERTY同様に"|"をつけることで階層構造になる。

UFUNCTION(BlueprintCallable, Category = "Utilities|Log")
void PrintLog(const FString& Log);

f:id:PaperSloth:20180919194145p:plain

参照について

引数を参照にした場合に入力ピンとなる場合と出力ピンとなる場合がある

①const参照の場合
入力ピンとして扱われる

UFUNCTION(BlueprintCallable, Category="Collision")
bool SimpleRayTrace(const FVector& StartLocation, const FVector& EndLocation);

f:id:PaperSloth:20180919194232p:plain

②constなしの参照の場合
出力ピンとして扱われる

UFUNCTION(BlueprintCallable, Category="Collision")
bool SimpleRayTraceHit(const FVector& StartLocation, const FVector& EndLocation, FHitResult& OutHit);

f:id:PaperSloth:20180919194304p:plain

③constなしの参照を入力として扱いたい場合
UPARAM(ref)を付けることで入力として扱われる

UFUNCTION(BlueprintCallable, Category="Collision")
bool RayTraceHit(const FVector& StartLocation, const FVector& EndLocation, UPARAM(ref)FHitResult& HitResult);

f:id:PaperSloth:20180919194341p:plain

空のUFUNCION()について

エンジンコードを眺めているといくつかUFUNCTION()を見かけます。
その中でも OnRep_ で始まる関数は変数のReplicationに関わるものです。
それ以外にもBindUFunctionを使用したデリゲートで必要な場合もあります。

コードスニペットについて

本題とは離れますが、登録しておくと快適にコードが書けるので使ってください
以前にも少し紹介しています。
Git or Perforceで落としてきたエンジンのEngine/Extras/VisualStudioSnippets以下にあります
UE4 Unreal C++を書くための環境構築 - PaperSloth’s diary

f:id:PaperSloth:20180919194545g:plain

UE4 Fade処理について

環境

UE4.19.2


FadeIn, Outについて

FadeIn:画面が徐々に明るくなる演出
FadeOut:画面が徐々に暗くなる演出

Level切替時やカットシーン等色々な場面で使用されますね。



UE4での表現方法について

Widgetのアニメーションを使用して全画面表示の画像で表現する
お手軽に表現できますが、都度Widgetに埋め込むのが面倒。
別パーツとして分けてUser Widgetにした場合だとCallback関数の登録が面倒。
SoundFadeを別途組む必要がある。

参考資料
Widgetでのアニメーションの作成方法が書かれています。
UE4 Unreal Motion Graphicsを使って黒画面フェードを実装する - Let's Enjoy Unreal Engine


②CameraFade関数を使用
・Set Manual CameraFade
・Start Camera Fade関数がある
お手軽に使えるがWidgetのアニメーションと違い終了時のコールバック関数の登録がない。
また、自前のPostProcessと相性が悪い場合がある。

参考資料
StartCameraFadeの引数の詳細な情報が書かれています。
UE4 シンプルな画面のフェードイン・フェードアウト(Start Camera Fade) 凛(kagring)のUE4とUnityとQt勉強中ブログ


FunctionLibraryに登録してFade終了後のCallback関数も登録可能にする

さて、今回の本題です。

①シンプルなFade
先ずはシンプルに組んでみましょう。
簡単なFadeであればこれで十分でしょう。
f:id:PaperSloth:20180613223526p:plain

②FadeIn, Outの切り替え
続いて、FadeIn, Outを切り替えれるようにします。
IsReverseなどのFlagを用意しても良いですが
UMGで用意されている列挙型(EUMG SequencePlayMode)が名前も分かりやすいので今回はこちらを使用します。
f:id:PaperSloth:20180613224637p:plain
f:id:PaperSloth:20180613223906p:plain

③Callback関数の登録
さて、これまでは通常通りのCameraFadeでした。
次にFade終了時のEventを登録できるようにします。
下図のようにSet Timer by Eventを使用します。
f:id:PaperSloth:20180613224856p:plain
f:id:PaperSloth:20180613224232p:plain

しかし、FunctionLibraryからはSet Timer by Eventを呼び出せないため
他のBlueprintでノードを作成して、コピペします。
Event引数も通常はdelegate変数の登録ができないため、関数の入力ノードにEventピンをドラッグします。
この方法は少々ハック的なやり方でいつ動作しなくなるかは保証ができません。

④補足:Delayを使用しない理由について
MucroLibraryにしてDelayを使わない理由についてです。

先ずはMacroLibraryでDelayを使用して作った例が下図です。
Delayノードを使用することでシンプルにFade終了時のタイミングを取得できます。
f:id:PaperSloth:20180613224333p:plain

さて、使用しない理由についてですが
例えばゲーム内でスローモーションや早送りがあった場合にDelayノードだった場合
処理速度の変化の影響を受けてしまい、意図した挙動にならないことがあると思います。
そういった問題を回避するために今回はSet Timer by Eventを使用するようにしています。

参考資料
時間変化の影響を受けるノード等について書かれています。
UE4小ネタ : 制限時間の実装方法を色々と - ぼっちプログラマのメモ


まとめ

Fadeについては以上です!
Fadeはおおよそどんなゲームでも使うのではないでしょうか?

今回紹介した方法に限らずプロジェクトに合った便利機能を作っていきましょう!

UE4 Logの収集について

環境

UE4.19.1


Logファイルの収集について

UE4でよく使うUE_LOGマクロ、PrintStringノードがありますね。

UE_LOG(LogTemp, Error, TEXT("Log message"));

f:id:PaperSloth:20180422183250p:plain

これらで出力したLogはSavedファイルに保存されます。
(ProjectDirectory)/Saved/Logs/(ProjectName).log

エラー処理をした時など、ログを探したい時などに役立ててください。

UE4 カスタムビルドエンジンの起動方法

環境

Unreal Engine (Git:4.19)
Visual Studio 2017 Community
Windows 10


Editorのexeについて

エンジンビルドの方法についてはヒストリアさんのブログが参考になります。
[UE4] エンジンのソースコード取得とビルド手順のまとめ UE4.6改訂版|株式会社ヒストリア


さて、カスタムビルドのエンジンを毎回IDEから起動するとどうしても時間がかかってしまいますね。

ですが、エンジンを一度ビルドすると実行ファイルが作られます。
(EngineDirectory)/Engine/Binaries/(Platform)/UE4Editor.exe


WindowsPCだと下記のフォルダに作成されます。
(EngineDirectory)/Engine/Binaries/Win64/UE4Editor.exe

実行するとLauncherからLaunchした際と同様です。
f:id:PaperSloth:20180422182325p:plain