2

I have a game where I have a queue matchup system. I would like to show the player how long they been in the current queue. It works well, until the player presses the menu/app overview button on their phone, which basically freezes the timer, and it only continues counting when the player switches back to full screen mode on their phone.
I tried looking for an app lifecycle method (somewhat like onApplicationPause, but it didn't work for me)
I also tried syncing the time by saving it in the db and then loading from the database actually, but Firebase puts on some delay, so it won't be exact. How could I solve this, so it will keep counting when the user presses their app overview/menu button on their phone?

For now, I have this code which counts the user's queue time:

private void Update() {
    if(startedCounting) {
        timer += Time.deltaTime;
        int seconds = Mathf.FloorToInt(timer % 60);
        int minutes = Mathf.FloorToInt(timer / 60);
        queueStatusText.text = "You are in the queue\n"
                               + string.Format("{0:00}:{1:00}", minutes, seconds);
    }
}
Chris G.
  • 25
  • 4

1 Answers1

2

There are different aproaches, some using static class or singleton pattern. It is better to not update this time variable each time on Update() as it takes the computation time each update (if you don't need this time for anything else). Also user doesn't need to have exact time by frames so you can avoid things like adding Time.deltaTime.

I'll show you example with static class, it can hold this information. Also note that this script is only added as C# file, but you don't attach it to any GameObject :

public static class QueueTimerInformation //It is not inheriting from MonoBehavior!
{
    private static DateTime dt;
    private static bool isRunning = false;

    //Save current DateTime when user did the action
    public static void Start()
    {
        if(!isRunning)
        {
            dt = DateTime.Now;
            isRunning = true;
        }
    }

    public static void Reset()
    {
        isRunning = false;
    }

    // This gets the actual time in String value
    // Usually it is better to return just `elapsedTime` and format it later
    public static string GetTimeElapsed()
    {
        if(!isRunning) return "00:00"; //Not running, return some default

        var elapsedTime = (DateTime.Now - dt);
        return $"{elapsedTime:mm\\:ss}";
    }
}

Usage

//On 1st time enter lobby
QueueTimerInformation.Start();

//In update method
var result = QueueTimerInformation.GetTimeElapsed();
Tatranskymedved
  • 4,194
  • 3
  • 21
  • 47
  • is it gonna work when app is in background? – Saad Anees Nov 23 '20 at 10:39
  • @SaadAnees I would say yes, because you store time when you call `Start()` and for result you only subtract it when you need it. You are not consinuously increasing the value (as in example of OP) which could be interrupted by app going to background. – Tatranskymedved Nov 23 '20 at 10:42
  • 1
    In this case this might work but in general you can't just replace the Unity `Time` with `DateTime` or a also e.g. a `StopWatch` since the Unity [timeScale](https://docs.unity3d.com/ScriptReference/Time-timeScale.html) can be altered so the virtual time runs faster or slower ;) – derHugo Nov 23 '20 at 12:28
  • @derHugo Thanks for pointing that out (I didn't even know there is something like that, nice new info). :-) – Tatranskymedved Nov 23 '20 at 16:57