Script's if statement dealing with time/float modulus remainder zero does not work properly when done with Application.LoadLevel() from other scene?
Hi, I have a problem dealing with time in this line of code:
Time.timeSinceLevelLoad % levelUpBySeconds == 0f;
It works perfectly if I'm in the scene with that script in empty gameObject called "GameManager" in "Level_Start" scene as my starting scene, but when it came from other scene ("Start_Scene") and load it or load it again ( Application.LoadLevel("Level_Start")
/ using UnityEngine.SceneManagement;
SceneManager.LoadScene("Level_Start")
) – it does not work anymore. Why is this happening?
Is Time.time
or Time.timeSinceLevelLoad
loses its precision in calculations when Application.LoadLevel() is done? or is the problem with modulus ( %
)?
My "Level_Start" scene:
You see, when I play this scene with my editor, this works properly; let's say, I set my public preference "levelUpBySeconds" to 10, it means every 10 secs will update my "LevelValue" in hierarchy added by 1, and also instantiate 1 "EnemySpawn" prefab every level rises by 1: (working properly)
My "Start_Scene" scene: if I start here or go here...
...and go to "Level_Start" scene (again) by Application.LoadLevel(); now the "LevelValue" stays at 1 forever: (not working)
Please just look for this line below:
if (Time.timeSinceLevelLoad % levelUpBySeconds == 0f && Time.timeSinceLevelLoad > 0f)
in line 38 (and also 54 which have no problem unlike line 38) of GameController.cs.
Note: I have tried Time.time - timeElapse % levelUpBySeconds == 0f
where timeElapse is a variable initiate from start with Time.time, or Mathf.Repeat(Time.timeSinceLevelLoad, levelUpBySeconds) == 0
still the same result...
GameController.cs
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class GameController : MonoBehaviour {
public float levelUpBySeconds = 60f;
public int levelUpByScore = 0;
[Range(1,100)] public int level = 1;
public Transform parentInstantiatorPrefab;
public Transform enemySpawnPrefab;
void Start () {
if (level > 0)
{
SetLevel();
for (int i = 1; i < level; i++ )
{
SetEnemySpawn();
}
}
/*else //uses "[Range(1,100)]" instead... works like a charm! ;)
{
level = 1;
SetLevel();
}*/
}
void FixedUpdate () {
SetLevelByTime();
if (Input.GetKeyUp(KeyCode.Escape)) {
Application.LoadLevel("Start_Scene");
}
}
void SetLevelByTime()
{
GameObject.Find("TimeValue").GetComponent<Text>().text = System.Math.Round(Time.timeSinceLevelLoad, 2).ToString();
if (levelUpBySeconds > 0f)
{
if (Time.timeSinceLevelLoad % levelUpBySeconds == 0f && Time.timeSinceLevelLoad > 0f)
{ /*### ^up PLEASE SEE this if statement what's going on here? ###*/
level++;
SetLevel();
}
if (Time.timeSinceLevelLoad == 10) //Edited: I just add this line of code to see...
Debug.Log(Time.timeSinceLevelLoad.ToString()); //As mention, does not work/display when loaded from other Scene as start scene!
if (Time.timeSinceLevelLoad == 20) //Edited: I just add this line of code to see...
Debug.Log(Time.timeSinceLevelLoad.ToString()); //As mention, does not work/display when loaded from other Scene as start scene!
}
}
public void SetLevelByScore(int currentScore)
{
if (levelUpByScore > 0f)
{
if (currentScore % levelUpByScore == 0 && Time.timeSinceLevelLoad > 0f)
{ /*### ^up PLEASE SEE ALSO this if statement, it works perfectly as we expected! ###*/
level++;
SetLevel();
}
}
}
void SetLevel ()
{
GameObject.Find("LevelValue").GetComponent<Text>().text = level.ToString();
SetEnemySpawn();
}
void SetEnemySpawn()
{
Instantiate(enemySpawnPrefab, parentInstantiatorPrefab);
}
}
ScoreController.cs (Extra, just look, no problem here)
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class ScoreController : MonoBehaviour {
private int currentScore = 0;
private int highScore = 0;
void Start ()
{
if (PlayerPrefs.HasKey("highScore"))
{
highScore = PlayerPrefs.GetInt("highScore");
}
else
{
PlayerPrefs.SetInt("highScore", 0);
}
GameObject.Find("HighScoreValue").GetComponent<Text>().text = highScore.ToString();
SetScore();
}
public void AddScore ()
{
currentScore++;
if (currentScore > highScore)
{
PlayerPrefs.SetInt("highScore", currentScore);
}
SetScore();
}
void SetScore()
{
GameObject.Find("ScoreValue").GetComponent<Text>().text = currentScore.ToString();
GameObject.Find("GameManager").GetComponent<GameController>().SetLevelByScore(currentScore);
}
}
StartSceneController.cs (Extra, just look, no problem here)
using UnityEngine;
using System.Collections;
public class StartSceneController : MonoBehaviour {
void Update () {
if (Input.GetKeyUp(KeyCode.Return) || Input.GetKeyUp(KeyCode.Mouse0)) {
Application.LoadLevel("Level_Start");
}
if (Input.GetKeyUp(KeyCode.Escape)) {
Application.Quit();
}
}
}
Answer by Ultimate360 · Jan 15, 2017 at 04:34 AM
Hey, I can have this code instead:
GameController.cs
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class GameController : MonoBehaviour {
public float levelUpBySeconds = 60f;
public int levelUpByScore = 0;
private int score = 0; //added: global variable for storing pass paramenter 'currentScore'.
[Range(1,100)] public int startLevel = 1; //player set starting level...
private int addLevel = 0; //add level by 1 over time in game-play...
public Transform parentInstantiatorPrefab;
public Transform enemySpawnPrefab;
void Start () {
if (startLevel > 0)
{
SetLevel();
for (int i = 1; i < startLevel; i++ )
{
SetEnemySpawn();
}
}
/*else //uses "[Range(1,100)]" instead... works like a charm! ;)
{
startLevel = 1;
SetEnemySpawn();
}*/
}
void FixedUpdate () {
SetLevelByTime();
}
void SetLevelByTime()
{
GameObject.Find("TimeValue").GetComponent<Text>().text = System.Math.Round(Time.timeSinceLevelLoad, 2).ToString();
if (levelUpBySeconds > 0f)
{
/* //ineffective if statement, commented out...
if (System.Math.Round((Time.timeSinceLevelLoad % levelUpBySeconds), 2) == 0f && Time.timeSinceLevelLoad > 0f)
{
addLevel++;
SetLevel();
}
*/ //uses this if statement instead... works perfectly!
if (levelUpByScore > 0 && Time.timeSinceLevelLoad + (levelUpBySeconds * (startLevel - 1)) + (levelUpBySeconds * Mathf.Floor(score / levelUpByScore)) > levelUpBySeconds * (startLevel + addLevel))
{
addLevel++;
SetLevel();
}
//for testing only... Debug.Log();
if (Time.timeSinceLevelLoad == 10)
Debug.Log(Time.timeSinceLevelLoad.ToString());
if (Time.timeSinceLevelLoad == 20)
Debug.Log(Time.timeSinceLevelLoad.ToString());
}
}
public void SetLevelByScore(int currentScore)
{
if (levelUpByScore > 0f)
{ //modulus(%) have no problem with int types calculations!
if (currentScore % levelUpByScore == 0 && Time.timeSinceLevelLoad > 0f)
{
addLevel++;
SetLevel();
score = currentScore; //stored pass paramenter 'currentScore' to this global
//variable 'score'...
}
}
}
void SetLevel ()
{
GameObject.Find("LevelValue").GetComponent<Text>().text = (startLevel + addLevel).ToString();
SetEnemySpawn();
}
void SetEnemySpawn()
{
Instantiate(enemySpawnPrefab, parentInstantiatorPrefab);
}
}
I conclude that either the Time or the modulus (%) or both have the problem with precision calculation with comes to float types after using Application.LoadLevel().
For simpler concept:
Note:
'run_time_value' (or Time.time) is constantly increasing over time...
You can just simply change this:
if (run_time_value % set_value == 0)
{
...your code here...
}
... to ...
private int increment; //declared variable 'increment'...
void Start () {
increment = 0; /* or 1 */ //initiate 'increment' to 0; choice 1 if you don't want instant execution...
}
...
...some code here...
...
(
/*if 'run_time_value' is equal or slightly more than 'set_value': it become true, if it succeed,
*then 'increment++;' is applied to multiply the 'set_value' for another add on 'set_value'...*/
if (run_time_value >= set_value * increment)
{
...your code here...
increment++;
}
)
...
Your answer
Follow this Question
Related Questions
How to make a timer that counts up in seconds, as an int? 5 Answers
prefab time delay 1 Answer
Why is AudioSettings.DspTime so inaccurate? 1 Answer
Pause scene?!? 1 Answer