Request: simple working Slate example

I’ve tried many Slate tutorials and none of them work. I get a ton of errors when compiling. Tried going through the code to see if I can fix it myself but I can’t figure it out. Just to see if I messed up somewhere, I followed the Hello Slate tutorial completely step by step and even copy/pasted the code. It still didn’t compile. I also tried writing from scratch based on the documentation which did compile but crashes the editor on Play. I ended up removing all the code just so I can work on other parts of the project.

I just need a simple “display text on screen and change text value during runtime” example. I’m using engine version 4.19

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.

I just want to point out that Vehicle Game implements UI using Slate.
You can get Vehicle Game through Epic Games Launcher > Learn > Vehicle Game.

Thanks! I’m looking through the code right now. It barely has any comments in it but so far I’m able to understand it. It’s so much easier to learn from example.
I’ll post here if I get stuck again.

I took a break from my project for a while because I was doing some other IRL stuff, but I’m stuck again.

I can’t seem to be able to cast to my character. I checked the Vehicle Game example and there they cast to a custom GameMode which I cannot do either.
Vehicle Game cast:


AVehicleGameMode* const MyGame = OwnerWorld->GetAuthGameMode<AVehicleGameMode>();
return MyGame->GetGameInfoText();

My game cast:


#include "SHealthWidget.h"
#include "SlateOptMacros.h"
#include "MyPlayer.h"

BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SHealthWidget::Construct(const FArguments& InArgs)
{
    WidgetOwner = InArgs._WidgetOwnerArg;

    ValueBinding.Bind(this, &SHealthWidget::GetValue);

    ChildSlot
    .VAlign(VAlign_Fill)
    .HAlign(HAlign_Fill)
    
        SNew(SOverlay)
        +SOverlay::Slot()
        .VAlign(VAlign_Top)
        .HAlign(HAlign_Left)
        
            SNew(STextBlock)
            .ColorAndOpacity(FLinearColor::Green)
            .Font(FSlateFontInfo("Arial", 26))
            .Text(ValueBinding)
        ]
    ];

}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION

FText SHealthWidget::GetValue() const {
    AMyPlayer* const myPlayer = Cast<AMyPlayer>(/* idk what to do in here?*/);
    return FText::FromString("SECONDS: --");
}

I know I’m supposed to reference the MyPlayer class inside the cast but no matter which example I follow, I just can’t seem to be able to do it. It won’t compile.
I also saw a Slate tutorial A new, community-hosted Unreal Engine Wiki - Announcements and Releases - Unreal Engine Forums that uses:



 ATutorialCharacter* character = Cast<ATutorialCharacter>(OwnerHUD->PlayerOwner->GetCharacter()); 

This example doesn’t work either. I get this error:


error C2664: 'AMyPlayer *TCastImpl<From,To,ECastType::UObjectToUObject>::DoCast(UObject *)': cannot convert argument 1 from 'AMyHUD *' to 'UObject *'

Looks like there’s a conversion issues to UObject. I’m at a loss.

I figured it out.
Every time I’m just about annoyed enough to give up for the day and after requesting help online, I suddenly figure things out.

Anyway, the problem was that I forgot to include “MyHUD.h”, so I couldn’t use OwnerHUD in my cast.
What threw me off is that Visual Studio didn’t underline it so I assumed it was right.

Here’s my cast in case anyone is curious:


FText SHealthWidget::GetValue() const {
**AMyPlayer* const myPlayer = Cast<AMyPlayer>(OwnerHUD->PlayerOwner->GetCharacter());**
    if (myPlayer == nullptr) {
        return FText::FromString("SECONDS: --");
    }
    else {
        FString ValueBinding = TEXT("SECONDS: ");
        ValueBinding.AppendInt(myPlayer->Health);
        return FText::FromString(ValueBinding);
    }
}

I’m actually getting a “pointer to incomplete class type is not allowed” error in VS but it compiles and works. If I remove GetCharacter() from the cast, the error goes away but then the cast returns a nullptr.