- Home /
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;
}
}
Haven't read it all but it was too obvious to not ask about. Why are you always setting quitGame = true;
? It makes the IF statement that follows it redundant.
I saw something like it, in another thread but it wouldn't work so i just changed it although i still get some errors.
Walk us through how you expect this to work and how OnApplicationQuit works.
Answer by Bunny83 · Mar 30, 2014 at 03:54 PM
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.
Tested it in Unity and had to fix a few things ;) $$anonymous$$ainly the UnixTimestamp method which i took from StackOverflow. Just had to add the System namespace before $$anonymous$$ath and DateTime of course.
From my tests it works pretty well. I just set a 30 seconds interval and quit the game while i'm writing this comment. So i will check if the lives regenerate properly and then finish this comment ;)
So, yes, it's working ;) However It might be a good idea to call Regenerate in Start a couple of times manually so when the app is restarted it regenerates the lives immediately.
So you might want to add at the end of Start:
for(var i = lives; i < maxLives; i++)
{
Regenerate();
}
Thanks you so much! It works, the only problem is that, it generates "lives" every second ins$$anonymous$$d of every 30 $$anonymous$$ute.
No, it doesn't. It just generates 1 life every second after you restarted your game and several 30-$$anonymous$$ute-periods have passed already. It will regenerate 1 life every 30 real-life-$$anonymous$$utes.
Again, if you use up all your lives, quit your game and come back after 6h this script will generate 1 life for every 30-$$anonymous$$ute-period that has passed since the last time. So 6h (would be 12x30$$anonymous$$) is enough to restore all (5) lives.
$$anonymous$$ake sure the Interval is set to 1800 seconds in the inspector.
Okay it's just because i want to display the "lives" and the time left, so i have made it display "5 lives" if lives is five and so on for four,three,two etc. but when i play the game and lose a level, it goes from 5 lives to 4 lives and then a second after it goes to 5 lives again. Is there a way to make it do this, but only show the displayed regeneration every 30 $$anonymous$$ute, while everything else still works?
This is the code for displaying the lives.
function OnGUI () {
if (lives == 5) {
GUI.skin = Energy5skin;
if (GUI.Button(Rect(10,20,80,40),"")){
}
}
if (lives == 4) {
GUI.skin = Energy4skin;
if (GUI.Button(Rect(10,20,80,40),"")){
}
}
}
Are you sure you used "SubtractLife()" to reduce lives like i said in my answer? Usually i would implement this in C# and use a property for "lives". Even i know UnityScript now supports properties as well, i can't remember the exact syntax ;)
You can use SubtractLife() even in an if condition like this:
if (SubtractLife())
{
// Yes we still had a life and lives has been reduced by 1
}
else
{
// No more lives
}
Your answer
Follow this Question
Related Questions
javascript System time and date? 3 Answers
How to measure the real time differential between application runs 0 Answers
Restart game script. 1 Answer
How to load saved data from another scene? 2 Answers
Save and load data with Javascript... 0 Answers