In this post we’re going to see how to create a custom gameplay debugger category. By the time of this writing the official documentation page is outdated.

This post was written in 4.15 version of the engine. Depending on the time you’re reading this, this information may be outdated as well.

Please note that this is a followup post to my “Creating Custom Modules” post. So before going any further, make sure that you have followed that post and everything works fine.

Modifying the .Build.cs file

Before we go any further, open up the .Build.cs file of your module (in my case this will be OrfeasModule.Build.cs file and add the following lines of code:

.build.cs file if (UEBuildConfiguration.bBuildDeveloperTools || (Target.Configuration != UnrealTargetConfiguration.Shipping && Target.Configuration != UnrealTargetConfiguration.Test)) { PrivateDependencyModuleNames.Add("GameplayDebugger"); Definitions.Add("WITH_GAMEPLAY_DEBUGGER=1"); } else { Definitions.Add("WITH_GAMEPLAY_DEBUGGER=0"); } 1 2 3 4 5 6 7 8 9 if ( UEBuildConfiguration . bBuildDeveloperTools || ( Target . Configuration != UnrealTargetConfiguration . Shipping && Target . Configuration != UnrealTargetConfiguration . Test ) ) { PrivateDependencyModuleNames . Add ( "GameplayDebugger" ) ; Definitions . Add ( "WITH_GAMEPLAY_DEBUGGER=1" ) ; } else { Definitions . Add ( "WITH_GAMEPLAY_DEBUGGER=0" ) ; }

When you’re done with that, add a new C+ class that inherits the UObject inside your module and name it CustomGameplayDebugger so you can follow the tutorial easier.

Creating the GameplayDebuggerCategory

Open up the header file of the CustomGameplayDebugger class and erase the code that the editor has written for you and declare the following class:

CustomGameplayDebuggerCategory #pragma once #include "CoreMinimal.h" #if WITH_GAMEPLAY_DEBUGGER #include "GameplayDebuggerCategory.h" //Forward declarations class AActor; class APlayerController; class FGameplayDebuggerCanvasContext; //The data we're going to print inside the viewport struct FDataToPrint { float HP; float Damage; }; //The class of our custom gameplay debugger category class FGameplayDebuggerCategory_Orfeas : public FGameplayDebuggerCategory { protected: //The data that we're going to print FDataToPrint Data; public: FGameplayDebuggerCategory_Orfeas(); /** Creates an instance of this category - will be used on module startup to include our category in the Editor */ static TSharedRef<FGameplayDebuggerCategory> MakeInstance(); /** Collects the data we would like to print */ virtual void CollectData(APlayerController* OwnerPC, AActor* DebugActor) override; /** Displays the data we collected in the CollectData function */ virtual void DrawData(APlayerController* OwnerPC, FGameplayDebuggerCanvasContext& CanvasContext) override; }; #endif 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #pragma once #include "CoreMinimal.h" #if WITH_GAMEPLAY_DEBUGGER #include "GameplayDebuggerCategory.h" //Forward declarations class AActor ; class APlayerController ; class FGameplayDebuggerCanvasContext ; //The data we're going to print inside the viewport struct FDataToPrint { float HP ; float Damage ; } ; //The class of our custom gameplay debugger category class FGameplayDebuggerCategory_Orfeas : public FGameplayDebuggerCategory { protected : //The data that we're going to print FDataToPrint Data ; public : FGameplayDebuggerCategory_Orfeas ( ) ; /** Creates an instance of this category - will be used on module startup to include our category in the Editor */ static TSharedRef < FGameplayDebuggerCategory > MakeInstance ( ) ; /** Collects the data we would like to print */ virtual void CollectData ( APlayerController * OwnerPC , AActor * DebugActor ) override ; /** Displays the data we collected in the CollectData function */ virtual void DrawData ( APlayerController * OwnerPC , FGameplayDebuggerCanvasContext & CanvasContext ) override ; } ; #endif

Then, open up the source file of your class and type in the following code:

Gameplay Debugger Category #include "GDBlogPostCharacter.h" #if WITH_GAMEPLAY_DEBUGGER #include "DebugRenderSceneProxy.h" FGameplayDebuggerCategory_Orfeas::FGameplayDebuggerCategory_Orfeas() { bShowOnlyWithDebugActor = false; } TSharedRef<FGameplayDebuggerCategory> FGameplayDebuggerCategory_Orfeas::MakeInstance() { return MakeShareable(new FGameplayDebuggerCategory_Orfeas()); } void FGameplayDebuggerCategory_Orfeas::CollectData(APlayerController* OwnerPC, AActor* DebugActor) { if (DebugActor) { AGDBlogPostCharacter* Char = Cast<AGDBlogPostCharacter>(DebugActor); if (Char) { //Store the data to our struct Data.HP = Char->Health; Data.Damage = Char->MaxDamage; } } } void FGameplayDebuggerCategory_Orfeas::DrawData(APlayerController* OwnerPC, FGameplayDebuggerCanvasContext& CanvasContext) { //Test print with white text CanvasContext.Printf(TEXT("Test Print")); CanvasContext.Printf(FColor::Yellow, TEXT("Yet again another print!")); //Print the health data with green color CanvasContext.Printf(TEXT("{green}HP: %s"), *FString::SanitizeFloat(Data.HP)); //Print the damage data with red color CanvasContext.Printf(TEXT("{red}Damage: %s"), *FString::SanitizeFloat(Data.Damage)); } #endif 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #include "GDBlogPostCharacter.h" #if WITH_GAMEPLAY_DEBUGGER #include "DebugRenderSceneProxy.h" FGameplayDebuggerCategory_Orfeas :: FGameplayDebuggerCategory_Orfeas ( ) { bShowOnlyWithDebugActor = false ; } TSharedRef < FGameplayDebuggerCategory > FGameplayDebuggerCategory_Orfeas :: MakeInstance ( ) { return MakeShareable ( new FGameplayDebuggerCategory_Orfeas ( ) ) ; } void FGameplayDebuggerCategory_Orfeas :: CollectData ( APlayerController * OwnerPC , AActor * DebugActor ) { if ( DebugActor ) { AGDBlogPostCharacter * Char = Cast < AGDBlogPostCharacter > ( DebugActor ) ; if ( Char ) { //Store the data to our struct Data . HP = Char -> Health ; Data . Damage = Char -> MaxDamage ; } } } void FGameplayDebuggerCategory_Orfeas :: DrawData ( APlayerController * OwnerPC , FGameplayDebuggerCanvasContext & CanvasContext ) { //Test print with white text CanvasContext . Printf ( TEXT ( "Test Print" ) ) ; CanvasContext . Printf ( FColor :: Yellow , TEXT ( "Yet again another print!" ) ) ; //Print the health data with green color CanvasContext . Printf ( TEXT ( "{green}HP: %s" ) , * FString :: SanitizeFloat ( Data . HP ) ) ; //Print the damage data with red color CanvasContext . Printf ( TEXT ( "{red}Damage: %s" ) , * FString :: SanitizeFloat ( Data . Damage ) ) ; } #endif

Before you attempt to build your project, make sure that your character class is marked with the appropriate *_API macro – otherwise you will encounter a linker error. (Special thanks to Mieszko Zielinski for his help on this one).

In my case, my project is named “GDBlogPost” so my character class is going to have the following macro in the class declaration:

class GDBLOGPOST_API AGDBlogPostCharacter : public ACharacter

Moreover, don’t forget to add the Health and MaxDamage properties of the character somewhere in its header file:

Character's properties public: UPROPERTY(EditAnywhere) float Health; UPROPERTY(EditAnywhere) float MaxDamage; 1 2 3 4 5 6 7 public : UPROPERTY ( EditAnywhere ) float Health ; UPROPERTY ( EditAnywhere ) float MaxDamage ;

The last things we need to do, is to tell our Module to register our custom gameplay debugger category on its startup. Moreover, we need to tell our Module to unregister our category if its shutdown. To do that navigate to your module’s source file and type in the following code:

OrfeasModule.cpp void FOrfeasModule::StartupModule() { UE_LOG(OrfeasModule, Warning, TEXT("Orfeas module has started!")); #if WITH_GAMEPLAY_DEBUGGER //If the gameplay debugger is available, register the category and notify the editor about the changes IGameplayDebugger& GameplayDebuggerModule = IGameplayDebugger::Get(); GameplayDebuggerModule.RegisterCategory("OrfeasCustomCategory", IGameplayDebugger::FOnGetCategory::CreateStatic(&FGameplayDebuggerCategory_Orfeas::MakeInstance), EGameplayDebuggerCategoryState::EnabledInGameAndSimulate); GameplayDebuggerModule.NotifyCategoriesChanged(); #endif } void FOrfeasModule::ShutdownModule() { UE_LOG(OrfeasModule, Warning, TEXT("Orfeas module has shut down")); #if WITH_GAMEPLAY_DEBUGGER //If the gameplay debugger is available, unregister the category if (IGameplayDebugger::IsAvailable()) { IGameplayDebugger& GameplayDebuggerModule = IGameplayDebugger::Get(); GameplayDebuggerModule.UnregisterCategory("OrfeasCustomCategory"); } #endif } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 void FOrfeasModule :: StartupModule ( ) { UE_LOG ( OrfeasModule , Warning , TEXT ( "Orfeas module has started!" ) ) ; #if WITH_GAMEPLAY_DEBUGGER //If the gameplay debugger is available, register the category and notify the editor about the changes IGameplayDebugger & GameplayDebuggerModule = IGameplayDebugger :: Get ( ) ; GameplayDebuggerModule . RegisterCategory ( "OrfeasCustomCategory" , IGameplayDebugger :: FOnGetCategory :: CreateStatic ( &FGameplayDebuggerCategory_Orfeas :: MakeInstance ) , EGameplayDebuggerCategoryState :: EnabledInGameAndSimulate ) ; GameplayDebuggerModule . NotifyCategoriesChanged ( ) ; #endif } void FOrfeasModule :: ShutdownModule ( ) { UE_LOG ( OrfeasModule , Warning , TEXT ( "Orfeas module has shut down" ) ) ; #if WITH_GAMEPLAY_DEBUGGER //If the gameplay debugger is available, unregister the category if ( IGameplayDebugger :: IsAvailable ( ) ) { IGameplayDebugger & GameplayDebuggerModule = IGameplayDebugger :: Get ( ) ; GameplayDebuggerModule . UnregisterCategory ( "OrfeasCustomCategory" ) ; } #endif }

Once you’re done with that, save and build your project. At this point, if you navigate to your Project’s settings inside the Gameplay Debugger option, you will have the following category available:

You may have to restart your Editor if that option isn’t visible.

Enabling the Gameplay Debugger

To enable the gameplay debugger click on the apostrophe key on your keyboard (‘) and type in the “showflag.debugAI 1” console command while simulating your game.

Then, select your character. The following window will appear: