I don’t know why but after going to File->Refresh VS files and rewriting my UI, it now works. Before that I went to the project folder, right clicked uproject file and generated VS files there. That didn’t seem to work. I’m guessing modules didn’t really load like they’re supposed to.
I still don’t know how to properly bind data to a Slate widget though. To tell the truth, I’ve been stuck on this for weeks… I don’t know what it is about UI’s, but I’ve been really struggling with them.
Anyway, I have a Health variable currently stored on MyCharacter which I’d like to display and update at runtime. I don’t know if it makes a difference but this character can take many hits/sec (assume 10-50 hits). Please give a clear example. I always see people post quick solutions without a proper example and it’s just frustrating trying to figure it out that way. I’ve been struggling learning and I’d appreciate the help.
Here’s what my code looks like right now:
MyHUD.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "MyHUD.generated.h"
/**
*
*/
UCLASS()
class MyGame_API AMyHUD : public AHUD
{
GENERATED_BODY()
// Initialize Slate and add widgets to Viewport. Runs before BeginPlay()
virtual void PostInitializeComponents() override;
// Reference to widget
TSharedPtr<class SHealthWidget> HealthWidget;
};
MyHUD.cpp
#include "MyHUD.h"
#include "SHealthWidget.h"
#include "Widgets/SWeakWidget.h"
#include "Runtime/Engine/Classes/Engine/Engine.h"
void AMyHUD::PostInitializeComponents()
{
Super::PostInitializeComponents();
// Assign widget to reference and expose it as HealthWidget
SAssignNew(HealthWidget, SHealthWidget).WidgetOwnerArg(this);
if (GEngine)
{
// Add widget to viewport
GEngine->GameViewport->AddViewportWidgetContent(
SNew(SWeakWidget)
.PossiblyNullContent(HealthWidget.ToSharedRef())
);
}
}]
SHealthWidget.h
#pragma once
#include "CoreMinimal.h"
#include "Widgets/SCompoundWidget.h"
class MyGame_API SHealthWidget : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SHealthWidget)
{}
SLATE_ARGUMENT(TWeakObjectPtr<class AMyHUD>, WidgetOwnerArg);
SLATE_END_ARGS()
/** Constructs this widget with InArgs */
void Construct(const FArguments& InArgs);
private:
TWeakObjectPtr<class AMyHUD> WidgetOwner;
};
SHealthWidget.cpp
#include "SHealthWidget.h"
#include "SlateOptMacros.h"
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SHealthWidget::Construct(const FArguments& InArgs)
{
WidgetOwner = InArgs._WidgetOwnerArg;
ChildSlot
.VAlign(VAlign_Fill)
.HAlign(HAlign_Fill)
SNew(SOverlay)
+SOverlay::Slot()
.VAlign(VAlign_Top)
.HAlign(HAlign_Left)
SNew(STextBlock)
.ColorAndOpacity(FLinearColor::Red)
.ShadowColorAndOpacity(FLinearColor::Black)
.ShadowOffset(FIntPoint(-1, 1))
.Font(FSlateFontInfo("Arial", 26)) // font doesn't work
.Text(FText::FromString("HEALTH: --")) // i want to display & update health here at runtime
]
];
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
MyCharacter.cpp
AMyCharacter::AMyCharacter()
{
Health = 100.0f;
}
// Called every frame
void AMyCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (Health > 0.0f)
Health = Health -DeltaTime * 1.0f; // test. reduce health overtime 1hp/s
else
Health = 0.0f;
UE_LOG(LogTemp, Warning, TEXT("Health: %d"), (int)Health); // log HP. convert to integer
}
There’s a lot more in MyCharacter.cpp but I don’t wanna spam here too much so I’m just exposing essential code. As you can see I’m simply decreasing the Health value to simulate change. Now I want to display this value in my HealthWidget.