Archive 19/01/2023.

Countdown Timer - UI

capelenglish

I am trying to create a countdown timer using Text. When the user presses a certain key, I want the seconds value to update on the screen as it counts down from 5. The code below uses a Urho3D::Timer, but it doesn’t display the text on the screen until after the timer has counted all the way down. Any suggestions would be appreciated.

ResourceCache* cache = GetSubsystem<ResourceCache>();
	UI* ui = GetSubsystem<UI>();
	// Construct new Text object, set string to display and font to use
	Text* instructionText = ui->GetRoot()->CreateChild<Text>();
	instructionText->SetFont(cache->GetResource<Font>("Fonts/Anonymous Pro.ttf"), 48);
	instructionText->SetColor(Color(0.0f, 1.0f, 0.0f));
	instructionText->SetTextAlignment(HA_CENTER);
	instructionText->SetHorizontalAlignment(HA_CENTER);
	instructionText->SetVerticalAlignment(VA_CENTER);
	instructionText->SetPosition(0, ui->GetRoot()->GetHeight() / 4);
	instructionText->SetText("Countdown");
	// Add Text instance to the UI root element
	GetSubsystem<UI>()->GetRoot()->AddChild(instructionText);

	for (int i = 5; i >= 1; i--)
	{
		instructionText->SetText("Countdown " + String(i));
		Timer tmr = Timer();
		do {} 
		while (tmr.GetMSec(false) < 1000);
		// reset the timer
		tmr.Reset();

		if (DEBUG) URHO3D_LOGINFOF("Tick %d", i);
	}
Eugene

The program cannot draw countdown because Engine doesn’t draw anything until you exit all your functions and let internal rendering routines go.

Lumak

Understanding a bit about Urho3D’s game loop might help - I’ll keep it short.
Like many game engines, Urho3D’s game loop consists of (listing from Urho3D/Core/CoreEvents.h):

1 - E_BEGINFRAME, BeginFrame
2 - E_UPDATE, Update
3 - E_POSTUPDATE, PostUpdate
4 - E_RENDERUPDATE, RenderUpdate
5 - E_POSTRENDERUPDATE, PostRenderUpdate
6 - E_ENDFRAME, EndFrame

For simplicity, treat these as sequential stages that gets processed every frame , and in each stage processes some subsystem required for that stage, e.g graphics and UI needs to render in stage 4 .
Most of the user’s game logic ends up in stage 2, in Update(). However, if your Update stage looks like:

Update-Stage()
{
  for-loop(...)
  {
    do{} while (somevalue == valid);
  }
}

rest of the stages are waiting their turn to process but cannot get there until update() completes.

Better method for your countdown in Update()

if (countDownTimer_.GetMSec(false) > 1000 && countDown_ > 0)
{
  instructionText->SetText("Countdown " + String(--countDown_));
  countDownTimer_.Reset();
}
capelenglish

@Lumak , Thanks for this answer, it is very helpful. This is my first gaming engine and I’m still trying to get my head wrapped around how everything works.

capelenglish

@Lumak , using your suggested approach, I was able to implement my countdown timer exactly as I wanted to. Thanks again!

I would mark this issue [SOLVED] but I don’t see any buttons or links to do so.

Eugene

Here should be one more button:
But maybe topics in this forum category doesn’t have such feature, I’m not 100% sure.
image

Modanung

Indeed only topics in the Support category can be marked solved .

capelenglish

It appears that only certain users have the checkbox to mark a reply as solving the problem. For example, neither @Lumak nor I have this checkbox but @Eugene and @Modanung do. Not sure what’s up with that…

Modanung

I did have to change the topic’s category (allowed at trust level 4) first and refresh the page for the button to appear. :slight_smile: