- Home /
Why doesn't this energy refill code work when I'm not on the game?
Hi guys! So I have written an energy refill script:
if(Reference.energy < 20 && PlayerPrefs.GetInt("Key_2") == 0)
{
PlayerPrefs.SetString("Key_1", DateTime.Now.ToString());
PlayerPrefs.SetInt("Key_2", 1);
Debug.Log("Refill");
}
if(PlayerPrefs.GetInt("Key_2") == 1)
{
refillTime = DateTime.Now.Subtract(DateTime.Parse(PlayerPrefs.GetString("Key_1")));
if(refillTime.TotalSeconds > 5)
//Refill time of 5 seconds for testing purposes
{
Reference.energy += (int)refillTime.TotalSeconds / 5;
counter.text = "Energy: " + Reference.energy + "/20";
PlayerPrefs.SetInt("Key_0", Reference.energy);
PlayerPrefs.SetInt("Key_2", 0);
}
It works beautifully when I'm playing the game, every five seconds the energy counter goes up by 1. However, if I exit my game for 20 seconds, and the energy should increase by 4, it still stays on the same amount as it was when I exited my game. WHy is this happening and how can I fix it? Thanks!
Whenever I have problems like this, I use Debug.Log to log out almost every single variable I have. I cannot spot the mistake, but once you see how the variables change, are saved, etc it will be far more obvious. The problem may very well be when this code is executed
EDIT: also, you should probably not name variables $$anonymous$$ey_1 and $$anonymous$$ey_2, give them more self-explenatory names, or add more comments to your code
Answer by FunIsDangerous · Jun 12, 2017 at 09:02 AM
I just did some testing and this seems to work perfectly, it should also be more efficient than your version.
using System;
using UnityEngine;
public class EnergyTest : MonoBehaviour {
int energy;
int nextTimeToGiveEnergy = 5;
void Start()
{
energy = PlayerPrefs.GetInt("energy"); //get energy from Prefs
int timeOffline = (int)DateTime.Now.Subtract(DateTime.Parse(PlayerPrefs.GetString("lastTimeEnergyGiven"))).TotalSeconds; //calculate time offline as an int
while (timeOffline > 5 && energy < 20) //doing this so we can limit energy to 20
{
energy += 1;
timeOffline -= 5;
}
PlayerPrefs.SetInt("energy", energy); //save energy again
PlayerPrefs.SetString("lastTimeEnergyGiven", DateTime.Now.ToString()); //save the time, because the user just got energy
Debug.Log(energy); //testing purposes
}
void Update () {
if (Time.time >= nextTimeToGiveEnergy) //Time.time is incremented every second, with 0 being the second the game began.
{ //Code is ran every 5 seconds, it also is more efficient than DateTime.now
nextTimeToGiveEnergy += 5; //It will run again in 5 seconds
energy++; //increment energy by one
PlayerPrefs.GetInt("energy", energy); //save energy
PlayerPrefs.SetString("lastTimeEnergyGiven", DateTime.Now.ToString()); //save the last time energy was given, cannot be Time.time
Debug.Log(energy); //testing purposes
}
}
}
There are some obvious problems that would show when the energy is refilled less frequently, let's say 5 minutes. For example, if you were offline for 3 minutes, when logging in the timer would reset. This is fairly easy to fix, but I'll leave the code up to you.
I am also not sure if having the loop this way is faster than having a coroutine with an infinite loop and a yield new WaitForSeconds(5)
Just realised, another problem is the fact that the first time you run it, it will throw an error, because PlayerPrefs.GetString("lastTimeEnergyGiven") will return null, and Date time won't be able to cast it
Hi, thanks for sharing,
PlayerPrefs.GetInt("energy", energy); //save energy
in this line you are not saving energy it should be
PlayerPrefs.SetInt("energy", energy); //save energy
Also I am testing it and I am getting this issue
FormatException: String was not recognized as a valid DateTime.
Related to this line:
int timeOffline = (int)DateTime.Now.Subtract(DateTime.Parse(PlayerPrefs.GetString("lastTimeEnergyGiven"))).TotalSeconds; //calculate time offline as an int
Yes the first thing was probably a typo / copy&paste error. The error you get is pretty obvious. The first time your code executes there is not "lastTimeEnergyGiven" stored in the playerprefs. A simple solution is to use the second parameter of the GetString method. You can specify a default value that is returned when the key is not found. So just make sure you pass a valid time string. It's also recommended to split the line up into clearer and shorter sub parts. That helps when reading the code and also helps debugging:
var time = DateTime.Now;
var storedTime = PlayerPrefs.GetString("lastTimeEnergyGiven", time.ToString());
int timeOffline = (int)time.Subtract(DateTime.Parse(storedTime)).TotalSeconds;
Here we simply use the current time as the default value for the GetString method. So if there is no lastTimeEnergyGiven we simply get the current time as string. That way the parsing doesn't fail. However a better approach in general is to use DateTime.TryParse
var time = DateTime.Now;
DateTime lastTime;
if (!DateTime.TryParse(PlayerPrefs.GetString("lastTimeEnergyGiven"), out lastTime))
lastTime = time;
int timeOffline = (int)time.Subtract(lastTime).TotalSeconds;
Answer by kornstar83 · Jun 10, 2017 at 03:47 PM
maybe you are running into an issue when casting it as an int. try changing line 13 to this,
Reference.energy += Mathf.FloorToInt(refillTime.TotalSeconds / 5);
Your answer
Follow this Question
Related Questions
Help With Boost Bar for Game 0 Answers
How to save DateTime in a list 1 Answer
Energy refill script bug fix 2 Answers
Fast Forward Time like in the Sims 3 using DateTime 1 Answer
Energy refill script bug fix 0 Answers