概要
ゲーム開発していると、デバッグメニューを作成したりデバッグ用のユーティリティを作成したりしていきます。
最終的にビルドしてパッケージを作るときに、そういったソースコードを含めたくはないです。
純粋なC++でフルスクラッチしていれば、ビルドコンフィギュレーションを使用して
#if DEBUG ~ #endif
でクラスごと囲み定義を無くすことで対応します。
がUnrealC++の場合、UCLASSがあったりUFUNCTIONがあったりすると #if ディレクティブ で囲むことができません。(正確には #if WITH_EDITORONLY_DATA のみ囲めるといった制限があります。)
このようなときどのような対応をすることができるのかを調べたメモです。
検証バージョン
UE5.2 preview2
プラグイン化
UEでは機能ごとにプラグインを作成することができます。
https://docs.unrealengine.com/5.1/ja/plugins-in-unreal-engine/
プラグイン化することでデバッグ用のソースコード一式をゲームプロジェクトから分離します。
コードの書き方
プラグイン化しているので、#if UE_BUILD_DEBUG ~ #endif で囲むなどする必要がありません。
ビルドコンフィギュレーション毎にプラグインを使うか使わないかを Build.cs で指定することになります。
/**
* UCLASSもそのまま書く
*/
UCLASS()
class DEBUGMENURUNTIME_API UDebugMenuRootObject : public UObject
{
GENERATED_BODY()
};
ゲームプロジェクト側からの利用
プラグインを作成しデバッグ用の処理を書いていきました。
ゲームプロジェクト側からプラグインの処理を呼び出さなければなりません。
ゲームプロジェクト側の Build.cs にプラグインの依存関係を記述します。
DebugとDevelopmentビルドで有効にしようとするなら以下のように記述します。
using UnrealBuildTool;
public class MyProject : ModuleRules
{
public MyProject(ReadOnlyTargetRules Target) : base(Target)
{
bUseUnity = true;
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.Add("MyProject");
PublicDependencyModuleNames.AddRange(new string[]
{
"Core",
"CoreUObject",
"Engine",
"InputCore",
"HeadMountedDisplay",
"EnhancedInput",
"GameplayAbilities",
"GameplayTags",
"GameplayTasks",
});
if (Target.Configuration == UnrealTargetConfiguration.Debug ||
Target.Configuration == UnrealTargetConfiguration.Development)
{
PublicDependencyModuleNames.Add("DebugMenuRuntime");
}
}
}
デバッグ用の処理を呼び出すゲームプロジェクト側は #ifディレクティブ を使って以下のように書きます
#if UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT
これでパッケージビルドを行うとデバッグ用のソースコードは DebugとDevelopmentの時はコンパイルされ、Shippingのときにはコンパイルされません。
懸念
デバッグ専用処理はプラグイン化してコンパイル対象から外すことはできましたが、ゲームプロジェクト側のデバッグ専用関数はどうするべきでしょうか。
プレイヤーキャラクターを無敵にするなどゲームプロジェクト側の処理と関連深い処理はプラグイン側に定義することが難しい場合もあります。
定義はあっても呼び出しがなければDEADCODEとして消えてほしいですが、UnrealC++でどうなるかは確認していません。
モジュールを使用
モジュールを使用しても同様にコンパイルされない動作になりました。
https://docs.unrealengine.com/5.1/ja/how-to-make-a-gameplay-module-in-unreal-engine/
プラグインとして他のプロジェクトにも使えるようにする必要がないならモジュール化で良さそうです