Combining C++ HUD with UserWidgets (UMG)

Hello,

I’m posting this after quite a few days of research, and everything led me into a dead end.

(Have you ever had the feeling that, while you’re trying to keep as much as possible in C++, everything you find documented is related to Blueprints? :frowning: )

Okay, so, I’m trying to create a simple HUD Display that combines both a class extended from AHUD (The example FPS one with just the crosshair is fine) with an UMG class created in the editor (I want health amount display, but I’m fine with a text string for now).

My latest attempt was to find the UMG reference in the HUD constructor:

	static ConstructorHelpers::FObjectFinder<UUserWidget>testWidget(TEXT("WidgetBlueprint'/Game/UMG/TestHUD.TestHUD'"));
	testUMG = testWidget.Object;

And try to spawn it using CreateWidget() - but it would need a bunch of hacks to get the PlayerController from inside the HUD.
(As, a quick reminder, is being setup in GameMode using HUDClass = AHavenHUD::StaticClass(); )

It feels I’m missing something stupid, but I’m probably tired of an endless loop search here so I decided to ask you guys if you can help me with this issue.

Of course, recommendations of the best way to set the HUD (using C++) is welcome!
Also, I’d like to avoid ditching my custom AHUD class completely (but tell me to do anyway if keeping it is a bad idea)

Thank you guys in advance!

1 Like

It seems my original assumptions were very wrong.
The way I found is:

  1. In Editor, create a UserWidget with the data you want to show on your HUD.

  2. In Editor, create a Blueprint based on AMyHUD (your custom HUD on C++ - you can use the provided one in the UE4 template)

  3. Edit your HUD Blueprint and on EvenBeginPlay, add a constructor node (“create widget” node) that creates your new Widget (the one from step 1)

  4. Set the constructor (create) node return value to “Add to Viewport”.

  5. On your MyGameMode.cpp, on the constructor, replace the C++ code

    HUDClass = AMyHUD::StaticClass();

with

// use our custom HUD class
static ConstructorHelpers::FClassFinder <AHUD> MyDefaultHUD(TEXT("/Game/UI/MyDefaultHUD"));
HUDClass = (UClass*)MyDefaultHUD.Class;

And you’re done!

Hope this helps someone out there :slight_smile:

2 Likes

I wrestled with this myself. I was able to get a UMG UserWidget (a blueprint widget) up and running from a C++ HUD in the first person shooter example project:

  • Add the “UMG” modules to the project dependencies inside testfps.Build.cs It should look like this:

      PublicDependencyModuleNames.AddRange (new string [] { "Core", "CoreUObject", "Engine", "InputCore", "UMG" });
      PrivateDependencyModuleNames.AddRange (new string [] { "Slate", "SlateCore" });
    
  • Added C++ character controller and custom HUD classes to the project and set it up in my *GameMode.cpp:

     // testfpsGameMode.cpp constructor
     PlayerControllerClass = AtestfpsController::StaticClass ();
     HUDClass = AtestfpsHUD::StaticClass ();
    
  • Added a WidgetBlueprint named mainHUDWidget to my project with its parent class set to User Widget in its ClassSettings

  • set up some visible text or a box or something in the mainHUDWidget blueprint so that we can see it when it works

  • Inside testfpsHUD.h I added the following properties and override:

      class UClass * hudWidgetClass;
      class UUserWidget * hudWidget;
      
      virtual void BeginPlay () override;
    
  • Then inside testfpsHUD.cpp:

      #include "Runtime/UMG/Public/UMG.h"
      #include "Runtime/UMG/Public/UMGStyle.h"
      #include "Runtime/UMG/Public/Slate/SObjectWidget.h"
      #include "Runtime/UMG/Public/IUMGModule.h"
      #include "Runtime/UMG/Public/Blueprint/UserWidget.h"
      #include "Blueprint/UserWidget.h"
      AtesttwoHUD::AtesttwoHUD () {
          // notice that at this point we can't guarantee that the playerController is actually constructed yet, so we can't get a reference to it
          static ConstructorHelpers::FClassFinder<UUserWidget> hudWidgetObj (TEXT ("/Game/FirstPersonCPP/hud/mainHUDWidget"));
          if (hudWidgetObj.Succeeded ()) {
              hudWidgetClass = hudWidgetObj.Class;
          } else {
              // hudWidgetObj not found
              hudWidgetClass = nullptr;
          }
      }
      
      void AtesttwoHUD::BeginPlay () {
      	Super::BeginPlay ();
          if (hudWidgetClass) {
              // the player controller should be constructed by now so we can get a reference to it
              hudWidget = CreateWidget<UUserWidget> (this->GetOwningPlayerController (), this->hudWidgetClass);
              hudWidget->AddToViewport ();
          }
      }
    
1 Like