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 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

UE4 IDEの変更方法

環境

UE4.19.1
Visual Studio 2017 Community


IDEの変更方法について

Unreal C++IDEMacではXCode, WindowsではVisual Studioを使用することが多いと思います。

IDEの変更方法はEditor PreferencesのSource Codeから変更します。
f:id:PaperSloth:20180422174833p:plain

Visual Studio 2017 Communityをインストールしたので、この機会に変更してみました。
f:id:PaperSloth:20180422175049p:plain

因みにこの後にOpen Visual Studio 2017を選択しても
プロジェクトをVisual Studio 2015で作成していたらVisual Studio 2015が開きます。
f:id:PaperSloth:20180422175229p:plain

Refresh Visual Studio 2017 Projectを選択してソリューションを更新します。
f:id:PaperSloth:20180422175351p:plain

これでプロジェクトでVisual Studio 2017を使用出来るようになります。
Visual Stuidio Code等他のIDEを使用したい場合もここから変更出来ます。

UE4 C++でGameModeの初期化を行う方法

環境

UE4.19.1
Visual Studio 2015 Community


GameModeで登録する初期値の初期化について

ここの部分の初期化についてです。
f:id:PaperSloth:20180422161755p:plain

C++で作成したGameModeBaseだと編集できないのですが
Blueprintだと楽に編集ができますね。
ここをC++側で編集する方法について書きます。

GameModeBaseに登録されているのは下記のような処理です。

AGameModeBase::AGameModeBase(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer.DoNotCreateDefaultSubobject(TEXT("Sprite")))
{
    // 省略

    DefaultPawnClass                     = ADefaultPawn::StaticClass();
    PlayerControllerClass                = APlayerController::StaticClass();
    PlayerStateClass                     = APlayerState::StaticClass();
    GameStateClass                       = AGameStateBase::StaticClass();
    HUDClass                             = AHUD::StaticClass();
    GameSessionClass                     = AGameSession::StaticClass();
    SpectatorClass                       = ASpectatorPawn::StaticClass();
    ReplaySpectatorPlayerControllerClass = APlayerController::StaticClass();
    ServerStatReplicatorClass            = AServerStatReplicator::StaticClass();
}

例えばGameModeBaseを継承したGameModeでnullptrを設定するとNoneになります。

AExampleGameModeBase::AExampleGameModeBase()
{
    DefaultPawnClass = nullptr;
}

f:id:PaperSloth:20180422163144p:plain

継承したクラスを登録したい場合は下記のようになります。

#include "ExampleGameModeBase.h"
#include "ExampleCharacter.h"
#include "ExamplePlayerController.h"

AExampleGameModeBase::AExampleGameModeBase()
{
    DefaultPawnClass      = AExampleCharacter::StaticClass();
    PlayerControllerClass = AExamplePlayerController::StaticClass();
}

f:id:PaperSloth:20180422170729p:plain

UE4 C++で複数実行ピンの作成

環境

UE4.19.1
Visual Studio 2015 Community


概要

いくつかやり方があって、今回は一番簡単でお手軽なenumを使ったやり方を紹介します。


enumを使った関数のおさらい

先ずは下記のようなenumを定義します。

UENUM(BlueprintType)
enum class EErrorCode : uint8
{
    Success,
    Failed
};

続いてUFUNCTIONマクロを使用してBlueprintに関数を公開します。

UFUNCTION(BlueprintCallable, Category = "Example")
void ExampleEnumInput(const EErrorCode ErrorCode);

// 関数内でErrorCodeの値が変わる関数を想定
UFUNCTION(BlueprintCallable, Category = "Example")
void ExampleEnumOutput(EErrorCode& ErrorCode);

constなしの参照にすることで引数が出力ピンに変わります。
constをつけた参照の場合は引数が入力ピンになります。

Blueprintから先程の関数を呼び出すと下図のようになります。
f:id:PaperSloth:20180422143212p:plain


enumを使った複数実行ピンの作成方法

さて、ようやく本題です。
enumを使って複数の実行ピンを使用するにはUFUNCTIONのmetaに下記を追加することで実現可能です。

UFUNCTION(/*省略*/,  meta = (ExpandEnumAsExecs = "ArgumentName"))

ArgumentNameの部分は任意の引数名を入力します。
実際に使用する引数名と一致するようにします。

先程の関数に手を加えて下記のように変更しました。

UFUNCTION(BlueprintCallable, Category = "Example", meta = (ExpandEnumAsExecs = "ErrorCode"))
void ExampleEnumMultiInput(const EErrorCode ErrorCode);
UFUNCTION(BlueprintCallable, Category = "Example", meta = (ExpandEnumAsExecs = "ErrorCode"))
void ExampleEnumMultiOutput(EErrorCode& ErrorCode);

Blueprint側から呼び出すと下記のようになります。
f:id:PaperSloth:20180422144216p:plain

enumで登録した値が全て実行ピンになっていますね。
後はC++側でswitchとかで処理を分けると良さそうです。

また、enumで定義を追加するとノードも変更されます。

UENUM(BlueprintType)
enum class EErrorCode : uint8
{
    None,
    Success,
    InternalError,
    ExternalError,
    NetworkError,
    UnknownError,
};

Noneを定義した場合は実行ピンには名前が出ません。
f:id:PaperSloth:20180422152849p:plain


簡単な応用

もう少し気の利いた処理になるように関数の中身も書いてみます。

Successの時、Failedの時でそれぞれ呼び出す関数を登録します。
C++だけで処理を実装するのは直ぐにできますが
今回はC++で関数の定義をしてBlueprintでロジックを実装する形にしてみましょう。

先ずは呼び出す関数の登録を行います。

UFUNCTION(BlueprintImplementableEvent, Category = "Example")
void OnSuccess();
UFUNCTION(BlueprintImplementableEvent, Category = "Example")
void OnFailed();

成功時、失敗時のそれぞれの関数を用意しました。
BlueprintImplementableEventはC++側で定義してBlueprintで関数のロジックを実装するときに使用します。
この定義だとBlueprintで処理の記述はできますが、関数呼び出しはC++からしか呼び出せません。
Blueprintからも呼び出したい場合は、BlueprintCallableと組み合わせることで使用できます。

複数実行ピンを入力できる関数で呼び出しを行うように処理を記述します。

void AExampleActor::ExampleEnumMultiInput(const EErrorCode ErrorCode)
{
    switch (ErrorCode)
    {
        case EErrorCode::Success:
            OnSuccess();
            break;
        case EErrorCode::Failed:
            OnFailed();
            break;
    }
}

これでBlueprint側で処理の登録と呼び出しを行ってみましょう。
下図のように組むとSuccessに実行ピンを繋ぐとOnSuccessが呼ばれ
Failedに実行ピンを繋ぐとOnFailedが呼びだされます。
f:id:PaperSloth:20180422150809p:plain

こういった処理を書く場合はDelegateで登録することが多いですが
今回は複数実行ピンを使用したイメージとして用意してみました。


また、余談ですがMultiOutput関数は
下図のようにOutputをSwitch分岐させるのと同様の処理になります。
ですが、C++側で何か処理を加えたい場合に役立ちますし、ノードもスッキリするため
ExpandEnumAsExecs を積極的に使用した方が良いでしょう。
f:id:PaperSloth:20180422151304p:plain

UE4 SpawnActorDeferredについて

環境

UE4.19.0
Visual Studio Community 2015

SpawnActorについて

SpawnActorを呼び出すにはWorld, 生成位置、回転情報、名前や所有者の登録等のオプションが必要になります。

#include "Engine/World.h"
#include "ExampleActor.h"

void AExampleGameMode::BeginPlay()
{
    Super::BeginPlay();

    auto const World = GetWorld();
    const FTransform SpawnTransform = FTransform::Identity;
    FActorSpawnParameters parameters;
    auto const exampleActor = World->SpawnActor<AExampleActor>(AExampleActor::StaticClass(), SpawnTransform, parameters);
}

基本的にはこれで問題ないのですが
BeginPlayが呼び出される前に処理を行いたい場合や値を渡したいという場合もあります。

そんな場合に役立つのがSpawnActorDeferredです。

SpawnActorDeferredについて

一先ずコードから見ていきましょう。

#include "Engine/World.h"
#include "ExampleActor.h"

void AExampleGameMode::BeginPlay()
{
    Super::BeginPlay();

    auto const World = GetWorld();
    const FTransform SpawnTransform = FTransform::Identity;
    auto const exampleActor = World->SpawnActorDeferred<AExampleActor>(AExampleActor::StaticClass(), SpawnTransform);

    // BeginPlayが呼び出される前に処理したい初期化処理等
    exampleActor->Initialize();

    // ここでBeginPlayが呼び出される
    exampleActor->FinishSpawning(SpawnTransform);
}

SpawnActorDeferredを利用する機会は何かしら作っていると何度も出てきます。
頭の片隅に入れておくと便利です。