Counting down in UI

Hi!

I took a bit of a deeper dive into the “Lose” UI, and made the seconds to restart count down :slight_smile:

The first step was to name my bottom text box in the WBP_LoseScreen. This can be done at the top of the Details panel when the text box is selected;
image
My name was “TB_RestartTimer”. We’ll need this for getting the address of it later.

Then, to the C++ code!
The idea is to have a timer that calls a function several times, and then inside that function, we can count down and update the text. This example helped me get the gist of it.
We can re-write our timer setting as

//Takes timer handle, object we want to call on, method to call, interval between calls, and whether to loop or not
GetWorldTimerManager().SetTimer(restartTimer, this, &AShooterPlayerController::TimerEvent, 1.0, true);

As you see, I’ve made a TimerEvent function, we’ll get back to that soon.
We set the timer to call this function on repeat at 1-second intervals.
Now, we’ll have to call our loseScreen widget within the function, so let’s make it a member variable of the ShooterPlayerController over in the .h file. We will also need some way of keeping track of how many times we have called the function (so we know when the defined nubmer of seconds have passed), so let’s make a varaible for that as well. I now have this in my ShooterPlayerController.h:

	FTimerHandle restartTimer;
	UUserWidget * loseScreen;
	float timerCount;

And this is all we need, really! Let’s initialise the timerCount variable to the value of restartDelay (which is what I called the UPROPERTY we set in the lecture) before we set the timer; timerCount = restartDelay. This way, we can start counting down the time starting from restartDelay. Note that the way I’ve done it, there’s an implicit conversion from float to int here.

Finally, let’s write a TimerEvent function. My function in ShooterPlayerController.cpp looks like this:

void AShooterPlayerController::TimerEvent()
{   
    // Decrease timerCount by 1
    timerCount--;

    // Update the text on the screen
    UE_LOG(LogTemp, Warning, TEXT("Time remaining: %i"),timerCount);
    UTextBlock * bottomText = Cast<UTextBlock>(loseScreen->GetWidgetFromName(TEXT("TB_RestartTimer")));
    if(bottomText != nullptr) {
        FString outString = FString::Printf(TEXT("Game will restart in %i seconds..."),timerCount);
        bottomText->SetText(FText::FromString(outString));
    }

    // Actually do the restart when we've reached zero
    if (timerCount <= 0) {
        APlayerController::RestartLevel();
    }
}

I start by decreasing the timer count by 1, and then we get into updating the text box content.
First of all, we need to get a pointer to it. There is this handy function called GetWidgetFromName that helps us here; give it your text box name as an argument.
Then we do a nullptr check just to be sure, and of we have it, we construct an FText (there are many ways to do this, but I chose the path over an FString as I didn’t see a need to go fancy and dig into localisation here). I got the info about formatting of an FString from here.

Finally, if the counter has reached zero, we call the APlayerController::RestartLevel();, and the level restarts!

And that’s basically it :slight_smile:
I also updated the initial setting of the text as the widget was created, just to make it more flexible with any restart delay we might set, so i also update the bottomText before we display the UI for the first time. This isn’t strictly necessary though, but does make it a bit more flexible.
So, in GameHasEnded(), I do this:

    //Set the timer counter
    timerCount = restartDelay;

    //Spawn lose UI. Needs owner object (e.g. playercontroller), and class to create
    loseScreen = CreateWidget(this, loseScreenClass);
    //Make it visible. Add it to the viewport
    if (loseScreen != nullptr) {
        UTextBlock * bottomText = Cast<UTextBlock>(loseScreen->GetWidgetFromName(TEXT("TB_RestartTimer")));
        if(bottomText != nullptr) {
            FString outString = FString::Printf(TEXT("Game will restart in %i seconds..."),timerCount);
            bottomText->SetText(FText::FromString(outString));
        }
        loseScreen->AddToViewport();
    }

and then I set the timer as described above.

In the end, I get this kind of thing, with the time in the UI counting down the seconds until restart!

Kind regards,
Håkan

Privacy & Terms