While our game may be running without any issues in the editor or even in…
Creating Custom Gameplay Debugger Categories
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:
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:
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:
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 ACharacterMoreover, don’t forget to add the Health and MaxDamage properties of the character somewhere in its header file:
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:
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:
Is it required to use a custom module for this? 🙁 Or could the #if gameplay debugger ommitted here?
Cheers! I love your blog mate
– Tom
Hey Tom,
I was following the engine’s source code when I came up with this. According to this comment, in order to register a category in general, a module is required (not a custom one though).
Thanks for your kind words!
-Orfeas
Hi, I apologize if this is not totally on topic but I don’t know where else to ask… u_u
I was wondering, would it be possible to create a .h and .cpp file entirely in Visual Studio that contains only a collection of UFUNCTION() that can be accessed from every blueprint you make inside the blueprint editor?
Kind of like the basic nodes (for example “float*float”) that are shared across all BP
If yes, could you kindly point me in the direction of the appropriate tutorial or example? ^_^
Hello Marcus,
What you’re looking for is called “Blueprint Function Library”. You have to add via the C++ wizard though.
-Orfeas
I actually bumped into it yesterday by pure luck by digging on the wiki, but thank you a lot nonetheless for helping me 🙂
Still working on 4.19?
Experiencing either a bunch of linker errors following this or anything else to try and get this friggen gameplay debugger stuff going lol
Updated build.cs code for latest versions:
if (Target.bBuildDeveloperTools || (Target.Configuration != UnrealTargetConfiguration.Shipping && Target.Configuration != UnrealTargetConfiguration.Test))
{
PrivateDependencyModuleNames.Add(“GameplayDebugger”);
PublicDefinitions.Add(“WITH_GAMEPLAY_DEBUGGER=1”);
}
else
{
PublicDefinitions.Add(“WITH_GAMEPLAY_DEBUGGER=0”);
}