LoginSignup
9
11

More than 1 year has passed since last update.

Visual StudioのImmediate ViewでUnreal Engineをデバッグする

Last updated at Posted at 2022-06-30

1. 概要

 本記事ではVisual Studio の Immediate Window を利用してUnreal Engineに生かすためのヒントを記載しています。この内容は公式ドキュメント、Visual Studio のヒントとコツの一部を補足するもので、以下のような事ができるようになります。

  • エンジンクラスや自作したカスタムクラスで定義された変数の素早いウオッチ、書き換え
  • Visual Studioでブレーク中に各クラスのモジュールを実行

 これらの操作がVisual Studioで完結するなどによって、コンソール開発においても反復移動を減らすことができます。

2. 使い方

 デバッグを行う方法は以下の流れになります。

  1. プロジェクトを起動してImmediate Window を開く
  2. 任意の箇所でブレークする
  3. Immediate Window にコマンドや変数を入力する

1. プロジェクトを起動してImmediate Window を開く
 プロジェクトを起動してVisual StudioでImmediate Windowを開きます。プロジェクトはVisual Studioから起動しても、動作中のプロジェクトにVisual Studioからアタッチする方法でもどちらでも良いです。Immediate Windowは、[Debug]->[Windows]->[Immediate] から開くことができます。
2022-06-27_12h05_33.png

2. 任意の箇所でブレークする
 Immediate Windowはブレーク中にコマンドを受け付ける事ができるため、任意の箇所にブレークポイントを追加してプロジェクトをブレークした状態にします。

2022-06-27_12h17_35.png

3. Immediate Window にコマンドや変数を入力する
 Immediate Windowにコマンドや変数を入力したりします。一例として挙げられる内容としては、公式ドキュメント、Visual Studio のヒントとコツにも記載されている内容が参考になります。こちら2022/06/30 現在ではコマンドの内容がUE4のものとなっているため、UE5で利用する場合には以下のように置き換えてください。

コマンド 説明
{,,UnrealEditor-Core}::PrintScriptCallstack() ブループリント コールスタック
{,,UnrealEditor-Core}::GFrameNumber 現在のフレーム数 (ブレークポイント条件としても機能します)
{,,UnrealEditor-Core}::GPlayInEditorID PIE ID (マルチプレイヤーの場合に便利であり、ブレークポイント条件としても機能します)
UnrealEditor-Engine!GPlayInEditorContextString PIE ウィンドウ名 (マルチプレイヤーの場合に便利です)

 コマンドの入力した例を以下に示します。例えば一番上の「ブループリント コールスタック」を出力したい場合は、コンソール画面に以下の内容を入力します。

コマンド入力:{,,UnrealEditor-Core}::PrintScriptCallstack()
{,,UnrealEditor-Core}::PrintScriptCallstack()

 そうするとコールバックとして以下のような出力が行われます。これはブレークの過程で実行されたブループリントのコールスタックを示しています。「レベルブループリントからアクター(BP_TestActor)をスポーンした時に、スポーンされた親のC++クラスコンストラクタでブレークを張っている」状況であるためこのようなコールスタックとなっています。

コマンド入力:{,,UnrealEditor-Core}::PrintScriptCallstack()
{,,UnrealEditor-Core}::PrintScriptCallstack()
[2022.06.27-03.16.50:579][162]LogOutputDevice: Warning: 

Script Stack (4 frames):
BP_TestActor_C.ExecuteUbergraph_BP_TestActor
BP_TestActor_C.SpawnActor
NewMap_C.ExecuteUbergraph_NewMap
NewMap_C.InpActEvt_One_K2Node_InputKeyEvent_0

<void>

 他にもコマンドが存在していますが、キーとなっているのが {,,UnrealEditor-Core} の部分で、これは実行ファイル名(UnrealEditor)とモジュール名(Core)から構成されており、これらを応用することで様々なことができるようになります。クラスの前の部分の組み合わせについては、Visual Studioのコールスタックを見ると以下のように呼ばれたモジュールと関数が載っているため、この内容を参考にすることもできます。

UnrealEditor-TP_500.dll!AMyActor::IncrementVal()
UnrealEditor-CoreUObject.dll!UFunction::Invoke(UObject * Obj, FFrame & Stack, void * const Z_Param__Result)
UnrealEditor-CoreUObject.dll!UObject::CallFunction(FFrame & Stack, void * const Z_Param__Result, UFunction * Function)

 その他のコマンドについても実行した内容と出力結果を見てみましょう。このコマンドではブレークしたタイミングでのフレーム番号を出力します。

コマンド入力:{,,UnrealEditor-Core}::GFrameNumber
{,,UnrealEditor-Core}::GFrameNumber
13163

 このコマンドではマルチプレイ実行時など複数窓で実行時に割り当てられるIDを出力することができます。どちらのIDで現在実行しているか、どちらのIDでブレークしているかといったことが分かります。以下は2人のマルチプレイ時に各クライアントからコマンドを実行した結果を載せています。

コマンド入力:{,,UnrealEditor-Core}::GPlayInEditorID
{,,UnrealEditor-Core}::GPlayInEditorID
0

{,,UnrealEditor-Core}::GPlayInEditorID
1

 このコマンドではどのクライアントでプレイしているかが分かります。こちらもクライアント3とクライアント1で各コマンドを実行した結果を載せています。

コマンド入力:UnrealEditor-Engine!GPlayInEditorContextString
UnrealEditor-Engine!GPlayInEditorContextString
L"Client 3"
    Data: Num=9 L"Client 3\0"
UnrealEditor-Engine!GPlayInEditorContextString
L"Client 1"
    Data: Num=9 L"Client 1\0"

3. 応用

 上記で記載したように固定部分は実行ファイル名とモジュール名の構成になっているため、この部分を変更すれば他のパラメータや関数も実行できることが分かります。ドキュメントに記載されている部分以外の箇所を見てみましょう。

 以下では GFrameCounterRenderThread のカウンタは GFrameCounter よりも遅れている事が確認できます。

{,,UnrealEditor-Core}::GFrameCounter
17031
{,,UnrealEditor-Core}::GFrameCounterRenderThread
17030

 自分で作成したクラスの変数や内容についても見てみましょう。例えば以下のようなクラスや変数を定義した場合、

MyActor.h
UCLASS()
class MYPROJECT_API AMyActor : public AActor
{
public:
	int32 IntVal = 1;
	bool BoolVal;
	float FloatVal = 1.0f;
}
MyActor.cpp
void AMyActor::TestFunc()
{
	UE_LOG(LogTemp, Warning, TEXT("test"));
}

 ブレーク中に以下のように入力すると各変数や関数の実行、値の上書きができます。

UnrealEditor-MyProject!AMyActor::IntVal
1

UnrealEditor-MyProject!AMyActor::BoolVal
false

UnrealEditor-MyProject!AMyActor::FloatVal
1.00000000

UnrealEditor-MyProject!AMyActor::TestFunc()
[2022.XX.XX-XX.XX.XX:XXX][XXX]LogTemp: Warning: test

UnrealEditor-MyProject!AMyActor::intVal=555
555

 例えばこれを活かすことによって、以下のようにコンソールコマンド実行用の関数を用意しておくと、

#include "Kismet/KismetSystemLibrary.h"

void AMyActor::ExecConsoleCommand(const char* str)
{
	FString TempStr(str);
	UKismetSystemLibrary::ExecuteConsoleCommand(GetWorld(), TempStr, nullptr);
}

 ブレーク中に実行することによって、ブレーク解除直後にコンソールコマンドが実行できるようになります。これはブレーク直後にコンソールコマンドを入力したいケースや、画面が無いDedicated Serverにコンソールコマンドをデバッグ実行しながら入力したいようなケースでも役に立ちそうです。

UnrealEditor-MyProject!AMyActor::ExecConsoleCommand("RestartLevel")
[2022.XX.XX-XX.XX.XX:XXX][XXX]Cmd: RestartLevel

 これはあくまで1つの例ですが、他にも自作の関数やエンジンの機能にアクセスすることによってデバッグの幅が広がって良いかと思いますので、是非ご活用ください。

9
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
11