Healthbars and Nameplate Widgets with UMG

Today I’d like to quickly show how you can add UI for things like health bars, nameplates, interaction prompts and more in Unreal Engine. It’s quite simple to do, and I hear a lot of questions about this, so today I’ll share you some tricks to make this even easier. The sample code is done in C++, but keep reading as I show you a quick and easy Blueprint-only trick too! The following guide explains the concept of how to be able to fetch the information you desire for your in-world widgets such as health, player names, etc., you don’t need to follow this to the letter, so long as you understand the concept, and implement what suits your own projects best.

To make it easy to get information on what the widget is attached to, we need to help it out a little. By default the UMG Widget has no context on what is it being drawn on top of (it doesn’t know which WidgetComponent it belongs to either) this is a problem for us as we have no way to find out what health the actor is at, or what name to display for that specific Actor (in the image below: “Spy” or “Soldier” based on a variable inside the player’s Pawn)

In the C++ Implementation below our custom widget component sets the Owner (an Actor) of the WidgetComponent as variable inside our custom UserWidget class so that we have instant access to the owning actor when working on the UI element. This is great for retrieving the health of the Actor we are attached to for example. The C++ snippets below show you how that’s done. But first, let’s look at the simplest Blueprint implementation to get an understanding of what we’re trying to solve in the most basic way.

The Simplest Implementation in Blueprint

Not everyone wants to touch C++, and it’s not really required. You may also not like the idea of the custom UserWidget base class for your UI elements moving forward (those are will be drawn in the world at least). You could do this in Blueprint too, just a little different. Here is the basic principle of how you could achieve the same result in your Blueprint project in a quick and straight forward manner.

I created a fresh Widget Blueprint, added a variable called OwningActor of type Actor. Now I access the Widget Component on the Actor that will own the Widget (eg. the Player pawn Blueprint from the image above) during BeginPlay, and we get the “User Widget Object” which we need to cast to the correct type. Finally we fill in the OwningActor variable with the Actor “self” and we’re done!

In the above example we added the widget blueprint to a grenade actor so it can display the information on mouse-over when the player sees it in the world. Look at the end of the post for some more context screenshots in case you’re not quite following this yet.

Preparing your C++ Project

Besides the super easy implementation for Blueprint, you could do the exact same in C++ or you could opt to make your own user widget and widgetcompont classes, I’ll quickly show you how that’s done. For C++ to extend UMG, which is what we’ll be doing, you will have to prepare your project first. The user “WCode” has Epic Wiki page for exactly that:

Required: Extend UserWidget for UMG Widgets

Make sure your project is prepared using the link above, it shouldn’t take too long. If you’re just interested in the concept and will us Blueprint you don’t need to do this.

The implementation in C++

The following is the code for SActorWidgetComponent and derives from Unreal’s WidgetComponent class. The functionality we add here is to set the owning Actor on the SActorWidget class (will be covered in a bit) which is an exposed variable to Blueprint for use in the UMG Editor.

#include "SActorWidgetComponent.h"
#include "FrameworkZeroPCH.h"
#include "SActorWidget.h"



USActorWidgetComponent::USActorWidgetComponent()
{
	// Set common defaults when using widgets on Actors
	SetDrawAtDesiredSize(true);
	SetWidgetSpace(EWidgetSpace::Screen);
	SetCollisionEnabled(ECollisionEnabled::NoCollision);
}


void USActorWidgetComponent::InitWidget()
{
	// Base implementation creates the 'Widget' instance
	Super::InitWidget();

	if (Widget)
	{
#if !UE_BUILD_SHIPPING
		if (!Widget->IsA(USActorWidget::StaticClass()))
		{
			// Suggest deriving from actor widget (not strictly required, but you lose the benefit of auto-assigning the Actor this way)
			UE_LOG(LogGame, Warning, TEXT("WidgetClass for %s does not derive from SActorWidget"), *GetNameSafe(GetOwner()));
		}
#endif
		USActorWidget* WidgetInst = Cast<USActorWidget>(Widget);
		if (WidgetInst)
		{
			// Assign the owner, now we have easy access in the widget itself
			WidgetInst->SetOwningActor(GetOwner());
		}
	}
}

Here is the header file:

#pragma once

#include "CoreMinimal.h"
#include "Components/WidgetComponent.h"
#include "SActorWidgetComponent.generated.h"

/**
 * Extension of the WidgetComponent to make it easy to have owning Actor context to the Widget. Commonly used to display health bars, names, and interaction panels above Actors.
	Automatically calls SetOwningActor on the widget if the correct type of widget is used (ActorAttachWidget)
 */
UCLASS(ClassGroup = (LODZERO), meta = (BlueprintSpawnableComponent))
class LZFRAMEWORK_API USActorWidgetComponent : public UWidgetComponent
{
	GENERATED_BODY()
	
public:

	virtual void InitWidget() override;
	
	USActorWidgetComponent();
	
};

That covers part one, the main element however is the variable we add to the Widget class, which looks like this:

#include "SActorWidget.h"

void USActorWidget::SetOwningActor(AActor* NewOwner)
{
	if (OwningActor == NewOwner)
	{
		// Skip repeated calls
		return;
	}

	OwningActor = NewOwner;

	OnOwningActorChanged.Broadcast(NewOwner);
}

And the header:

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "SActorWidget.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnOwningActorChanged, AActor*, NewOwner);


/**
 * Base class for UMG Widgets that belong to a single Actor in the world via a WidgetComponent, eg. for 3D health-bars, nameplate, interaction tooltip.
 */
UCLASS(Abstract)
class LZFRAMEWORK_API USActorWidget : public UUserWidget
{
 GENERATED_BODY()

protected:

 /* Actor that widget is attached to via WidgetComponent */
 UPROPERTY(BlueprintReadOnly, Category = "ActorWidget")
 AActor* OwningActor;
 
public:

 /* Set the owning actor so widgets have access to whatever is, broadcasting OnOwningActorChanged event */
 UFUNCTION(BlueprintCallable, Category = "LODZERO|UI")
 void SetOwningActor(AActor* NewOwner);

 UPROPERTY(BlueprintAssignable, Category = "LODZERO|UI")
 FOnOwningActorChanged OnOwningActorChanged;
};

That’s all the code required to use this in your game project. The main thing to keep in mind is that your in-world widgets should use both these classes for this to work. When you create a new Blueprint class now that derives from SActorWidget you will have the following variable available:

If you’re following along, make sure the Actor has the SActorWidgetComponent instead of the built-in WidgetComponent and assigned your UMG Widget class as your normally would with WidgetComponents.

That’s it! This quick little trick should make it a lot easier to display in-world information on Actors. Both a quick and easy Blueprint implementation and a C++ alternative to ‘bake this down’ if your project so desires.

As always, you can follow me on Twitter and if you have questions or comments you can leave them below!

References

22 Responses

  1. Hate to necro an old post, but some of the links in this post no longer work. I’m actually following your Udemy Unreal Mastery C++ course, but wanted to learn about world space UI, so ended up here. I was wondering if there is anywhere else I can follow for Extending the UserWidget? Or maybe there is a different way to do it in Unreal now?

  2. Hello tom, pls I have a similar scenario to this but not working for me in BP. I created a text widget to be displayed on actor begin overlap, but the thing now is that all actors(multiplayer) sees the popup on their own screen. Thanks for your quick response

    • You’ll need to check in your overlap whether the pawn is locally controlled. that’s a function that will tell you if the overlap happened on “this machine” when it’s multiplayer.

  3. How to make an object show information when you put the mouse on it? how with the grenade from above, That is cool.

    • You can do by using WidgetComponent on the Actor and have it show/hide based on ‘focus events’ meaning you will check if your cursor or center-screen is hovering over the actor (One of my very first tutorials on “usable actors” explains one way to implement this)

  4. Hi Tom, I have a Question regarding the UWidgetComponent, I have also posted the question in the Answerhub (https://answers.unrealengine.com/questions/817509/widgetcomponent-wont-render-in-world.html), so the issue is that I’m setting the Widget Component to the world space, but for some reason it’s not getting rendered in the World, to get it to render I have to unpossess the player and change any small detail in the rendering section, after any change, it actually renders the Widget, but it’s not rendering correctly since the Image of a DPad is not getting rendered, it only render the white background that I had set to test the widget just in case. Any idea of why this might be happening?

  5. Hi Tom! Thanks for doing this tutorial. Just one quick thing how would I go about setting the visibility of the widget according to the team number (like in a shooter)? I tried to make a custom function ESlateVisibility DetermineVisibility(); which checks if the owning actor is the owning player (GetOwningPlayer()) to hide it for the owner since OwnerNoSee(true); is not working out for me. After that I tried to get the player state of the owning player to check if it is unequal to the owning actors player state to hide it if they are in a different team. But either is it invisible or visible for all characters. Could you help me out, please?

  6. Hey Tom, thanks for this tutorial. Just one question, where should I actually bind the delegate? Construct is not working out for me.

    • Hi there! Which delegate do you mean? Normally I would use PostInitializeComponents in C++ or BeginPlay in Blueprint to bind delegates.

      – Tom

      • First, thanks for the reply. I’m sorry for being so imprecise. I tried to assign the FOnOwningActorChanged delegate to the overridden widget’s construct event.
        I have read about some problems when using the construct event on the widget to bind delegates.
        My custom widget is used to display the owning actor’s (character) name. So whenever the owning actor changes I want to change the color according to the character’s team.

  7. Hi Tom!Can you make new update of this animation of dying mannequin lying in first person mode dropping weapon nearby standing in air very close to terrain with dot of shadow light and also before that happens can you show me how your life stamina is full and slowly getting empty when your playable character gets hurt by opposite enemy character AI,please?You showed us just a little bit of health stamina loss in this amazing video .gif file.

      • Thanks. Also do you think that updating bars (progress bars and health numbers) are ok (from performance point of view) in tick function ? I have EWidgetSpace::Screen.

  8. Good stuff! How do you make health bars scale in size and always the player camera? Right now I do some scaling math on tick which is something I’m not a fan of.

    • You just have to set the widget space to EWidgetSpace::Screen as Tom did in the constructor. This does all the magic.

  9. Good post. Thx! Just one minor: it’s not necessary to check IsBound() on dynamic multicast delegate. It’s always safe to call (does the check internaly). See ScriptDelegates.h:450;)

    • Fair point! I usually don’t check for Isbound, I’ll update the code snippet. Guess I was trying to be overly safe haha.

Leave a comment on this post!