Download

Assigning a variable for a Widget Class UMG?

I am very new to the UMG system. I come from Unity so it’s been a big learning overhaul for me. I have asked this question before but I don’t think I made myself clear, so let me ask it again (yes I deleted the old post) :

I started a blank c++ project. I created a new c++ class called MyActor. MyActor has two floats : currentValue and maxValue. Both are equal to 100 right now. There is a method called deplete which will deplete the currentValue overtime. This is called in the Tick function. Here is the header file :



#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"

UCLASS(Blueprintable)
class LEARNINGWIDGETS_API AMyActor : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	AMyActor();

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Variables")
	float currentValue = 100;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Variables")
	float maxValue = 100;

	void Deplete(float decrementValue);

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	
	
};


And the CPP file



#include "MyActor.h"


// Sets default values
AMyActor::AMyActor()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

void AMyActor::Deplete(float decrementValue)
{
	if (currentValue != 0)
	{
		currentValue -= decrementValue;
	}
}

// Called when the game starts or when spawned
void AMyActor::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void AMyActor::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	Deplete(DeltaTime * 0.025);
}


I have dragged this actor into the scene now.

I want a visual representation of the current health value. So, I created a new Widget Blueprint called MyWidget_BP
I have a progress bar already set. In the progress panel, I set a bind for that progress bar. Here’s what the graph looks like:

f19643a2dbcc7b5e3420092c4e7d4f1359646ec8.png

Look at the variable called “ReferenceToMyActor”. Pretty self explanatory on what it is. Of course, I can’t set the default value since this is a WidgetBlueprint is a class default.
So now here’s my question: How do I display this widget from MyActor? I see alot of documentation doing it somewhere else, like the game mode base. I just want to show it in MyActor.
Also, how do I set ReferenceToMyActor from MyActor? Or is that possible? Instead, I see a lot of people getting their player controller and then accessing values through there. But I want to access MyActor in the scene. How would I do that? I need to access it because as you can see, I can pull out Current Value and Max Value to update the progress bar.

This has been something that seems simple but has driven me crazy. Let me know if i need to explain further, I want to know how to do this ASAP!

And F.Y.I. yes, get all actors works but it something I want to avoid. What if there are multiple actors who derive from this and use this widget blueprint, but some of their implementation is different? Get All actors of class might return me the actor I didn’t want.
I want to avoid Get all actors by tag as well. All in all, I want to be able to set that reference variable so I can reuse this Widget_BP

Add a widget component to the actor…same as you add any other component?

No not quite… that would create a 3D widget for me - not what I want. Again I am also trying to store the MyActor reference in there.

Bump for this

I figured it out.

Essentially what I want to is in c++, I want to create a GameInstance called MyGameInstance. Then, I declared a variable like this:


class MyActor* referenceActor

Must be exposable to blueprints (the variable + the class just for the sake of it). In my case I had to do a forward declaration here. Additionally, I have to set this in the editor via Edit>Project Settings>Maps and Modes>now just find where you can set your game instance. It should be a dropdown.

Now, in blueprints all I have to do is do a GetGameInstance node → cast it to the class name of the custom game instance I created with c++ (in my case, it is called UMyGameInstance_CPParent) → get “referenceActor” → follow up with the rest of the nodes to get the currentValue, maxValue etc.

In MyActor, I declared a variable like this


class UMyGameInstance_CPParent* gameInstance

Again, forward declaration.
Then, in BeginPlay, I do this:


if (GetWorld()->GetGameInstance() != nullptr)
	{
		gameInstance = Cast<UMyGameInstance_CPParent>(GetWorld()->GetGameInstance());
		if (gameInstance != nullptr)
		{
			gameInstance->referenceActor = this;
		}
	}

Remember that you want to include the necessary header files for this to work.

Finished files and blueprint code:

MyActor .h :



// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "Blueprint/UserWidget.h"
#include "MyGameInstance_CPParent.h"

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"

UCLASS(Blueprintable)
class LEARNINGWIDGETS_API AMyActor : public AActor
{
	GENERATED_BODY()
	
private:

public:	
	// Sets default values for this actor's properties
	AMyActor();

#pragma region My variables
public:
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Variables")
	UUserWidget* playerHUD;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Variables")
	float currentValue = 100;

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Variables")
	float maxValue = 100;

	class UMyGameInstance_CPParent* gameInstance;
#pragma endregion

#pragma region My Functions
private:
	void Deplete(float decrementValue);
#pragma endregion

#pragma region Default Functions
protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;
#pragma endregion
	
	
};


MyActor.cpp :



// Fill out your copyright notice in the Description page of Project Settings.

#include "MyActor.h"
#define DISPLAY_MESSAGE(message) if(GEngine){GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Yellow, TEXT(message));} 

// Sets default values
AMyActor::AMyActor()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;
	

}

void AMyActor::Deplete(float decrementValue)
{
	if (currentValue > 0)
	{
		currentValue -= decrementValue;
	}
}

// Called when the game starts or when spawned
void AMyActor::BeginPlay()
{
	Super::BeginPlay();

	if (GetWorld()->GetGameInstance() != nullptr)
	{
		DISPLAY_MESSAGE("Valid!");
		gameInstance = Cast<UMyGameInstance_CPParent>(GetWorld()->GetGameInstance());
		if (gameInstance != nullptr)
		{
			gameInstance->referenceActor = this;
			DISPLAY_MESSAGE("Valid x2!");
		}
	}

	if (playerHUD != nullptr)
	{
		playerHUD->AddToViewport();
	}
}

// Called every frame
void AMyActor::Tick(float DeltaTime)
{

	Super::Tick(DeltaTime);                                                              
	Deplete(DeltaTime * 0.25);
}


MyGameInstance_CPParent.h (the .cpp I left as is. I didn’t touch it. It just includes this header file):



// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "MyActor.h"

#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "MyGameInstance_CPParent.generated.h"

/**
 * 
 */
UCLASS()
class LEARNINGWIDGETS_API UMyGameInstance_CPParent : public UGameInstance
{
	GENERATED_BODY()
	
public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Global varaibles")
	class AMyActor* referenceActor;
};



The widget blueprint’s progress bar’s bind function graph:
UE4Solution.PNG

There’s probably a better way to set that reference, just by the looks of it seems unsafe, but it works for now. Additionally, there is also a way to do this via singleton pattern, but I keep hearing from the c++ community to avoid these unless strictly needed