Game Level Best Time

hi, with the following script , game level time is calculated and displayed.

however how may i have also the best time also available?

for the bet time there is a ui text and i cannot figure it out how to pass the most lowest time when user could win the current game level.

here is the script :

public class GameLevelInfo : MonoBehaviour
{
    [SerializeField]
    private Text moneyAmountText;

    [SerializeField]
    private Text gameTimeText;

    [SerializeField]
    private Text gameBestTimeText;

    public static float timer;



    private void Update()
    {
        timer += Time.deltaTime;

        int minutes = Mathf.FloorToInt(timer / 60F);
        int seconds = Mathf.FloorToInt(timer - minutes * 60);

        gameTimeText.text = string.Format("{0:0}:{1:00}", minutes, seconds);

        moneyAmountText.text = GlobalValues.money.ToString();
    }
    
}

as soon as game level is over or it is game win , then the above script is running.

any help would be appreciated.

   [SerializeField]
    private Text gameTimeText;

    [SerializeField]
    private Text gameBestTimeText;

    public static float timer;



    private void Update()
    {
        timer += Time.deltaTime;

        int minutes = Mathf.FloorToInt(timer / 60F);
        int seconds = Mathf.FloorToInt(timer - minutes * 60);

        gameTimeText.text = string.Format("{0:0}:{1:00}", minutes, seconds);

        if (timer > PlayerPrefs.GetFloat("BestScore"))
        {
            PlayerPrefs.SetFloat("BestScore", timer);
        }

        //show the high score
        gameBestTimeText.text = ""+((int)PlayerPrefs.GetFloat("BestScore"));

        moneyAmountText.text = GlobalValues.money.ToString();
    }

this is working but it does not show like minutes and seconds. how to fix the time format for best time ui text?

  private void Update()
    {
        timer += Time.deltaTime;

        int minutes = Mathf.FloorToInt(timer / 60F);
        int seconds = Mathf.FloorToInt(timer - minutes * 60);

        gameTimeText.text = string.Format("{0:0}:{1:00}", minutes, seconds);

        if (timer > PlayerPrefs.GetFloat("BestScore"))
        {
            PlayerPrefs.SetFloat("BestScore", timer);
        }

        //show the high score
        TimeSpan bestGametTime = TimeSpan.FromSeconds(PlayerPrefs.GetFloat("BestScore"));
        gameBestTimeText.text = bestGametTime.Minutes + " : " + bestGametTime.Seconds;

        moneyAmountText.text = GlobalValues.money.ToString();
    }

this is now working but the problem is i need to save the best time in each game level as the lowest time when user wins the game. but now only the longest time is saved and showed. how can i fix that ?

you check in your if on line 10, if your time is greater then the best score and if it is you set it has new best score. i think you have to check, if the time(r) is smaller then the current best time:

if (timer < PlayerPrefs.GetFloat("BestScore"))
{
    PlayerPrefs.SetFloat("BestScore", timer);
}
1 Like

this is the point!
so the very first time game is running , actually there is not a best game time. i did like this for that i start method

 [SerializeField]
    private Text gameTimeText;

    [SerializeField]
    private Text gameBestTimeText;

    public static float timer;
    private float gameBestTime;


    private void Start()
    {
        gameBestTime = PlayerPrefs.GetFloat("BestScore", 0);
    }

    private void Update()
    {
        timer += Time.deltaTime;

        int minutes = Mathf.FloorToInt(timer / 60F);
        int seconds = Mathf.FloorToInt(timer - minutes * 60);

        gameTimeText.text = string.Format("{0:0}:{1:00}", minutes, seconds);

        if (timer > PlayerPrefs.GetFloat("BestScore"))
        {
            PlayerPrefs.SetFloat("BestScore", timer);
        }

        //show the high score
        TimeSpan bestGametTime = TimeSpan.FromSeconds(PlayerPrefs.GetFloat("BestScore"));
        gameBestTimeText.text = bestGametTime.Minutes + " : " + bestGametTime.Seconds;
        gameBestTimeText.color = Color.yellow;

        moneyAmountText.text = GlobalValues.money.ToString();
    }

and now only on game win condition , i need a comparision if best time is the lowest amongst , then yes set and save it.

how can i do it ? i am confused. please help ^^

for that you need a flag which you set, if the game was finished/won:

private bool wonGame;

private void Update()
{
    // your current timer code

    if (wonGame)
    {
        if (timer > PlayerPrefs.GetFloat("BestScore")
        {
             PlayerPrefs.SetFloat("BestScore", timer);
         }
    }
}

to set the value of the flag to true, you need a method or something in your Upload() that is called/triggered as soon as the game is finished

1 Like

so still (timer > or (timer < ???

because i need the lowest time which user won the game level to be registerd.

how really do that?

ah yes sure still < sry, didn´t copy it, but typed it again. if you want the lower one it´s always < :wink:

1 Like

this is not working and each time level is finished , best time is zero. why?

using UnityEngine;
using System;
using UnityEngine.UI;

public class GameLevelInfo : MonoBehaviour
{
    [SerializeField]
    private Text moneyAmountText;

    [SerializeField]
    private Text gameTimeText;

    [SerializeField]
    private Text gameBestTimeText;

    public static float timer;
    private float gameBestTime;

    // set it true when game win is done.
    public static bool wonGame = false;



    private void Start()
    {
        gameBestTime = PlayerPrefs.GetFloat("BestScore", 0);
    }

    private void Update()
    {
        timer += Time.deltaTime;

        int minutes = Mathf.FloorToInt(timer / 60F);
        int seconds = Mathf.FloorToInt(timer - minutes * 60);

        gameTimeText.text = string.Format("{0:0}:{1:00}", minutes, seconds);

        if (wonGame)
        {
            if (timer < PlayerPrefs.GetFloat("BestScore"))
            {
                PlayerPrefs.SetFloat("BestScore", timer);
            }
        }
     
        TimeSpan bestGametTime = TimeSpan.FromSeconds(PlayerPrefs.GetFloat("BestScore"));
        gameBestTimeText.text = bestGametTime.Minutes + " : " + bestGametTime.Seconds;
        gameBestTimeText.color = Color.yellow;

        moneyAmountText.text = GlobalValues.money.ToString();
    }
    
}
using UnityEngine;

public class FinishLevel : MonoBehaviour
{
    [SerializeField]
    private int coinsAmount;

    [SerializeField]
    private int coinsToTake;

    [SerializeField]
    private GameObject collectCoinsPanel;

    [SerializeField]
    private GameObject levelWinPanel;


    private void OnCollisionEnter2D(Collision2D collision)
    {
        if (collision.gameObject.CompareTag("Player"))
        {
            if (coinsAmount >= coinsToTake)
            {
                levelWinPanel.SetActive(true);
                GameLevelInfo.wonGame = true;
                Time.timeScale = 0f;
            }
            else
            {
                collectCoinsPanel.SetActive(true);
                GameLevelInfo.wonGame = true;
                Time.timeScale = 0f;
            }
        }
    }
}

what exactly does not work ?

only the score value in your GameLevelInfo or your FinishLevel script as well ?

Debug it or put some debug logging in it to see the values on the different places.

Is the if (wonGame) passed ?
Is the value of “timer” correct ?
Do you really need the field “gameBestTime” you set it to 0 in the Start method, but never use it.

1 Like

Do you really need the field “gameBestTime” you set it to 0 in the Start method, but never use it.

it is because the first time game runs , the initial value for that to be defined as 0. or i am wrong with that?

on FinishLevel script with debug.log the value for coinsAmount is always equal to 0.
this is the problem. then i assigned the coins value to that in start method. again it does not work.

    private void Start()
    {
        coinsAmount = GlobalValues.money;
    }

i dont know what to do now

Anytime you think the above thought, this should be your instantaneously-next thought:

To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

Doing this should help you answer these types of questions:

  • is this code even running? which parts are running? how often does it run?
  • what are the values of the variables involved? Are they initialized?

Knowing this information will help you reason about the behavior you are seeing.

1 Like

i did debug.log but as i said above here coinsAmount is always 0. but i have already took some coins. and i dont expect to find it as 0. why coinsAmount does not become as much as coins that are taken ?

if (coinsAmount >= coinsToTake)
            {
                levelWinPanel.SetActive(true);
                GameLevelInfo.wonGame = true;
                Time.timeScale = 0f;
            }

No, no you didn’t. Until you literally print EVERYTHING you are not finished.

  • the coins before
  • the amount you are considering adding
  • the coins after
  • the coins where you try to use them next time
  • etc etc etc.
2 Likes

so after searching in the code here it is :

the value of “timer” is correct when if (timer > PlayerPrefs.GetFloat(“BestScore”)) but in this case the highest time is always saved and displayed. rather i need to see the lowest time as game level time.

the value of “timer” is not correct when if (timer < PlayerPrefs.GetFloat(“BestScore”)) either.

how to fix that? how to give the comparison the correct amount for PlayerPrefs.GetFloat(“BestScore”?

If you finish something in one second, is that a better time than zero seconds?

It’s not, so that’s probably why the zero is not being replaced.

This is the logic you want:

if ((best time does NOT exist) OR (current time is better than (less than) best time))
{
      replace best time with current time
}

PlayerPrefs.HasKey() can tell you if anything exists for that key.

And obviously if you don’t HAVE a best time, don’t show zero because that’s confusing. Show no best time at all.

2 Likes

this is excactly what i need . let me see how it come in true with codes ^^ . thanks.

You’re welcome! I recommend you wrap all those PlayerPrefs calls up somewhere you don’t have to keep retyping “BestScores” and whatnot.

Here’s an example of simple persistent loading/saving values using PlayerPrefs:

Useful for a relatively small number of simple values.

You could add to that a method called “HaveBestScore()” and then if you decide to change how best scores are stored in the future, none of your game changes, just this one module.

2 Likes

i cannot post my question. but here it is :

when i go to another scene and come back best time is 0.
and also first time best time is 0 but other time it is a very small number. what is wrong ? why still not working?

0.02
UnityEngine.Debug:Log(Object)
GameLevelInfo:Start() (at Assets/Scripts/GameLevelInfo.cs:22)
private void Update()
    {
        timer += Time.deltaTime;

        int minutes = Mathf.FloorToInt(timer / 60F);
        int seconds = Mathf.FloorToInt(timer - minutes * 60);

        gameTimeText.text = string.Format("{0:0}:{1:00}", minutes, seconds);

        TimeSpan bestGametTime = TimeSpan.FromSeconds(PlayerPrefs.GetFloat("BestScore"));
        gameBestTimeText.text = bestGametTime.Minutes + " : " + bestGametTime.Seconds;
        gameBestTimeText.color = Color.yellow;

        if (wonGame)
        {
            if (PlayerPrefs.GetFloat("BestScore") == 0 || timer < PlayerPrefs.GetFloat("BestScore"))
            {
                Debug.Log("here");

                PlayerPrefs.SetFloat("BestScore", timer);
                PlayerPrefs.Save();
            }
        }

        moneyAmountText.text = GlobalValues.money.ToString();
    }

scene change:

 public void LoadLevel(int sceneIndex)
    {
        StartCoroutine(LoadAsynchronously(sceneIndex));
        GameLevelInfo.timer = 0;
    }