How do I check if player has bought skin or not?

I have all my skins in an array. I was thinking of using a boolean to check if a player has bought one or not but how do I add a boolean value to an array of sprites? Here is the code for choosing skins

Any help would be appreciated :slight_smile:

public class Skins : MonoBehaviour
{
    SpriteRenderer renderer;
    Player player;
    int currentSkinIndex;

    [SerializeField] Sprite[] skins;
    void Start()
    {
        player = FindObjectOfType<Player>();
        renderer = player.GetComponent<SpriteRenderer>();
    }

    private void Update()
    {
        renderer.sprite = skins[currentSkinIndex];
    }


    public void rightMouseButton()
    {
        currentSkinIndex++;
        if(currentSkinIndex >= skins.Length)
        {
            currentSkinIndex = 0;
        }
    }

    public void leftMouseButton()
    {
        currentSkinIndex--;
        if(currentSkinIndex < 0)
        {
            currentSkinIndex = skins.Length - 1;
        }
    }
   

}

Would making a second array of bools work?

1 Like

You can either create a second array of bools (if the script is not gonna be big) as stated above, or create a struct which contains one skin and one bool, and then have an array of this new type.

3 Likes

Thanks everyone I will try it out :slight_smile:

I made a second array of bools and it worked perfectly. But how do I save the value of each bool? How do I use playerprefs in this case because no when the player buys a skin and exits the game or goes back to the menu scene the bought value goes back to false. Here is the code of what I have now:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;

public class Skins : MonoBehaviour
{
    SpriteRenderer renderer;
    Player player;
    int currentSkinIndex;

    [SerializeField] Sprite[] skins;
    [SerializeField] GameObject buyUI;
    [SerializeField] GameObject playUI;
    [SerializeField] TextMeshProUGUI priceText;
    [SerializeField] int[] skinPrices;
    bool[] hasBought;

    void Start()
    {
        hasBought = new bool[skins.Length];
        hasBought[0] = true;
        player = FindObjectOfType<Player>();
        renderer = player.GetComponent<SpriteRenderer>();
    }

    private void Update()
    {
        priceText.text = skinPrices[currentSkinIndex].ToString();
        renderer.sprite = skins[currentSkinIndex];
        if(hasBought[currentSkinIndex])
        {
            PlayerPrefs.SetInt("usedSkin", currentSkinIndex);
        }       
    }


    public void rightMouseButton()
    {
        currentSkinIndex++;
        if(currentSkinIndex >= skins.Length)
        {
            currentSkinIndex = 0;
        }

        if(hasBought[currentSkinIndex])
        {
            bought();
        }

        else if(!hasBought[currentSkinIndex])
        {
            notBought();
        }
    }

    public void leftMouseButton()
    {
        currentSkinIndex--;
        if(currentSkinIndex < 0)
        {
            currentSkinIndex = skins.Length - 1;
        }

        if (hasBought[currentSkinIndex])
        {
            bought();
        }

        else if (!hasBought[currentSkinIndex])
        {
            notBought();
        }
    }

    void bought()
    {
        buyUI.SetActive(false);
        playUI.SetActive(true);
    }

    void notBought()
    {
        buyUI.SetActive(true);
        playUI.SetActive(false);
    }

    public void buy()
    {
        if(skinPrices[currentSkinIndex] <= PlayerPrefs.GetInt("Coins"))
        {
            hasBought[currentSkinIndex] = true;
            PlayerPrefs.SetInt("Coins", PlayerPrefs.GetInt("Coins") - skinPrices[currentSkinIndex]);
            bought();
        }

        else
        {
            return;
        }
    }

   
   

}

Since PlayerPrefs can save neither bools nor arrays, you will have to do some trickery, but it’s not hard.
First of all, to save an array, you can OnApplicationQuit (or when a skin is bought) save the length of the bool array. Afterwards save the values using the name of the array and the index as key, using a for-loop. From the PlayerPrefs perspective you are just saving single values, so you only have to make sure you are saving the correct amount and that you are able to recover them. So when you need to load it, you first look up the length, then create an array of that length and fill its indices with the corresponding values, again using a for-loop.
Secondly, instead of saving a bool, you will need to save a different representation. Integers would probably be your best bet. Save 0 for false and 1 for true. You can easily get these values by using either Conver.ToInt32, or by using a simple tertiary operation. When loading the values, do the opposite or simply check for != 0 or something like that.

1 Like

I will try that. Thanks alot!

It didn’t work, but I probably understood you wrong. I don’t really get it. How do I save the values of each value in the array when playerprefs requires a string key? is this code what you meant? i changed from bool to int too

public class Skins : MonoBehaviour
{
    SpriteRenderer renderer;
    Player player;
    int currentSkinIndex;

    [SerializeField] Sprite[] skins;
    [SerializeField] GameObject buyUI;
    [SerializeField] GameObject playUI;
    [SerializeField] TextMeshProUGUI priceText;
    [SerializeField] int[] skinPrices;
    [SerializeField] AudioClip selectSound;
    [SerializeField] AudioClip failSound;
    [SerializeField] AudioClip buySound;
    int[] hasBought;

    void Start()
    {
        hasBought = new int[skins.Length];
        hasBought[0] = 1;

        for(int i = 1; i <= hasBought.Length; i++)
        {
            hasBought[i] = PlayerPrefs.GetInt("hasBought[i]", 0);
        }

        player = FindObjectOfType<Player>();
        renderer = player.GetComponent<SpriteRenderer>();
    }

    private void Update()
    {
        priceText.text = skinPrices[currentSkinIndex].ToString();
    }

    private void FixedUpdate()
    {       
        renderer.sprite = skins[currentSkinIndex];
        if(hasBought[currentSkinIndex] == 1)
        {
            PlayerPrefs.SetInt("usedSkin", currentSkinIndex);
        }       
    }


    public void rightMouseButton()
    {
        currentSkinIndex++;
        if(currentSkinIndex >= skins.Length)
        {
            currentSkinIndex = 0;
        }

        if(hasBought[currentSkinIndex] == 1)
        {
            bought();
        }

        else if(hasBought[currentSkinIndex] <= 0)
        {
            notBought();
        }

        AudioSource.PlayClipAtPoint(selectSound, Camera.main.transform.position, 0.1f);
    }

    public void leftMouseButton()
    {
        currentSkinIndex--;
        if(currentSkinIndex < 0)
        {
            currentSkinIndex = skins.Length - 1;
        }

        if (hasBought[currentSkinIndex] == 1)
        {
            bought();
        }

        else if (hasBought[currentSkinIndex] <= 0)
        {
            notBought();
        }

        AudioSource.PlayClipAtPoint(selectSound, Camera.main.transform.position, 0.1f);
    }

    void bought()
    {
        buyUI.SetActive(false);
        playUI.SetActive(true);
    }

    void notBought()
    {
        buyUI.SetActive(true);
        playUI.SetActive(false);
    }

    public void buy()
    {
        if(skinPrices[currentSkinIndex] <= PlayerPrefs.GetInt("Coins"))
        {
            hasBought[currentSkinIndex] = 1;
            PlayerPrefs.SetInt("Coins", PlayerPrefs.GetInt("Coins") - skinPrices[currentSkinIndex]);
            AudioSource.PlayClipAtPoint(buySound, Camera.main.transform.position, 0.2f);
            PlayerPrefs.SetInt("BoolLength", hasBought.Length);

            for(int i = 0; i < hasBought.Length; i++)
            {
                if(hasBought[i] == 1)
                {
                    PlayerPrefs.SetInt("hasBought[i]", 1);
                }

                else
                {
                    PlayerPrefs.SetInt("hasBought[i]", 0);
                }
            }

            bought();
        }

        else
        {
            AudioSource.PlayClipAtPoint(failSound, Camera.main.transform.position, 0.2f);
        }
    }

   
   

}

Currently you are saving only one key, which is hasBought[ i], and do so hasBought.Length-many times. Instead you want to save (“hasBought”+i) and do that hasBought.Length-many times. So for each i, we create one key, ie hasBought0, hasBought1 and so on. Now we would actually save hasBought.Length-many different keys and values, which we can recover in the same fashion. It is worth mentioning, that you only need to save the bought skin in Buy(), since only that one changes. Saving the entire array is unnecessary there. I would probably do it OnApplicationQuit still, but technically we only ever need to save the one that got bought.

Code example for saving the entire array:

for(int i = 0; i < hasBought.Length; i++){
   PlayerPrefs.SetInt("hasBought" + i, hasBought[i] ? 1 : 0); // using tertiary operator to determine 1 or 0
}

To then load them we do the opposite:

int length = PlayerPrefs.GetInt(BoolLength);
hasBought = new bool[length];
for(int i = 0; i < length; i++){
    bool value = PlayerPrefs.GetInt("hasBought" + i, 0) > 0; //  ie 1 = true and 0 = false
    hasBought[i] = value;
}

As mentioned above, as far as saving goes, you should only need to save the actual bought skin when buying a skin. You dont really need to worry about, if for example the program crashes, and you thus only saved hasBought5, but not hasBought 0 to 4, since only the skin at index 5 was bought. This would still work, since PlayerPrefs.GetInt returns the default value of 0, if it cannot find the key, ie GetInt(“hasBought4”) would still return 0 = not bought. Or rather we set the default value to be 0 if it cannot find the key, which is the second parameter for those GetSomething methods of PlayerPrefs.

Last but not least, you may have noticed that i changed the way to set the value to 0 or 1. I did this for two reasons. I personally think this way is easier readable, but most importantly the way you did it does not work. You check hashBought == 1, which will never be true, since you are comparing a bool value to 1. You would first need to cast it to an int (which should be possible, did not check), use the previously mentioned Convert.ToInt32, or do it like i did with a tertiary operator.

Hope this clears your confusion. I guess i should have posted examples from the beginning, but it’s always a bit annoying to directly code here in the forum editor :stuck_out_tongue:

1 Like

Thanks!!! It worked!! Ur the best. Btw I changed the array from bool to int and made it 1 is true and 0 is false which is why I set it to check for == 1 :).

Oh ok, that works too i guess, but i personally think it’s a bit confusing design-wise. Imagine another person reading your code. ‘hasBought’ being an array of integers would, to most people, imply that you can buy multiples of skins.
Anyways, just wanted to mention this real quick. Glad it works now :slight_smile:

1 Like

This

Personally I’d make the array still use bools. You can save/load ints with PlayerPrefs and convert them into bools for your array. Then you deal with the bool values everywhere else in your code, while only the PlayerPrefs code is aware they are stored to disk as integers.

You could also take a few alternative approaches to avoid spamming playerprefs keys. You could store each bool as a single bit in an integer, allowing an array of bools up to 32 length from a single integer. Another approach would be to serialize the array into a single string you store in PlayerPrefs.

1 Like