Trouble with bool and player prefs

I have been working on a program that has an intro, but fans of the program want the ability to turn them on and off. I can turn them on and I can turn them off, but not consistently. I don’t have any problem saving the bools from the toggles in the other scripts, but this one is causing problems that I cannot seem to narrow down.
Any suggestions would be great as I am stopping for the night as I have been looking at this code for too long.

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

public class IntroControl : MonoBehaviour
{
     public bool intros;
    [SerializeField] private Toggle disable;
    [SerializeField] private GameObject load;
    [SerializeField] private GameObject intro1;
    [SerializeField] private GameObject intro2;
    [SerializeField] private GameObject main;
    [SerializeField] private AudioConrol ac;
    [SerializeField] private float scene1 = 2f;
    [SerializeField] private float scene2 = 5f;
    [SerializeField] private float scene3 = 5f;

    private void Start()
    {
       
        Debug.Log(intros);
        if (intros = PlayerPrefs.GetInt("introToggle")== 0 ? true : false)
        {
            load.SetActive(false);
            ac.enabled = true;
            main.SetActive(true);
            disable.isOn = true;
        }
        else if (intros = PlayerPrefs.GetInt("introToggle") == 1 ? true : false)
        {
            disable.isOn = false;
            Debug.Log("On!!!");
            StartCoroutine(Intro());
        }
    }
    public void IntroStop()
    {
        if(!disable.isOn)
        {
            PlayerPrefs.SetInt("introToggle", 1);
            PlayerPrefs.Save();
            Debug.Log("On!!!" + intros);
        }
        else
        {
            PlayerPrefs.SetInt("introToggle", 0);
            SaveData();
            Debug.Log("Off!!!" + intros);
        }
       

    }
    IEnumerator Intro()
    {
        yield return new WaitForSeconds(scene1);
        load.SetActive(false);
        intro1.SetActive(true);
        yield return new WaitForSeconds(scene2);
        intro1.SetActive(false);
        intro2.SetActive(true);
        yield return new WaitForSeconds(scene3);
        intro2.SetActive(false);
        ac.enabled = true;
        main.SetActive(true);
    }
    public void SaveData()
    {
        PlayerPrefs.SetInt("introToggle", 0);
        PlayerPrefs.Save();
    }

    private void OnApplicationQuit()
    {
        PlayerPrefs.Save();
    }
}

I’m actually not sure what your if checks are doing in Start. You should just check if the playerprefs returns a 0 or 1.

Honestly, I think the value of intros will always be true also. Since if the first if check, which also does an assign is false, the second one will set it to true.

But, you don’t use the value of intros anywhere except the debug messages.

So, the next thing would maybe be the IntroStop method to look into. But, you weren’t really clear on what you meant by things being inconsistent.

It always boggled me that PlayerPrefs doesnt have Get/SetBool. I abstract it away in a Storage class and avoid all the what means what after. you may want to alter the Get signature to support providing a default boolean for consistency with the PlayerPrefs, but this is what I use.

    public const int FALSE_INT = 0;
    public const int TRUE_INT = 1;

    public static bool GetBool(string key){
        return PlayerPrefs.GetInt(key, FALSE_INT) == TRUE_INT;
    }
    public static void SetBool(string key, bool value){
        int i = value ? TRUE_INT : FALSE_INT;
        PlayerPrefs.SetInt(key, i);
    }

    public static bool IntToBool(int i){
        return (i == TRUE_INT);
    }
    public static int BoolToInt(bool b){
        return b ? TRUE_INT : FALSE_INT;
    }
}

What you can do is to create a class that does the job for you:

    public class Prefs: MonoBehaviour
    {
        const string INTRO_TOGGLE = "introToggle";
        public Prefs Instance;
        private bool introToggle;

        private void Awake()
        {
            Instance = this;
            init();
        }


        public bool IntroToggle
        {
            get
            {
                return introToggle;
            }
            set
            {
                introToggle = value;
                PlayerPrefs.SetInt(INTRO_TOGGLE, value ? 1 : 0);
                //PlayerPrefs.SetInt(INTRO_TOGGLE, Convert.ToInt32(value)); // alternate way
            }
        }

        private void init()
        {
            introToggle = PlayerPrefs.HasKey(INTRO_TOGGLE) ? PlayerPrefs.GetInt(INTRO_TOGGLE) == 1 : false;
            // introToggle = PlayerPrefs.HasKey(INTRO_TOGGLE) ? Convert.ToBoolean(PlayerPrefs.GetInt(INTRO_TOGGLE)) : true; // alternate way
        }
       public void Save()
        {
            PlayerPrefs.Save();
        }
    }

Your code should become something like this:

    private void Start()
    {
      
        Debug.Log(intros);
        if (Prefs.Instance.introToggle)
        {
            disable.isOn = false;
            Debug.Log("On!!!");
            StartCoroutine(Intro());
        }
        else
        {
            load.SetActive(false);
            ac.enabled = true;
            main.SetActive(true);
            disable.isOn = true;
        }
    }
    public void IntroStop()
    {
        if(disable.isOn)
        {
           Prefs.Instance.introToggle = false;
            Prefs.Instance.Save();
            Debug.Log("Off!!!" + intros);
        }
        else
        {

           Prefs.Instance.introToggle = true;
            Prefs.Instance.Save();
            Debug.Log("On!!!" + intros);

        }      
    }
    private void OnApplicationQuit()
    {
        //Prefs.Instance.Save(); // only if you remove the save calls in IntroStop
    }
}

Thank guys I will look into this later today after work

For my prefs I always do what @dlorre suggests but I just make it static… PlayerPrefs itself is static after all.

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

Useful for a relatively small number of simple values.

Is there some value to being a subclass of MonoBehavior? I tend to avoid it when possible so I get a constructor and all the other goodies.

I just do this to make an instance in Awake() but you can do as @Kurt-Dekker suggested and make a static class instead.

Okay so, I was able to get something to work by creating another int and saving that to fix the bool issues. Now my issue is, I am able to disable the intro for one startup, if I do not go back into the options panel and click the toggle again, the intros will appear in the next run. I tried the code provided, thank you btw, but it had a problem with Prefs.Instance that I couldn’t seem to fix. Small video attached to see what I am seeing.

Here is my current code:

public bool intros;
    [SerializeField] private Toggle disable;
    [SerializeField] private GameObject load;
    [SerializeField] private GameObject intro1;
    [SerializeField] private GameObject intro2;
    [SerializeField] private GameObject main;
    [SerializeField] private AudioConrol ac;
    [SerializeField] private float scene1 = 2f;
    [SerializeField] private float scene2 = 5f;
    [SerializeField] private float scene3 = 5f;
    [SerializeField] private int value = 0;

    private void Awake()
    {
        value = PlayerPrefs.GetInt("introToggle");

        if (value != 0)
        {
            intros = true;
            disable.isOn = false;
            Debug.Log("On!!!");
            StartCoroutine(Intro());
        }
        else
        {
            intros = false;
            load.SetActive(false);
            ac.enabled = true;
            main.SetActive(true);
            disable.isOn = true;
        }
    }
    private void Update()
    {
        if(value == 1)
        {
            intros = true;
        }
        if (value == 0)
        {
            intros = false;
        }
    }
    public void IntroStop()
    {
        if (!disable.isOn)
        {
            intros = false;
            disable.isOn = false;
            PlayerPrefs.SetInt("introToggle", 1);
        }
        else
        {
            intros = true;
            disable.isOn = true;
            PlayerPrefs.SetInt("introToggle", 0);
        }
        PlayerPrefs.Save();

    }
    IEnumerator Intro()
    {
        yield return new WaitForSeconds(scene1);
        load.SetActive(false);
        intro1.SetActive(true);
        yield return new WaitForSeconds(scene2);
        intro1.SetActive(false);
        intro2.SetActive(true);
        yield return new WaitForSeconds(scene3);
        intro2.SetActive(false);
        ac.enabled = true;
        main.SetActive(true);
    }
}

Hi. I have a settings file in my VR app but I don’t use the PlayerPrefs stuff preferring to write my own for maximum control. But I can tell you what I can see (or in one case, don’t see). Is something calling the IntroStop method because I don’t see if called here.

I have no idea what you are doing in the Update method but if it is important to keep setting your intros property repeatedly the following should do it.

private void Update()
{
    intros = (value == 1);
}

.
Something similarly “odd” is going on in IntroStop BTW. You test for !disable.IsOn and set it to false or if it is on you set it to true which means the setting does not change. And if the check box is “disable” then it sounds like checking it would mean intros should be false (maybe?).

In any case it appears that if the disable check is not selected then intros should be true and the value 1 should be saved. If that logic is reversed it is easy to reverse the values but this is all that should be required.

public void IntroStop()
{
    intros = !disable.isOn;
    PlayerPrefs.SetInt("introToggle", intros ? 1 : 0);

    PlayerPrefs.Save();
}

Thank you that worked for me!