GUI Manager - How to update the widget when Character asks for it - c++

I am using an ActorComonent as GUIManager, and at BeginPlay of the GameMode, it puts on screen the widgets I want.
For example, in my UGUI_Manager, I have a UserWidget which works as a HealthBar. In the BP of my Health Bar, I have a function that updates it when the character tells the GUI Manager to update it.

Alas, I have two problems:

  1. Even while debugging, if I give the BP event an input between 0,2 and 1 (never 0) it always looks empty;
  2. I have no idea how to make the Character call the GUI Manager to update the function.

Maybe I’m just overthinking it, but this is the way they asked me to work on it…

What I have now:

UFPS_GUIManager::UFPS_GUIManager()
{
	// Set this component to be initialized when the game starts, and to be ticked every frame.  You can turn these features
	// off to improve performance if you don't need them.
	PrimaryComponentTick.bCanEverTick = true;
	PrimaryComponentTick.bStartWithTickEnabled = false;
}

// Called when the game starts
void UFPS_GUIManager::BeginPlay()  //Create setup function to avoid beginplay
{
	Super::BeginPlay();
}

void UFPS_GUIManager::SetupGUIManager()
{
	HealthBar = CreateWidget<UUserWidget>(GetWorld(), HealthBarClass);
	if (HealthBar)
	{
		HealthBar->AddToViewport();
	}
}

void UFPS_GUIManager::UpdateBar(float HealthPercent)
{
	if (HealthBar)
	{
		UFunction* Function = HealthBar->FindFunction("HealthHasChanged");
		if (Function)
		{
			HealthBar->ProcessEvent(Function, &HealthPercent);
			UE_LOG(LogTemp, Warning, TEXT("Character gave me the health: %f"), HealthPercent);
		}
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("Function not found"));
		}
	}
	else
	{
		UE_LOG(LogTemp, Warning, TEXT("HealthBar is null"));
	}

	/*HealthBar->ProcessEvent(Function, &HealthPercent);*/
}

void UFPS_GUIManager::ShowHealthBar()
{
	if (HealthBar)
	{
		HealthBar->SetVisibility(ESlateVisibility::Visible);
	}
}

void UFPS_GUIManager::HideHealthBar()
{
	if (HealthBar)
	{
		HealthBar->SetVisibility(ESlateVisibility::Hidden);
	}
}
AFPS_GameModeBase::AFPS_GameModeBase()
{
	PlayerControllerClass = AMyCharacterController::StaticClass();
	static ConstructorHelpers::FClassFinder<APawn> PlayerPawnClassFinder(TEXT("/Game/FirstPerson/Blueprints/BP_MyCharacter"));
	DefaultPawnClass = PlayerPawnClassFinder.Class;
    
    GUIManager = CreateDefaultSubobject<UFPS_GUIManager>(TEXT("GUIManager"));
}

void AFPS_GameModeBase::BeginPlay()
{
    Super::BeginPlay();

    if (GUIManager)
    {   
            GUIManager->SetupGUIManager();

            GUIManager->ShowHealthBar();

            GUIManager->UpdateBar(1.0f);
     
    }
    else
    {
        UE_LOG(LogTemp, Error, TEXT("GUIManager is nullptr."));
    }
}
AMyCharacter::AMyCharacter(const FObjectInitializer& ObjectInitializer)
    :Super(ObjectInitializer.SetDefaultSubobjectClass<UCustomMovementComponent>(ACharacter::CharacterMovementComponentName))
{
    PrimaryActorTick.bCanEverTick = true;

    GetCapsuleComponent()->InitCapsuleSize(55.f, 96.0f);

    // Create a CameraComponent	
    FirstPersonCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
    FirstPersonCameraComponent->SetupAttachment(GetCapsuleComponent());
    FirstPersonCameraComponent->SetRelativeLocation(FVector(-10.f, 0.f, 60.f)); // Position of the camera
    FirstPersonCameraComponent->bUsePawnControlRotation = true;

    UE_LOG(LogTemp, Warning, TEXT("Character created. Initial Health: %f"), Health);

    CustomMovementComponent = Cast<UCustomMovementComponent>(GetCharacterMovement());

    GUIManager = CreateDefaultSubobject<UFPS_GUIManager>(TEXT("GUIManager"));
}

float AMyCharacter::GetHealth()
{
    return Health/MaxHealth;
}

void AMyCharacter::UpdateHealthBar()
{
    if (GUIManager)
    {
        GUIManager->UpdateBar(GetHealth());
    }
}

guiCPP.zip (94.8 KB)

Use the AHud class with it’s intended use. No need for making managers.

1 Like

Is it a better practice?

Yes. That is why epic coded the AHud class

And would you suggest creating a Custom User Widget class, to better track all the custom widgets, or do you think it’d be useless?

Better to use event dispatchers (blueprint) / c++ delegates to send information updates to many classes in the place of a monolith class.

edit: Ok just noticed the custom user widget. Yes you can use a more complex base user widget for interaction with c++ or you can make your function a UFUNCTION(BlueprintImplementableEvent) then do the further logic in the widget.
There are a couple of ways you can tackle the problem.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.