- Home /
Execute if statement in Update() only once
Hi!
I'm currently trying to build a simple day and night system. Every time a full cycle has passed, I want to update the day of the week. Currently I have the whole cycle working, but I noticed that in the Update() function the if statements gets executed more than once. I have tried a solution by setting a boolean to check whether or not the value is allowed to be incremented, and consequently also set this boolean as a condition for the if statement. However, none of this working.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class DayNight : MonoBehaviour {
public float CycleMins;
public float CycleCalc;
public float time;
public bool canUpdateDay = false;
public int startDay = 0;
public GameObject displayDay;
public string[] weekdays = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
// Use this for initialization
void Start () {
displayDay.GetComponent<Text> ().text = weekdays [startDay];
CycleMins = 1f;
CycleCalc = 0.1f / CycleMins * -1f;
}
// Update is called once per frame
void Update () {
if(Time.timeScale != 0){
time += Time.deltaTime;
transform.Rotate (0, 0, CycleCalc, Space.World);
}
if(time >= 1) {
int modulo = (int) time % 60;
if (modulo == 0) {
canUpdateDay = true;
}
if (modulo == 0 && canUpdateDay) {
canUpdateDay = false;
startDay += 1;
displayDay.GetComponent<Text> ().text = weekdays [startDay];
}
}
}
}
I was hoping that maybe someone on here can give me new insights in how to fix the problem, or if there perhaps is a more efficient way to implement this behaviour.
In any case, I thank you in advance.
Eric
Answer by revolute · Jun 14, 2017 at 09:19 AM
void Update () {
if(Time.timeScale != 0){
time += Time.deltaTime;
transform.Rotate (0, 0, CycleCalc, Space.World);
}
if(time >= 60) {
time = time - 60;
startDay = (startDay +1)%weekdays.Length;
displayDay.GetComponent<Text> ().text = weekdays [startDay];
}
}
Or, alternatively, you can use
startDay++;
displayDay.GetComponent<Text>().text = weekdays[startDay%weekdays.Length];
if you want to keep track of how many days have passed.
This is working, thanks a bunch. Could you perhaps explain me why my if statement got executed more than once?
Pretty sure it is because the variable time was always more or equal to 1. You never subtract anything from it, only add to it
The problem is actually that you cast the time into an integer. So once you hit the time value
"60.01" it get casted to "60" so modulo 60 is 0. The next frame time advances by the current deltaTime (at 60fps about 0.0166) so time will be 60.0266 which also leads to an integer value of 60. Since you only check the current "second" your statement will be true during that second until time reaches 61.xxx. So for about a second your statement will be true. Since you have about 60 frames per second your statement will be executed about 60 times during that second.
Thanks a lot for the explanation. That makes a lot of sense. The flaw in my logic is that I was thinking in the day and night cycle - which actually lasts 60 seconds - was directing the way Update() was operating. That also makes the cast totally unnecessary.
Answer by FunIsDangerous · Jun 14, 2017 at 09:22 AM
int currentTime = 0;
int timeDelay = 0;
int secondsToWait = 1;
void Update()
{
if (Time.time >= timeDelay) //called once per second
{
timeDelay += secondsToWait;
currentTime++;
//Other code you want to execute
}
}
This may have some errors as I am typing it on my phone. The if statement gets executed every second, but that can be tweaked by altering the secondsToWait variable
This was one of the workarounds I was thinking about. Thanks a lot! The answer provided by revolute is working for me, so I'll keep it like that :)
Answer by eskivor · Jun 14, 2017 at 12:41 PM
You can also use a coroutine (or a invoke method) for your day / night cycle, it's more appropriate for features that do not refresh at each frame, it's much less consuming than an update.
using UnityEngine;
using UnityEngine.UI;
//This using is necessary for coroutines
using System.Collections;
public class DayNight : MonoBehaviour
{
//Do not get component on an update if unnecessary
[SerializeField] Text displayedText;
[SerializeField] int dayDuration = 1;
string[] weekdays = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
int currentDayOfTheWeek;
//Do it at the moment when you want to the cycle start (on Start, Awake or other)
void Start ()
{
//If you want to use a coroutine
StartCoroutine (GoToNextDay ());
//If you want to use an Invoke method instead
//GoToNextDay2 ();
}
//Coroutine
IEnumerator GoToNextDay ()
{
DisplayText ();
//Wait dayDuration seconds (here 1 second)
yield return new WaitForSeconds (dayDuration);
RefreshDayData ();
//Continue the cycle
StartCoroutine (GoToNextDay ());
}
//Invoke method
void GoToNextDay2 ()
{
DisplayText ();
RefreshDayData ();
//Wait dayDuration seconds (here 1 second) before continuing the cycle
Invoke ("GoToNextDay2", dayDuration);
}
void RefreshDayData ()
{
//Use of a ternary operator : reset the week on purpose, no need of modulo
currentDayOfTheWeek = currentDayOfTheWeek < weekdays.Length - 1 ? currentDayOfTheWeek + 1 : 0;
//Exact Same result here as the ternary operator
/*if (currentDayOfTheWeek < weekdays.Length - 1)
{
//Go to the next day of the week
currentDayOfTheWeek ++;
}
else
{
//Reset the week
currentDayOfTheWeek = 0;
}*/
}
void DisplayText ()
{
//Debug.Log (weekdays [currentDayOfTheWeek]);
//Check to avoid errors if you have selected no UI text
if (displayedText != null)
{
//Display text
displayedText.text = weekdays [currentDayOfTheWeek];
}
}
}
Thanks for the input. It might be a better idea indeed to use the Update() solely for keeping track of time. However, in the current way I'm saving the game it became a necessity to do it this way to avoid any discrepancies between the current time, and the position of the sun.
I'm fairly new to Unity, so I'm still discovering everything it has to offer. This really helps, so thanks a lot!
Your answer

Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
For loop resetting itself, but needs to stop 2 Answers
Phyics.Raycast alternatively returns True/False with static input 2 Answers
Update functions and performance 0 Answers