main() blog

プログラムやゲーム、旅、愛する家族について綴っていきます。

【UE5】自作コンソール変数を作ってみよう!(C++編)

概要

コンソール変数の使用方法についてです。
コンソールコマンドから定義したコマンドで変数の値を変更することができます。
コンソール変数で使用できる型としてはint、float、bool、FStringを使用することができます。

グラフィックの設定やデバッグ用の変数などとして使用することができます。
あくまでも変数の値の変更のみを行うことができますが、
以下の様な用途として使用することができるので有効活用していただければと思います。

  • 各種デバッグ機能の切り替え
  • ゲームを起動したままで描画設定のパラメータの調整
  • ゲームを起動したまま敵の攻撃力を変更など、プランナーで調整が可能にできる

呼び出し時や変更時にコマンドして処理を行いたい場合はコンソールコマンドの実装方法で行う必要があります。
こちらについては過去記事を参考にしていただければと思います。

www.main-function.com

※本記事はC++での開発を前提としています。

動作環境

UnrealEngine 5.4.4

実装

変数定義

コンソール変数を実装するにはいくつか方法があります。

変数を定義する方法、ランタイムで追加する方法があります。
変数を定義する方法はstatic変数で定義することでエンジンの生成前に変数の生成を行うことができます。
TAutoConsoleVariable<>を使用してテンプレートで型を指定する方法と、FAutoConsoleVariableRef を使用して既存の変数を登録することも可能です。
UEのドキュメントではFAutoConsoleVariableRefは使用しないことを推奨とのことです。

以下がTAutoConsoleVariable<>での宣言のサンプルです。
参照時に変数をexternなどで参照できるようにもできますが、ヘッダーなどをインクルードする、もしくはexternをcppに記述してく必要が出てきます。
今回はstaticで宣言もしくは無名のnamespaceでローカルスコープで宣言して定義してみたいと思います。

namespace
{

TAutoConsoleVariable<int> CVarTestIntValue(
    TEXT("TestIntValue"),
    0,
    TEXT("Test int value."),
    ECVF_Default
);

TAutoConsoleVariable<float> CVarTestFloatValue(
    TEXT("TestFloatValue"),
    0.0f,
    TEXT("Test float value."),
    ECVF_Default
);

TAutoConsoleVariable<bool> CVarTestBoolValue(
    TEXT("TestBoolValue"),
    false,
    TEXT("Test bool value."),
    ECVF_Default
);

TAutoConsoleVariable<FString> CVarTestStringValue(
    TEXT("TestStringValue"),
    TEXT(""),
    TEXT("Test string value."),
    ECVF_Default
);

}

ちなみにFAutoConsoleVariableRefで宣言する場合は以下の様になります。
それぞれの変数を用意して、引数で渡すことでその変数をコマンドで変更できるようになります。

namespace
{
int32 TestIntValue = 0;
FAutoConsoleVariableRef CVarTestIntValue(
    TEXT("TestIntValue"),
    TestIntValue,
    TEXT("Test int value."),
    ECVF_Default);

float TestFloatValue = 0.0f;
FAutoConsoleVariableRef CVarTestFloatValue(
    TEXT("TestFloatValue"),
    TestFloatValue,
    TEXT("Test float value."),
    ECVF_Default);

bool TestBoolValue = false;
FAutoConsoleVariableRef CVarTestBoolValue(
    TEXT("TestBoolValue"),
    TestBoolValue,
    TEXT("Test bool value."),
    ECVF_Default);

FString TestStringValue = TEXT("");
FAutoConsoleVariableRef CVarTestStringValue(
    TEXT("TestStringValue"),
    TestStringValue,
    TEXT("Test string value."),
    ECVF_Default);
}

実行

コンソールコマンドからコマンド名が認識されていることが確認できます。

引数無しで実行した場合、現在設定されている値と変更の履歴が確認できます。
ログにはコンストラクタで設定されたことが確認できます。

引数で値を渡すことで変更することができます。

引数無しで再度確認すると値が変更されたことが確認できます。
変更履歴としてコンソールからの変更ということも確認できます。

boolの変数の場合はtrue/falseで設定できます。
True/Flaseでも設定することができるようです。
数値の場合は0だとfalse、それ以外ですとtrueが設定されるようです。

FStringの変数の場合は文字列がそのまま設定されます。

C++での値の取得と設定

少し煩雑ではありますが、コマンド名で参照して使用する方法で説明します。

コマンド名からコンソール変数を取得して操作することができます。
毎回参照するケースなどではstatic constなどで保持して参照するなどの対応を検討してください。

void hoge()
{
    IConsoleVariable* variable = IConsoleManager::Get().FindConsoleVariable(TEXT("TestIntValue"));
    if (variable)
    {
        UE_LOG(LogTemp, Log, TEXT("TestIntValue: %d"), variable->GetInt());
    }
}

ログに取得した値が出力されていることが確認できます。

同様に値の設定、変更もできます。

void hoge()
{
    IConsoleVariable* variable = IConsoleManager::Get().FindConsoleVariable(TEXT("TestIntValue"));
    if (variable)
    {
        variable->Set(1000);

        UE_LOG(LogTemp, Log, TEXT("TestIntValue: %d"), variable->GetInt());
    }
}

コンソールコマンドで変更を確認します。
履歴を確認するとコードから変更されたことも確認できます。

ReadOnly

変数の宣言時の引数のフラグでReadOnlyを指定するとコンソールコマンドからランタイムでは変更できなくなります。
C++からの設定か、iniファイルでの設定で変更することができるようです。

TAutoConsoleVariable<int> CVarTestIntValue(
    TEXT("TestIntValue"),
    0,
    TEXT("Test int value."),
    ECVF_ReadOnly
);

コンソールコマンドから変更しようとするとread onlyのメッセージが表示され、変更されていないことが確認できます。

iniファイルでの設定

DefaultEngine.iniでコンソール変数の初期値を変更してみたいと思います。
ReadOnlyの属性でも変更することが可能とのことです。

[ConsoleVariables]
TestIntValue=100

ReadOnltyの属性でも実行後にコンソールコマンドで初期値が100に変更されていることが確認できます。

参考

Unreal Engine の C++ のコンソール変数 | Unreal Engine 5.5 ドキュメンテーション | Epic Developer Community


【UE5】自動テストツールを使ってみよう!(Gauntlet準備編)

概要

UEでは自動テストのフレームワークがいくつか用意されています。
今回はGauntletと呼ばれるフレームワークについて説明したいと思います。

基本的な自動テスト環境のセットアップはこちらの記事を参照してください。
この中でもプラグインの設定でGauntletを有効にしておく必要があるので注意が必要です。

www.main-function.com

動作環境

UnrealEngine 5.4.4

プロジェクトに追加

エンジン側のGauntletのサンプルは実行はできましたが、プロジェクト側に新規で追加する方法が分かりませんでした。
プロジェクト側で新規にGauntletを追加する方法でEpicのページを参考に進めてみますが、分かりづらいのと、そのままでは対応できない部分があったのでそのあたりも含めて説明していきたいと思います。

基本的にはGauntlet用のC#のプロジェクトを追加する必要があります。

プロジェクトのGames側のフォルダで右クリックし、追加を選択します。

新しいプロジェクトの追加でクラスライブラリを選択します。
※クラスライブラリ(.NET framework)ではないので注意

以下の設定でプロジェクトを作成します。
プロジェクト名:{project}.Automation
場所:{project}\Build\Scripts\
※プロジェクト名は推奨の命名規則
※これで作成すると\Build\Scripts\以下に{project}.Automationのフォルダも作成されますが、今回はこのままでいきます

追加情報でフレームワークは.NET 6.0を選択します。
これで作成を行います。

作成を行うとClass1.csというC#のファイルが追加されているので{project}.csに変更します。

追加したプロジェクトを右クリックしてプロパティを選択します。
出力の項目の基本出力パスがbin\になっていることを確認します。

ビルドの構成マネージャーを選択します。
追加したプロジェクトの構成のドロップダウンから<編集>を選択します。

Releaseを選択して名前の変更でDevelopmentに変更します。

プロジェクトのコンテキストをDevelopmentに変更しておきます。

  • AutomationScripts.Automation
  • AutomationUtils.Automation
  • EpicGames.Build
  • EpicGames.Core
  • Gauntlet.Automation

Gauntletの自動テストのソースを追加してみます。
Epicのページを元に最小限の呼び出しを記述してみます。

using AutomationTool;

namespace TestProject.Automation
{
    // BuildCommand はすべてのコマンドの基本クラスです。
    public class SampleCommand : BuildCommand
    {
        public override void ExecuteBuild()
        {
            LogInformation("Gauntlet TestProject.Automation : SampleCommand.ExecuteBuild()");
        }
    }
}

LogInformationが非推奨となっているので、これを解消する必要があります。

右クリックのNuGetの管理を開きます。

Microsoft.CSharpをインストールします。

using AutomationTool;
using Microsoft.Extensions.Logging;

namespace TestProject.Automation
{
    // BuildCommand はすべてのコマンドの基本クラスです。
    public class SampleCommand : BuildCommand
    {
        public override void ExecuteBuild()
        {
            Logger.LogInformation("Gauntlet TestProject.Automation : SampleCommand.ExecuteBuild()");
        }
    }
}

コマンドラインから実行します。
この際、-scriptdirでプロジェクトのディレクトリを指定する必要があるので注意が必要です。

RunUAT.bat SampleCommand -scriptdir=d:\project\TestProject\Build\Scripts\

追加したログが出力されていることが確認できます。

Running AutomationTool...
Using bundled DotNet SDK version: 6.0.302
Starting AutomationTool...
Parsing command line: SampleCommand -scriptdir=d:\project\TestProject\Build\Scripts\
Initializing script modules...
Building 32 projects (see Log 'Engine/Programs/AutomationTool/Saved/Logs/Log.txt' for more details)
 Restore...
 Build...
Build projects time: 38.07 s
Total script module initialization time: 42.14 s.
Executing commands...
Gauntlet TestProject.Automation : SampleCommand.ExecuteBuild()
BUILD SUCCESSFUL
AutomationTool executed for 0h 0m 44s
AutomationTool exiting with ExitCode=0 (Success)

これでGautletの自動テストの処理が呼び出せるようになりました。
後はテストの処理などを実装して呼び出しを行うことでGauntletの環境でも自動テストが行えるようになると思います。

参考

dev.epicgames.com


【UE5】ソフトウェアカーソルでマウスカーソルを差し替えてみよう!

概要

UEで表示されるマウスカーソルを別の画像に差し替えてみたいと思います。
タイトルによってはWindowsの標準のマウスカーソルではなく、ゲーム側のデザインに差し替えたり、他のプラットフォームなどでマウス表示が必要な場合などに使用できます。

動作環境

UnrealEngine 5.4.4

画像の用意

今回はフリーの素材をトリミングしてマウスカーソルを用意します。
読み込ませてテクスチャアセットを作成しておきます。

ウィジットの作成

マウスカーソルのウィジットの作成を行います。
追加からユーザーインタフェイス → ウィジットブループリントを選択します。

親クラスにユーザーウィジットを選択して作成します。

パレットからキャンパスパネルを選択して追加します。

次に画像を選択して、先ほど追加したキャンパスパネルの子として追加します。

画像のプロパティのアピアランスのBrushのImageにカーソルの画像を追加します。

位置とサイズを調整します。

WBP_Cursorとして保存しておきます。

プロジェクト設定

プロジェクト設定のエンジン ユーザーインターフェイスのソフトウェアカーソルの項目で先ほど作成したWBP_Cursorを指定します。

マウスカーソルが差し替わっていることが確認できます。

参考

unreal-engine-tech.arsdiary.com


【UE5】自動テストツールを使ってみよう!

概要

UEでは自動テストを行う環境、ツールが提供されています。

たとえば

  • アセットの設定などをチェックする
  • 各レベルの読み込みをチェックする
  • キャラクターの読み込み、アクションのチェックをする
  • ゲームプレイ中のパフォーマンステスト

などのテストが考えらますが、これらのテストを手動で行うのにはコストがかかってしまいます。
ですので、テストの自動化が行えるものは自動化していくことで人手を使用せずともテストを行うことできるようになります。

テストをする内容についてはもちろんプロジェクト側で実装する必要が出てきますが、自動テストを管理、実行するためのツールや、実装のためのフレームワークなどが用意されています。
これらのテストを自動テストして用意することでUEのエディタ上やコマンドラインなどから実行することが可能となります。
最終的にはCIに組み込んでテストできるような環境の構築を目指していきたいと思います。

UEではテストを記述する方法をいくつか提供しています。
他にもありそうですが使用されているものと思われるものをピックアップしておきます。
※Automation Dirverは現在は積極的な開発は行われていないとのことです

  • Automation Testing
  • Automation Spec
  • Automation Driver
  • Guntlet Automation Framework

今回は自動テストの使用方法と、基本的な機能と思われるAutomation Testingでのテスト方法について説明します。

UEの自動テストの機能を使用しなくてもプロジェクトで独自のテスト環境の構築も検討できると思いますが、まずはUEで提供されている機能について確認してみたいと思います。

動作環境

UnrealEngine 5.4.4

自動テストの有効化

自動テストは以前はエンジンに組み込まれていたようですが、UE5からはプラグインとして提供されているようです。
デフォルトの状態ですと自動テストの項目がツールに登録されていない状態となっています。

自動テストに関するプラグインもデフォルトの状態だと有効になっていません。

まずは自動テストに関するプラグインを有効にします。
とりあえず以下のプラグインを有効にしてみます。

  • Automation Driver Tests
  • Code Quality Unreal Test Plugin
  • Functional Testing Editor
  • Gauntlet
  • RHI Tests
  • Runtime Tests

※実際はFunctional Testing Editorを有効にすることでツールにテスト自動化が追加されるようです
※他の機能も必要になると思われるので一旦上記のプラグインを有効にしておきます

再起動を求められるのでエディタを再起動すると「プラグインが見つからないのダイアログ」が表示されるので再ビルドします。
ビルド後に起動してプラグインが有効になっていることを確認します。

[ツール]に[テスト自動化]が追加されていることを確認します。

セッションフロントエンドに"オートメーション"と"画面比較"が追加されていることを確認します。

エンジン側で用意されているテスト項目が確認できます。
テストしたい項目にチェックを入れて再生ボタンを押すことでテストが実行されます。

テストの追加方法

プロジェクト側で独自のテストを追加する方法についてです。

C++実装

C++で実装する際に以下のクラスが基底クラスとなっています。

FAutomationTestBase  
IAutomationLatentCommand

上記のクラスを継承して直接クラスを定義しなくても、以下のマクロでクラス定義が行えるようになっています。

IMPLEMENT_SIMPLE_AUTOMATION_TEST( TClass, PrettyName, TFlags )
IMPLEMENT_COMPLEX_AUTOMATION_TEST( TClass, PrettyName, TFlags )
DEFINE_LATENT_AUTOMATION_COMMAND(CommandName)
簡易テスト(SimpleTest

IMPLEMENT_SIMPLE_AUTOMATION_TESTのマクロを使用してクラスを定義します。
マクロの引数でクラス名、テスト名、フラグを指定します。
RunTestの関数をオーバーライドする必要があります。
この返却値がテスト結果となります。
trueが成功で、falseで失敗となります。

IMPLEMENT_SIMPLE_AUTOMATION_TEST(FHogeSimpleTest, "HogeTest.HogeSimpleTest", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
bool FHogeSimpleTest::RunTest(const FString& Parameters)
{
    UE_LOG(LogTemp, Log, TEXT("FHogeSimpleTest::RunTest()"));

    return true;
}

上記をソースのどこかに記述してビルドすることで、自動テストの項目に追加されます。
HogeTest.HogeSimpleTestが追加されていることが確認できます。

この状態でテストの実行を確認することができます。
返却値でtrueを返しているのでテストが成功となります。

falseを返すことで失敗となることが確認できます。

ここにテストコードを書いてtrue/falseを返すことで成功/失敗の結果を返すことができようになります。

複合テスト(ComplexTest)

複数のテストを行う場合に使用します。
IMPLEMENT_COMPLEX_AUTOMATION_TESTのマクロを使用してクラスを定義します。
GetTestsとRunTestをオーバーライドする必要があります。

GetTestsの関数でテスト名とテストに渡すコマンド(文字列)を設定します。
以下のような記述で実行するとRunTestが複数回実行されることが確認できます。

IMPLEMENT_COMPLEX_AUTOMATION_TEST(FHogeComplexTest, "HogeTest.HogeComplexTest", EAutomationTestFlags::EditorContext | EAutomationTestFlags::EngineFilter)
void FHogeComplexTest::GetTests(TArray<FString>& OutBeautifiedNames, TArray<FString>& OutTestCommands) const
{
    UE_LOG(LogTemp, Log, TEXT("FHogeComplexTest::GetTests()"));

    // テスト名とレベル名の文字列を登録.
    OutBeautifiedNames.Add("HogeTestMap01");
    OutTestCommands.Add("LV_TestMap01");

    OutBeautifiedNames.Add("HogeTestMap02");
    OutTestCommands.Add("LV_TestMap02");

    OutBeautifiedNames.Add("HogeTestMap03");
    OutTestCommands.Add("LV_TestMap03");
}

bool FHogeComplexTest::RunTest(const FString& Parameters)
{
    UE_LOG(LogTemp, Log, TEXT("FHogeComplexTest::RunTest() : [%s]"), *Parameters);

    // パラメータで受け取ったレベルの読み込み.
    //ADD_LATENT_AUTOMATION_COMMAND(FLoadGameMapCommand(Parameters));

    return true;
}

オートメンションの項目に追加した各項目のテストが表示されていることが確認できます。

コマンド(LatentCommand)

RunTestの関数内でADD_LATENT_AUTOMATION_COMMANDを使用してコマンドを登録することで順次処理を行うことができようになります。
コマンドはIAutomationLatentCommandのインターフェイスクラスを継承して作成します。

以下はエンジン側で用意されているコマンドの一部抜粋です。
AutomationCommon.hで定義されているので実装の参考になると思います。

// Wait for the given amount of time
FEngineWaitLatentCommand

// Execute command string
FExecStringLatentCommand

// Write a string to editor automation tests log
FEditorAutomationLogCommand

// Latent command to load a map in game
FLoadGameMapCommand

// Latent command to wait for map to complete loading
FWaitForMapToLoadCommand

// Latent command to wait for map to complete loading
FWaitForSpecifiedMapToLoadCommand

// Waits for shaders to finish compiling before moving on to the next thing.
FWaitForShadersToFinishCompilingInGame

例えば、以下の様な記述で3秒待ってからスクリーンショットを撮るコンソールコマンドを実行して、3秒待ってからLog出力を行う処理を実装することができます。
コマンドの登録のみなのでRunTestの関数自体はすぐに抜けてしまいますが、その後で登録されたコマンドが処理され、実行されていきます。
すべてのコマンドが完了した時点でテストが完了となります。

IMPLEMENT_SIMPLE_AUTOMATION_TEST(FHogeSimpleTest, "HogeTest.HogeSimpleTest", EAutomationTestFlags::EditorContext | EAutomationTestFlags::ClientContext | EAutomationTestFlags::EngineFilter)
bool FHogeSimpleTest::RunTest(const FString& Parameters)
{
    // Log出力のコマンドを登録.
    ADD_LATENT_AUTOMATION_COMMAND(FEditorAutomationLogCommand(TEXT("FHogeSimpleTest::RunTest() : start")));

    // 3秒待つコマンドを登録.
    ADD_LATENT_AUTOMATION_COMMAND(FEngineWaitLatentCommand(3.0f));

    // スクリーンショットを撮るコンソールコマンドのコマンドを登録.
    ADD_LATENT_AUTOMATION_COMMAND(FExecStringLatentCommand(TEXT("shot")));

    // 3秒待つコマンドを登録.
    ADD_LATENT_AUTOMATION_COMMAND(FEngineWaitLatentCommand(3.0f));

    // Log出力のコマンドを登録.
    ADD_LATENT_AUTOMATION_COMMAND(FEditorAutomationLogCommand(TEXT("FHogeSimpleTest::RunTest() : finish")));

    return true;
}

独自のコマンドの追加方法

DEFINE_LATENT_AUTOMATION_COMMANDのマクロを使用してプロジェクト側でコマンドを定義することができます。
Update関数をオーバーライドする必要があります。
返却値でtrueを返すと関数は終了します。
falseを返すとUpdate関数は継続されて次フレームで呼ばれます。

DEFINE_LATENT_AUTOMATION_COMMAND(FHogeLatentCommand);
bool FHogeLatentCommand::Update()
{
    UE_LOG(LogTemp, Log, TEXT("FHogeLatentCommand::Update()"));

    return true;
}

定義したコマンドは同様にADD_LATENT_AUTOMATION_COMMANDで追加できます。

IMPLEMENT_SIMPLE_AUTOMATION_TEST(FHogeSimpleTest, "HogeTest.HogeSimpleTest", EAutomationTestFlags::EditorContext | EAutomationTestFlags::ClientContext | EAutomationTestFlags::EngineFilter)
bool FHogeSimpleTest::RunTest(const FString& Parameters)
{
    // 追加したコマンドを登録.
    ADD_LATENT_AUTOMATION_COMMAND(FHogeLatentCommand());

    return true;
}

DEFINE_LATENT_AUTOMATION_COMMAND_ONE_PARAMETERを使用することでクラスに変数を持たせることできます。
マクロの引数で変数の型と変数名を指定することで関数内で使用することできます。

DEFINE_LATENT_AUTOMATION_COMMAND_ONE_PARAMETER(FHogeLatentCommand2, int, count);
bool FHogeLatentCommand2::Update()
{
    UE_LOG(LogTemp, Log, TEXT("FHogeLatentCommand2::Update() : [%d]"), count);

    if (count < 20)
    {
        // falseを返すと次のフレームでもUpdate()が呼ばれる.
        count++;
        return false;
    }

    return true;
}

また、コマンド登録時に変数の初期値も指定することができます。

IMPLEMENT_SIMPLE_AUTOMATION_TEST(FHogeSimpleTest, "HogeTest.HogeSimpleTest", EAutomationTestFlags::EditorContext | EAutomationTestFlags::ClientContext | EAutomationTestFlags::EngineFilter)
bool FHogeSimpleTest::RunTest(const FString& Parameters)
{
    // 追加したコマンドを登録.
    ADD_LATENT_AUTOMATION_COMMAND(FHogeLatentCommand2(0));

    return true;
}

パッケージ環境での自動テストの実行方法

パッケージ(もしくはステージングビルド)環境でコマンドラインから自動テストを実行する方法です。
パッケージ環境で実行する場合、IMPLEMENT_SIMPLE_AUTOMATION_TESTのフラグの指定でEAutomationTestFlags::ClientContextが必要になるので注意してください。

IMPLEMENT_SIMPLE_AUTOMATION_TEST(FHogeSimpleTest, "HogeTest.HogeSimpleTest", EAutomationTestFlags::EditorContext | EAutomationTestFlags::ClientContext | EAutomationTestFlags::EngineFilter)
bool FHogeSimpleTest::RunTest(const FString& Parameters)
{
    UE_LOG(LogTemp, Log, TEXT("FHogeSimpleTest::RunTest()"));

    return true;
}

この状態でビルドを行い、パッケージを作成します。
コマンドラインから実行ファイルの引数のオプションの-ExecCmdsで"Automation RunTest"を指定し、先ほどのテスト名を指定することで自動テストを実行することが可能です。

TestProject.exe -ExecCmds="Automation RunTests HogeTest.HogeSimpleTest;Quit" -log=outlog.txt

基本的な使用方法、テストの追加方法についてでした。
他の機能については引き続き調査していきたいと思います。

参考

historia.co.jp

historia.co.jp

dev.epicgames.com


【UE5】StringTableを使ってみよう!(C++編)

概要

テキストデータを扱う場合、ローカライズなども考慮する必要があります。
DataTableで作成することも考えましたが、ローカライズを想定したStringTableというものがあるのでそちらを試してみたいと思います。
合わせてLocalizationDashboardも試してみたいと思います。

動作環境

UnrealEngine 5.4.4

実装

データの作成

コンテンツドロワーの "+追加" から "その他" → "ストリングテーブル" を選択し、新規に作成します。

下部のキー、ソースストリングに入力してデータを追加します。
追加した後でキーの変更はできないようです。
ソースストリングの変更は可能です。

CSVへエクスポート

csvにエクスポートしてみます。

Key,SourceString
EnemyName001,BUSHWACKER
EnemyName000,ROUGE

CSVからのインポート

csvからインポートしてみます。
試しに以下の様に1行追加してみます。

Key,SourceString
EnemyName001,BUSHWACKER
EnemyName000,ROUGE
EnemyName002,HIGHWAYMAN

CSVからインポートを選択します。

先ほどエクスポートしたファイルを選択してインポートします。

追加された行がインポートされていることが確認できます。

C++で参照する方法

この段階で文字列の取得を試してみます。

void Hoge()
{
    FText LocalizedText;

    // StringTable名とキーを指定してテキストを取得.
    LocalizedText = LOCTABLE("/Game/Game/StringTable/ST_Enemy.ST_Enemy", "EnemyName000");

    // 取得したテキストをログに表示.
    UE_LOG(LogTemp, Log, TEXT("Localized Text: %s"), *LocalizedText.ToString());
}

とりあえず文字列が取得できて、ログに出力されていることが確認できます。

ただ、指定したテーブルを読み込んではいないので、どこかで読み込まれていると思われます。
マクロの実装を確認したところ、引数でEStringTableLoadingPolicy::FindOrLoadが指定されているので、他で読み込まれていない場合は参照した段階でテーブルの読み込みが行われていると思われます。

別途、テーブルの読み込みについては確認が必要になりそうです。

LocalizationDashboard

ローカライゼーションダッシュボードはカルチャーを追加することで、そのカルチャー毎の翻訳データを作成、管理するための機能です。

"ツール" → "ローカライゼーションダッシュボード" から開くことができます。

"パッケージから収集" にチェックを入れ、Include Path Wildcards で参照するStringTableのパスを指定します。

新規カルチャーの追加を行います。

参考資料によると使用しない言語をデフォルトにしておいた方が無難とのことなので、とりあえず英語(アイルランド)を選択してみます。

ついでに日本語も追加しておきます。

この段階でテキストの収集を実行します。

これでデフォルト言語のワード数が更新されます。

追加、更新があった場合はこの操作でデフォルト言語の更新を行う必要があるようです。

個別の言語を編集する場合はそれぞれの言語の編集を押します。

試しに日本語の翻訳を編集してみます。

未翻訳のタブで編集したい項目のTranslation側をクリックします。
翻訳(日本語)を入力します。

ダッシュボードから言語ごとにコンパイルを実行します。

再度、テキストを収集を実行することで翻訳データが反映されます。

エディタ上で確認する場合はエディタの環境設定の一般の地域&言語のゲームのプレビュー言語を日本語にすることで日本語を確認することができます。

同じキーで参照して日本語訳が適用されていることが確認できました。

要検討

ゲーム側からはテーブルや言語に関係なく、Keyで文字列が取得できれば良いはずだが、テーブルとKeyを対で指定する必要があるがどのように実装するのが良さそうか?

LocalizationDashboardはテクスチャやサウンドなどのアセットも切り替えることができるとのこと。
ゲームによってはテキストとボイスそれぞれで言語切り替えが行えるタイトルなどもあるが、その場合はどのように対応すれば良いかなどまだ調査/検証が必要そうではある。

参考

historia.co.jp

qiita.com

docswell.com


【UE5】プラグインを作成してみよう!

概要

UE4プラグインは機能拡張のためにモジュールを追加することができます。
プロジェクト側でプラグインとしてモジュールを分けることはプロジェクト側(ゲーム側)依存を減らし、そのモジュールの独立性を高めることができます。
また、他のプロジェクトへプラグインとして提供することも可能になります。

※本記事はC++での開発を前提としています。

動作環境

UnrealEngine 5.4.4

作成手順

"編集" → "プラグイン" を選択してプラグインブラウザタブを開きます。

"+追加" ボタンをクリックしてプラグインリエーターダイアログを開きます。

作成するプラグインの一覧が表示されます。

作成できるプラグインは以下のものがあるようです。

今回は空白(blank)でプラグインを作成してみます。
空白を選択してプラグイン名を TestBlank とします。
右下の "プラグイン作成" をクリックします。

少し時間がかかりますが、コード生成やプロジェクト生成などのダイアログが表示されます。

VisualStudioのプロジェクトに作成したプラグインが追加されます。

ビルド後、エディタを起動し "編集" → "プラグイン" からプラグインブラウザタブを開き、追加したプラグインが認識されていることを確認します。

プラグインの項目の編集をクリックするとプロパティが開きます。
こちらでバージョンや説明、カテゴリなどの編集が行えます。

upluginファイルでも同様に編集が行えます。

これで空のプラグインが作成できました。

プラグインの実装を行った後で、プロジェクト(ゲーム側)からこのプラグインを使用する場合は、{Project}.Build.csの方に依存するモジュールを追記する必要があります。

参考

www.lancarse.co.jp

zenn.dev


【UE5】C++でクラスを追加する際にClass Typeを指定しない場合のインクルードパスの指定について

概要

C++のクラスを追加する際にUEの推奨の場合、Class TypeでPublic、Privateを指定する必要があります。
Class Typeを指定した場合、Public、Privateのフォルダが作成され、ヘッダーファイル、ソースファイルがそれぞれのフォルダに分けられます。
人によってはフォルダを分けられるのは分かりずらい、煩雑になるということで同じフォルダ内でヘッダーファイル、ソースファイルを配置したいというケースも出てくると思います。
その場合のインクルードパスの指定についてです。

※本記事はC++での開発を前提としています。

動作環境

UnrealEngine 5.4.4

Class Typeを指定した場合

C++のソースを追加する際にClass Typeを指定すると思います。
これはUEが推奨している方法でプロジェクト以下にPublic、Privateのフォルダ作成され、それぞれのフォルダ以下にcppやhが配置されます。
Publicの場合はヘッダーファイル(.h)はPublicに配置され、ソースファイル(.cpp)はPrivateに配置されます。
Privateの場合はヘッダーファイル、ソースファイルともにPrivate以下に配置されます。
これはモジュールとして外部に公開するものかどうかで指定するものと思われます。
Privateにした場合はモジュール内のみでの参照が可能となります。

新規にプロジェクトを作成した直後のvcxprojを確認すると、まだインクルードパスにPublic、Privateなどは追加されていません。
TestProjectというプロジェクトを作成した場合、vcxprojファイルは以下のフォルダに作成されます。

TestProject\Intermediate\ProjectFiles\TestProject.vcsproj

プロジェクトのSource/{Project}以下にPublic、Privateのフォルダが存在していれば、ソリューション生成(Generate VisualStudio project files)で生成されるvcxprojのもしくは<ClCompile_AdditionalIncludeDirectories>に....\Source{Project}\Public、....\Source{Project}\Privateが追加されます。
TestProjectというプロジェクトで、Class Typeを指定してソリューションの生成を行った場合、vcxprojには....\Source\TestProject\Public、....\Source\TestProject\Privateが追加されます。
これによりHoge/AHogeActor.cppなどを追加した際も以下のインクルードで該当ファイルが参照できるようになっています。

#include "Hoge/AHogeActor.h"

Class Typeを指定しない場合

個人やプロジェクトのルールなどでPublic、Privateに分けたくないなどの理由でPublic、Privateのフォルダを入れずにそのままヘッダーファイル、ソースファイルを同じフォルダ(階層)にするケースがあると思います。
C++でクラスを作成する際にClass Typeをしないで作成した場合に指定したフォルダ以下にヘッダーファイル、ソースファイルが追加されます。
この場合にC++で新規のクラスを追加した場合、ソースファイル(cpp)のビルドでヘッダファイルの参照が正しく行われずビルドエラーとなります。

#include "Hoge/AHogeActor.h" // ←ビルドエラー

その場合、vcxprojの方にはインクルードパスの設定が行われないため、そのままであれば{Project}のパスを追加、もしくは同フォルダ以内のヘッダーファイルであればそのフォルダのパスを削除する必要が出てきます。

#include "Hoge/AHogeActor.h" // ←ビルドエラー

 ↓
#include "AHogeActor.h"
もしくは
#include "TestProject/Hoge/AHogeActor.h"

これはUEが自動生成するソースがClass Typeを指定しないことで想定されていないインクルードパスの構成になってしまうためです。

Class Typeを指定しないケースでもClass Typeを指定した場合と同様のインクルードパスで参照できるようにしたい場合、プロジェクトのBuild.csにインクルードパスを指定することで対応できます。
TestProjectの場合、TestProject/Source/TestProject/以下にTestProject.Build.csというファイルがあるのでPublicIncludePathsでインクルードパスを追加することができます。

// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;

public class TestProject: ModuleRules
{
    public TestProject(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "EnhancedInput" });

        PublicIncludePaths.Add(ModuleDirectory);
    }
}

ModuleDirectoryでプロジェクトの相対パスが取得できるようなので、そのパスをPublicIncludePathsで追加します。
追加した後で再度ソリューションファイルを生成します。
vcsprojのもしくは<ClCompile_AdditionalIncludeDirectories>に....\Source\TestProjectが追加されていることが確認できます。

この状態であればClass Typeを指定しない状態で新規に追加してもビルドエラーにはならず、Class Typeを指定した場合と同様のパスでヘッダーファイルを参照できるようになります。

Class Typeを指定しない場合はこのあたりに注意しておく必要が出てくると思われます。

参考

historia.co.jp