HP Progress Bar won't move when the character is attacked.

Hi everyone. I have HP Progress Bar in the top left corner when the character is attacked. Like the picture.
스크린샷 2025-03-30 195655

made Progress Bar with WBP_HpBar and added WBP_HpBar that I made to WBP_HUD. And I wrote the code because I wanted to make HpBar shrink if the character was attacked. Below is the code I wrote.

class LIFEOFLUCK_API IOLHpInterface
{
	GENERATED_BODY()

	// Add interface functions to this class. This is the class that will be inherited to implement this interface.
public:
	virtual float SetHp() = 0;
};
#include "Interface/OLAttackInterface.h"
#include "Interface/OLHpInterface.h"
UCLASS()
class LIFEOFLUCK_API AOLCharacterBase : public ACharacter, public IOLAttackInterface, public IOLHpInterface
{
	GENERATED_BODY()
// HP
protected:
	virtual float SetHp() override;

};

float AOLCharacterBase::SetHp()
{
	return Hp / MaxHp;
}

For your information, the AOLCharacterBase has a TakeDamage function, where the Hp value changes (when under attack)

UCLASS()
class LIFEOFLUCK_API UOLHpBarWidget : public UUserWidget
{
	GENERATED_BODY()

public:
	UOLHpBarWidget(const FObjectInitializer& ObjectInitializer);

protected:
	class UProgressBar* HpBar;	// HpBar

	void UpdateHpBar();	// Hp 프로그레스바 체력에 따라 변경하는 함수

	UPROPERTY()
	float UpdateHp;
};

#include "UI/OLHpBarWidget.h"
#include "Interface/OLHpInterface.h"
#include "Components/ProgressBar.h"

UOLHpBarWidget::UOLHpBarWidget(const FObjectInitializer& ObjectInitializer) :Super(ObjectInitializer)
{
}

void UOLHpBarWidget::UpdateHpBar()
{
	APawn* Player = GetOwningPlayerPawn();	// Player 가져오기
	ensure(Player);

	IOLHpInterface* PlayerInterface = Cast<IOLHpInterface>(Player);
	if (!PlayerInterface)
	{
		UE_LOG(LogTemp, Error, TEXT("Cast to IOLHpInterface failed!"));
		return;
	}

	UpdateHp = PlayerInterface->SetHp();
	UE_LOG(LogTemp, Log, TEXT("UpdateHp: %f"), UpdateHp);

	HpBar->SetPercent(UpdateHp);
	UE_LOG(LogTemp, Error, TEXT("UpdateHp"));

}

I wrote the code like this. The problem now is that HpBar appears well on the screen. But SetPercent doesn’t seem to work. I don’t think Hp ProgressBar is being updated.
And the logs I wrote in UpdateHpBar don’t come up. I don’t know what the problem is.. (I might have written the wrong code)

I’d really appreciate your help.(Because I used a translator, words can be unnatural. Please understand..)

Hi.

Are you sure you are entering UOLHpBarWidget::UpdateHpBar() at all? Can you log at the beginning of the function and tell if the log is hit?

Also, your UOLHpBarWidget constructor is completely empty. Are you sure a UProgressBar is constructed and assigned to *HpBar?

Thank you for answering me first.

When I checked the code, I didn’t call the UpdateHpBar function. I just made it

I’m sorry but I didn’t understand this.. Can you say it again? (I’m having a little difficulty understanding it by using a translator. Please understand.)

void UOLHpBarWidget::NativeConstruct()
{
	UpdateHpBar();
}

void UOLHpBarWidget::UpdateHpBar()
{
	UE_LOG(LogTemp, Error, TEXT("Hp Loding..."));

	APawn* Player = GetOwningPlayerPawn();	// Player 가져오기
	ensure(Player);

	IOLHpInterface* PlayerInterface = Cast<IOLHpInterface>(Player);
	if (!PlayerInterface)
	{
		UE_LOG(LogTemp, Error, TEXT("Cast to IOLHpInterface failed!"));
		return;
	}

	UpdateHp = PlayerInterface->SetHp();
	UE_LOG(LogTemp, Log, TEXT("UpdateHp: %f"), UpdateHp);

	if (HpBar)
	{
		HpBar->SetPercent(UpdateHp);
		UE_LOG(LogTemp, Error, TEXT("UpdateHp"));
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("Nooooo HpBar"));
	}


}

I modified the code as above. At this time, a log called Noooo HpBar appeared. I don’t think there’s an HpBar.
스크린샷 2025-03-31 174703
스크린샷 2025-03-31 174714
I think the Hp suddenly went to zero too. The color is gone.

I think it’s correct that the HpBar was not created. And I thought about it, if the character’s Hp is reduced, they should call the UpdateHpBar function somewhere, but they didn’t call it.

The problem with my code seems to be that HpBar has not been created, and Update HpBar is not called anywhere, so it doesn’t seem to diminish when attacked.

I’ve modified the code a little more now. I’ve created HpBar. Can you please check if this is the right way to do it..?

UCLASS()
class LIFEOFLUCK_API UOLHpBarWidget : public UUserWidget
{
	GENERATED_BODY()

public:
	UOLHpBarWidget(const FObjectInitializer& ObjectInitializer);

protected:
	virtual void NativeConstruct() override;

	UPROPERTY(EditAnywhere, Category = Hp)
	TObjectPtr<class UProgressBar> HpBarProgress;	// HpBar
...
	
};

void UOLHpBarWidget::NativeConstruct()
{
	Super::NativeConstruct();

	// 해당 컨트롤을 이름으로 찾기
	HpBarProgress = Cast<UProgressBar>(GetWidgetFromName(TEXT("HpBar")));
	ensure(HpBarProgress);

	UpdateHpBar();
}

I modified it like this. I named it HpBar because I set the Progress Bar as HpBar. That’s how I get the UpdateHp log.
Now the problem is UE_LOG ("LogTemp, Log, TEXT (“UpdateHp: %f”), UpdateHp); I think it’s written differently from what I intended. Because the Hp I thought was 1, but that log is outputting 0. I think that’s why Progress Bar appears gray.

You are just declaring a pointer to UProgressBar you are not creating the actual element. You need something like this:

bool UOLHpBarWidget::Initialize()
{
	if(!Super::Initialize())
		return false;
	if(WidgetTree)
	{
		auto MyCanvas = WidgetTree->ConstructWidget<UCanvasPanel>(UCanvasPanel::StaticClass());
		HpBar = WidgetTree->ConstructWidget<UProgressBar>(UProgressBar::StaticClass());
		MyCanvas->AddChildToCanvas(HpBar);
		WidgetTree->RootWidget = MyCanvas;
		return true;
	}
	else
		return false;
}

Or something along those lines… And no, I’ve not tested it. There is no force in the world that can make me build user interface in C++ :wink:

I’ll do something about the interface! But thank you very much for your answer :smiley:
Could you please confirm if my understanding is correct for the reason why I have to make it like the code you wrote? If you don’t mind…!

When you add a Progress Bar in the Unreal Editor and call the UI in code, you must create a real object. To move the Progress Bar (named HpBar) created by the Unreal Editor through setpercent, you must find the appropriate HpBar and put it in the object.

Through TObjectPtr, we create HpBarProgress, a ProgressBar variable, and assign an HpBar widget to it. So if the widget is assigned to HpBarProgress, you can use these functions such as SetPercent with this variable

(At this time, TObjectPtr is because I used HpBar to create a direct element.)

At this time, I would appreciate it if you could think that the interface is just a code from AOLCharacterBase. I think it’s just a function from AOLCharacterBase, ignoring the interface. (I think I confused you because I made it based on lectures from other places. :slight_smile:

UOLHpBarWidget::Initialize() is not an interface. It is just a member method in UOLHpBarWidget overriding the inherited method UUserWidget::Initialize()

The declaration below just declares a pointer (an empty address in memory)

UCLASS()
class LIFEOFLUCK_API UOLHpBarWidget : public UUserWidget
. . .
protected:
	class UProgressBar* HpBar;	// HpBar
. . .

at this point HpBae is nullptr because there is no object in it. This is why if(HpBar)... retunrs false and UE_LOG(LogTemp, Error, TEXT("Nooooo HpBar")); is executed.

The line below creates a progress bar and assigns it to HpBar

bool UOLHpBarWidget::Initialize()
. . .
    HpBar = WidgetTree->ConstructWidget<UProgressBar>(UProgressBar::StaticClass());
. . .

Aha, I understand now.
The interface I was talking about was IOLHpInterface. I thought you were talking about this and I got it wrong..

By the way, I assigned HpBar in NativeConstruct function, can you tell me the difference between Initialize and this function?

Initialize() is executed before the NativeConstruct() I think… You can try moving the code in
NativeConstruct() and say if it shows. As I said, one of my few goals in life is to I avoid doing UI in C++ but I saw that you are missing the construction of the HpBar so I chipped in.

Maybe someone else has ventured further in that…

It was supposed to run before NativeConstruct(). Thanks for letting me know!
If you don’t configure the UI with C++, how does dZh0 configure the UI? I’m curious how to do it!

First, I did it with Initialize(), but there was a crash, so I made it with the existing code in NativeConstruct().

void UOLHpBarWidget::NativeConstruct()
{
	Super::NativeConstruct();

	// 해당 컨트롤을 이름으로 찾기
	HpBarProgress = Cast<UProgressBar>(GetWidgetFromName(TEXT("HpBar")));
	ensure(HpBarProgress);

	// CharacterBase의 함수 가져오기
	APawn* Player = GetOwningPlayerPawn();	// Player 가져오기
	ensure(Player);

	IOLHpInterface* PlayerInterface = Cast<IOLHpInterface>(Player);
	ensure(PlayerInterface);

	PlayerInterface->SettingHpBar(this);

	HpBarProgress->SetPercent(1.f);

	UpdateHpBar();
}

I put a value of 1.f in SetPercent. The reason is that the Hp Bar should have been full of green when the game started, but it’s gray.

void UOLHpBarWidget::UpdateHpBar()
{
	UE_LOG(LogTemp, Error, TEXT("Hp Loding..."));

	APawn* Player = GetOwningPlayerPawn();	// Player 가져오기
	ensure(Player);

	IOLHpInterface* PlayerInterface = Cast<IOLHpInterface>(Player);
	ensure(PlayerInterface);

	UpdateHp = PlayerInterface->SetHp();
	UE_LOG(LogTemp, Log, TEXT("UpdateHp: %f"), UpdateHp);

	if (HpBarProgress)
	{
		HpBarProgress->SetPercent(UpdateHp);
		UE_LOG(LogTemp, Error, TEXT("UpdateHp"));
	}
	else
	{
		UE_LOG(LogTemp, Error, TEXT("Nooooo HpBar"));
	}


}

So when I checked it in this code, UpdateHp was 0. For your information, the SetHp function returns. returnHp / MaxHp; returns this value. But I don’t understand why it comes out as 0…

I don’t see your constructor again. Are you sure that anything ensure(HpBarProgress); is executed? I suspect that HpBarProgress == nullptr.

If you don’t configure the UI with C++, how does dZh0 configure the UI? I’m curious how to do it!

In blueprints: https://www.youtube.com/watch?v=PVgMkUwhtoM

However, when I initialized HpBarProgress in NativeConstruct(), it doesn’t seem to be null.

void UOLHpBarWidget::NativeConstruct()
{
	Super::NativeConstruct();

	// 해당 컨트롤을 이름으로 찾기
	HpBarProgress = Cast<UProgressBar>(GetWidgetFromName(TEXT("HpBar")));
	ensure(HpBarProgress);

	// CharacterBase의 함수 가져오기
	APawn* Player = GetOwningPlayerPawn();	// Player 가져오기
	ensure(Player);

	IOLHpInterface* PlayerInterface = Cast<IOLHpInterface>(Player);
	ensure(PlayerInterface);

	PlayerInterface->SettingHpBar(this);

	if (HpBarProgress)
	{
		HpBarProgress->SetPercent(1.f);
		UE_LOG(LogTemp, Display, TEXT("SetPercent"));
	}
	
	UpdateHpBar();
}

When I created the code as above, a log called SetPercent appeared on the screen. Does that mean it exists when the log is displayed like this?
Is it a more stable way to make it in blue print than in C++??