money system in death menu

I followed this tutorial

and when I click a button the money saves and can be used elsewhere but when I crash in my endless runner and my death menu pops up the score resets why is that? here is my death menu code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class DeathMenu : MonoBehaviour
{
    public Text scoreText;
    public Image backgroundImg;
    public static int moneyAmount;

    private bool isShowned = false;

    private float transition = 0.0f;

    // Start is called before the first frame update
    void Start()
    {
        gameObject.SetActive(false);
        PlayerPrefs.SetInt("MoneyAmount", moneyAmount);
    }

    // Update is called once per frame
    void Update()
    {
        if (!isShowned)
            return;

        transition += Time.deltaTime;
        backgroundImg.color = Color.Lerp(new Color(0, 0, 0, 0), Color.black, transition);
    }

    public void ToggleEndMenu(float score)
    {
        gameObject.SetActive(true);
        scoreText.text = ((int)score).ToString();
        isShowned = true;
        PlayerPrefs.SetInt("MoneyAmount", moneyAmount);

    }

    public void Restart()
    {
        PlayerPrefs.SetInt("MoneyAmount", moneyAmount);
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
    }

    public void ToMenu()
    {
        PlayerPrefs.SetInt("MoneyAmount", moneyAmount);
        SceneManager.LoadScene("Menu");
    }
}

Assuming the value in question is in the static field called moneyAmount, I see that you are only ever calling PlayerPrefs.SetInt() to write it to playerprefs. Is somewhere else loading it from player prefs?

Also, is anywhere else in your code setting moneyAmount to zero? Since it is public static, anyone can write it. You can guard it a bit with a construct like this:

    public static int moneyAmount { get; private set;}

This will trigger compiler errors if anyone else tries to change it outside of this function, but they can still use it.

However, keep in mind since you never reload it from PlayerPrefs in the code above, next time you run it will be zero, and then your Start() function will instantly write it back to zero in PlayerPrefas.

Usually the pattern is to have a clear load/save demarcation point so you avoid sprinkling PlayerPrefs calls throughout your code, which can make for this exact error and be more difficult to track down.

Well in your script you have a field called moneyAmount that you store in the PlayerPrefs at several places, but you never read from the PlayerPrefs. The field moneyAmount is never set and will remain at a default value of zero. It must be that you set this field from outside the script, which makes this a bit hard to understand. I am not clear about how this script integrates with the rest of your code base.

You should probably only write to PlayerPrefs when you close the game and read from it on start up. It is a permanent storage that is meant to hold data between sessions. It is not intended to be used frequently during the game.

this is the script where i pick up coins

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class GameControlScript : MonoBehaviour {

    public Text moneyText;
    public static int moneyAmount;
    int isDesertSold;

    // Use this for initialization
    void Start () {
        moneyAmount = PlayerPrefs.GetInt ("MoneyAmount");
        isDesertSold = PlayerPrefs.GetInt("IsDesertSold");
    }
   
    // Update is called once per frame
    void Update () {
        moneyText.text = "" + moneyAmount.ToString() + "$";
    }

    public void gotoShop()
    {
        PlayerPrefs.SetInt("MoneyAmount", moneyAmount);
        SceneManager.LoadScene("LevelSelect");
    }
}

and once i press the button to go to shop the money amount is there this is my shop code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System;

public class ShopControl : MonoBehaviour
{

    public static int moneyAmount;
    int isDesertSold;

    public Text moneyAmountText;
    public Text desertPrice;

    public Button buyButtonDesert;

    // Start is called before the first frame update
    void Start()
    {
        moneyAmount = PlayerPrefs.GetInt("MoneyAmount");
    }


    // Update is called once per frame
    void Update()
    {
        moneyAmountText.text = "" + moneyAmount.ToString() + "$";

        isDesertSold = PlayerPrefs.GetInt("IsDesertSold");

        if (moneyAmount >= 5 && isDesertSold == 0)
            buyButtonDesert.interactable = true;
        else
            buyButtonDesert.interactable = false;
    }

    public void buyDesert()
    {
        moneyAmount -= 5;
        PlayerPrefs.SetInt("IsDesertSold", 1);
        desertPrice.text = "";
        buyButtonDesert.gameObject.SetActive(false);
    }

    public void ToForest()
    {
        PlayerPrefs.SetInt("MoneyAmount", moneyAmount);
        SceneManager.LoadScene("motomadness");
    }

    public void ToCity()
    {
        PlayerPrefs.SetInt("MoneyAmount", moneyAmount);
        SceneManager.LoadScene("City");
    }

    public void ToDesert()
    {
        PlayerPrefs.SetInt("MoneyAmount", moneyAmount);
        SceneManager.LoadScene("Desert");
    }

    public void ToWinter()
    {
        PlayerPrefs.SetInt("MoneyAmount", moneyAmount);
        SceneManager.LoadScene("Winter");
    }

    public void ToDungeon()
    {
        PlayerPrefs.SetInt("MoneyAmount", moneyAmount);
        SceneManager.LoadScene("Dungeon");
    }

    public void ToMenu()
    {
        PlayerPrefs.SetInt("MoneyAmount", moneyAmount);
        SceneManager.LoadScene("Menu");
    }
}

and it seems when i press the button to go to the menu it resets to zero as well why does it save for the shop but not for anything else this is my main menu code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class MainMenu : MonoBehaviour
{
    public Text highscoreText;
    public Text moneyAmountText;
    public static int moneyAmount;

    // Start is called before the first frame update
    void Start()
    {
        highscoreText.text = "Highscore : " + ((int)PlayerPrefs.GetFloat("Highscore1motomadness")).ToString();
        PlayerPrefs.GetInt("MoneyAmount", moneyAmount);
    }

    // Update is called once per frame
    void Update()
    {
        moneyAmountText.text = "" + moneyAmount.ToString() + "$";
    }

    public void ToGame()
    {
        PlayerPrefs.SetInt("MoneyAmount", moneyAmount);
        SceneManager.LoadScene("motomadness");
    }

    public void ToMenu()
    {
        PlayerPrefs.SetInt("MoneyAmount", moneyAmount);
        SceneManager.LoadScene("LevelSelect");
    }
}

Again, during your game, do not use PlayerPrefs. Only do that on the very beginning and end. During the game, use a regular property. Have only one of those. Currently all your scripts have their own moneyAmount variable and they could be different. It is much easier to have one script that controls the money and all other scripts can reference it.

I think you probably call PlayerPrefs.SetInt somewhere before you load from it or update the moneyAmount variable in that script. At that time, moneyAmount is still zero and resets your balance.

Think of PlayerPrefs like a safe where you put things while you don’t use them. The script that holds moneyAmount is your wallet. Currently you have at least three of those and all of them constantly mess around with your safe.
Ever watched three people mess around with a safe full of money? Yeah, it’s empty in the end :smile:

Exactly this. Establish a clear point where the saved value is loaded from PlayerPrefs (the safe) into a variable, as well as a point (or points) where it needs to be saved back into PlayerPrefs (the safe), such as when a level is over.

Write out a diagram if you need to, such as:

first scene - load the data
game over scene - save the data

That can help you visualize when in time everything should happen. During the game, you would ONLY change the variable, and never touch PlayerPrefs (the safe).

I suggest going through the tutorial again. It seems you have some mistakes in your code. In first posted script you SetInt in your start method. I think it should be GetInt. Also you have assigned public static int moneyAmount in all of your scripts.

1 Like

I am a beginner but when I remove public static in moneyAmount in one of the scripts I get a bunch of errors saying that moneyAmount doesn’t exist in the current context and if I remove PlayerPrefs.SetInt(“MoneyAmount”, moneyAmount); from any of my scripts for buttons it doesn’t save the coins in the next scene I have changed SetInt to GetInt in my death menu script and it loads the previous coins I had saved but when I collect more coins and die it resets back to the previous coins I had before I started the level. can anyone give me an example or something to help me understand a little more?

it also seems weird that if I have a button on the level scene, collect coins, die and press the button on the level scene it saves my coins but if I die and then press a button on the death menu it doesn’t save my coins.

First, remove all your GetInt and SetInt calls. You do not need PlayerPrefs. Those are ONLY interesting if you want to keep state after closing your game so taht you can continue, when you start it again. You are having much more basic issues to solve before that. Keep that for later.

Delete all variables called “moneyAmount”, but one. Then, from the places where you deleted it, you access it with ClassName.moneyAmount, where ClassName is the name of the class that still has the field. It is a static variable after all. Read up on that keyword “static”.

You could add Debug.Log statements at various positions and print out the state that is confusing you to track down where it behaves differently than you would expect. This way you can get to the bottom of your problem. Better even use the debugger and step through your code with it.