Subtract time from time

I have this code, which has an integer of 5 and then a countdown which counts down from 30 minutes. If you loose a level, it subtracts one from the integer and then every 30 minute, it adds one to the integer. Now the problem is, that when i close the game(it’s for iOS) and i open it again 10 seconds later, the integer has been set back to 5 and the timer is set back to 30 and isn’t running.

I have tried making a bit of the code when closing the game and loading it, but i can’t seem to figure out how to subtract the time on quit with the time on load and then find the difference and subtract that with what the “counter” was on quit.

Here is my script.

 static var energyObj : int = 5;
    static var showC : boolean = true;
    private static var created = false;
    var counter : float;
    var quitGame : boolean = false;
    
    function Start()
    {
    counter = 1800;
    }
    
    function Update () {
     
     if (energyObj < 5) {
      counter -= Time.deltaTime;
         if(counter <= 0){
            energyObj += 1;
            counter = 1800;
            Debug.Log("Energy is " + energyObj); 
    		}
     	}
     	
     energyObj = Mathf.Clamp(energyObj, 0, 5);
     
     if (energyObj > 5) {
     		energyObj = 5;
    	}
     if (energyObj < 0) {
     		energyObj = 0;
     	}
    }
    
    function OnGUI () {
    
    if (energyObj < 5) {
    	var minutes = Mathf.Floor(counter / 60).ToString("00");
    	var seconds = (counter % 60).ToString("00");
    	if (showC == true){
    	GUI.Label(new Rect(100,40,400,40),"To Next: " + minutes + ":" + seconds);
    		}
    	}
    
    }

Here is the code for closing and loading the game.

    function OnApplicationQuit() {
	quitGame = true;
	
	if (quitGame == true) {
		PlayerPrefs.SetFloat("lastCounter",counter);
		PlayerPrefs.SetInt("lastEnergyObj",energyObj);
		PlayerPrefs.SetString("lastTimeSaved",System.DateTime.Now.ToBinary().ToString());
		Debug.Log("time now is : " + System.DateTime.Now);
        Debug.Log("energy is : " + energyObj);
        Debug.Log("last counter is: " + counter);
    } else if (quitGame == false) {
    	PlayerPrefs.GetInt("lastEnergyObj");
    	PlayerPrefs.GetString("lastTimeSaved");
    	PlayerPrefs.GetFloat("lastCounter");
    	var timeDifference : float = System.DateTime.Now - lastTimeSaved;
    	counter = timeDifference - counter;
    	ernergyObj = lastEnergyObj;		

     }
 }

You don’t want to work with relative time values but using absolute (date-)time values of the next timeout. It’s usually the simples to use the unix timestamp for such things since it’s a single value which can easily modified (adding / subtracting time).

Also you shouldn’t rely on OnApplicationQuit on mobile. In most cases it’s possible to terminate an app. It’s better to set those playerpref values during the game.

A script which provides a live-counter which automatically regenerates 1 live every 30 min could be done like this:

//UnityScript

var maxLives = 5;
var lives = 5;
var RegenInterval = 1800; // 30min * 60

var nextLife = 0;

function UnixTimestamp() : int
{
    return System.Math.Truncate((System.DateTime.UtcNow.Subtract(new System.DateTime(1970, 1, 1))).TotalSeconds);
}

function SecondsRemaining() : int
{
    return Mathf.Max(0,nextLife - UnixTimestamp());
}

function Start()
{
    lives    = PlayerPrefs.GetInt("lives", maxLives);
    nextLife = PlayerPrefs.GetInt("nextLife", 0);
    InvokeRepeating("Regenerate",1,1);
}

function Regenerate()
{
    var current = UnixTimestamp();
    if (lives < maxLives)
    {
        if (current >= nextLife)
        {
            AddLife();
            nextLife += RegenInterval; // important to do this incremental 
            
            PlayerPrefs.SetInt("nextLife", nextLife);
        }
    }
}
function AddLife()
{
    if (lives < maxLives)
    {
        lives++;
        PlayerPrefs.SetInt("lives", lives);
    }
}

function SubtractLife() : boolean
{
    if(lives <= 0)
        return false;  // no more lives left
    if (lives == maxLives)  // if we have full lives make sure the time get set to an absolute timeout
    {
        nextLife = UnixTimestamp() + RegenInterval;
    }
    PlayerPrefs.SetInt("nextLife", nextLife);
    lives--;
    PlayerPrefs.SetInt("lives", lives);
    return true;
}

ps: Haven’t tested it yet, but it should work. This script will automatically regenerate 1 life every “RegenInterval” seconds, even when the app is closed. When the app loads it reads out the last state of the “lives” and “nextLife” variables.

Keep in mind when you want to subtract a life to use the “SubtractLife” method and if you want to add a life use the AddLife method. They will ensure that the current life-counter is saved properly.

In the case that the user has used up all lives (so “lives” is 0 and nextLife is a time somewhere within the next 30 min) and he quits the app and comes back after 2 hours, the app will load the lives value “0” and the update time which now lies in the past. The Regenerate method(which checks every second if it should regenerate a life) will regenerate a life every second until it hits the value 4 (2h == 4 lives) and the countdown will continue to count down.