It looks like you want to do something like this, using PlayerPrefs to store the state between runs of the game. (This is insecure, but so is using the local system time - if a player wants to cheat, they can just change their local clock anyway, so we might as well keep things simple)
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using DateTime = System.DateTime;
using TimeSpan = System.TimeSpan;
public class CountdownAction : MonoBehaviour
{
// Assign a unique name here so two different countdowns
// don't fight for the same save location.
public string actionKey = "travelStart";
public int durationSeconds = 60;
public Text display;
public UnityEvent OnComplete;
DateTime? _startTime;
// On load, try to resume our countdown from where we left off.
void Start() {
// If we don't have a saved start time, then there's no action in progress.
// So we'll abort, and wait patiently for the player to start the action.
if (!PlayerPrefs.HasKey(actionKey))
return;
// Otherwise, load our saved start time.
// PlayerPrefs doesn't support DateTime natively, so we'll decode it from a string.
var savedString = PlayerPrefs.GetString(actionKey);
if (long.TryParse(savedString, out long ticks)) {
_startTime = new DateTime(ticks);
} else {
Debug.LogWarningFormat("Indecipherable countdown start time for {0}, restarting countdown.", actionKey);
_startTime = DateTime.Now;
}
// Wait for the action to complete, updating our countdown timer in the meantime.
StartCoroutine(WaitForCompletion());
}
// Start a new countdown.
public void StartCountdown() {
if (_startTime.HasValue) {
// Abort the countdown in progress and warn the developer - this might be a sign of a bug.
Debug.LogWarningFormat("Restarted the countdown for {0} when one was already running!", actionKey);
StopAllCoroutines();
}
// This moment is when we will measure the duration from.
_startTime = DateTime.Now;
// Save this in our player prefs, so we can recover it even if the app is closed & restarted.
PlayerPrefs.SetString(actionKey, _startTime.Value.Ticks.ToString());
// To be safe, let's save this data to disc right away, just in case our app crashes or we lose power.
PlayerPrefs.Save();
// Wait for the action to complete, updating our countdown timer in the meantime.
StartCoroutine(WaitForCompletion());
}
// This can be a win compared to Update, since it runs only when we have a countdown in progress.
IEnumerator WaitForCompletion() {
int remainingSeconds;
do {
// Compute how much time has passed since the countdown started.
var elapsed = DateTime.Now - _startTime.Value;
// Subtract the time we've waited from the total duration of the action.
remainingSeconds = Mathf.Max(durationSeconds - (int)elapsed.TotalSeconds, 0);
// Display the difference in our text field.
display.text = (new TimeSpan(0, 0, remainingSeconds)).ToString(@"hh\:mm\:ss");
// Wait a frame.
yield return null;
// Loop until the countdown is over.
} while (remainingSeconds > 0);
// We're done!
Debug.LogFormat("Action {0} has completed!", actionKey);
// Clear the countdown, since there's no longer any action in progress.
_startTime = null;
PlayerPrefs.DeleteKey(actionKey);
// Fire off any actions that were wired-up to happen once this timer completes.
// We'll assume if this countdown has any persistent effects, these handlers
// will call PlayerPrefs.Save so we don't have to double-up on it here.
if (OnComplete != null)
OnComplete.Invoke();
}
}
System.DataTime.Now.ToLocalTime().ToString("HH:mm:ss");
and I am assigning it to aActuallTime
variable. Now, when I want to travel to point B (let's say that travel takes 1 hour), then I am getting actuall time +1 hour bySystem.DateTime.Now.Hour.ToString() + 1;
. I simply substract that, the question is, how do I display, second after second how much time is left to travel to that point B? EDIT: And how do I make this run in background, when the app is OFF? \$\endgroup\$