How to collect gems only once and save into gamePrefs

I’m trying to monetise my game and I want the player to only collect each gem once, no matter how many times the game/level is restarted. The player will have a gemCount score. The score will go up when a gem is collected. Also the player will be able to buy packs of gems with ‘real’ money. The player can then spend the gems in the game shop. The gemCount will stay constant no matter if the game is quit and restarted.

The thing is I want to stop the player from adding to their gemCount by collecting the same gem over and over by just restarting the same level. . . because then they won’t need to spend ‘real’ money to buy gems. . .

Can someone tell me the correct methods I should use to ‘identify each gem’, ‘collect each gem only once’ and ‘record the gems collection to the gamePrefs’.

I’d rather not have a gamePref for each gem instance and I’d rather not have to name each gem either - but not sure if this is possible?

I will then need to check at each level start if each gem instance has been collected or not and whether or not to show/hide it.

I hope that makes sense?!

Hi Mark -

I don’t think there’s a straightforward way to accomplish what you’re looking for with PlayerPrefs as it’s not really designed for storing complex data (it should normally be used only for saving user-specific options plus, occasionally, installation-specific stuff, such as whether the user has seen a particular screen before).

Assuming you’re willing to look into more comprehensive saving solutions (such as saving the data as JSON), I’d approach it somewhat like this:

  • Create a Gem class with a public int for an ID and a public bool for whether the gem has been collected before or not. When adding a gem while designing a level, you’ll just need to manually add an id to that gem (e.g., 0, 1, 2, 3, etc).
  • Create a Level class that stores level-specific information, such as high scores, status of gems (collected or not), etc.
  • Ideally, you would create a List gems which will get populated upon instantiation (see below)
  • Upon instantiating the level, have each gem add itself to the list of gems using its ID (e.g., gems.Insert(id,this)). Upon adding the gem, have it check for whether it’s been collected before - if it’s been collected before, have it immediately run gameobject.SetActive(false). This way, you’re only left with gems that haven’t been collected before - those that have been will have disabled themselves.
  • Add a event or a method for tracking gem collect events - the idea is that when the gem is collected, its corresponding bool changes to true.
  • Now, the reason we add them all to the list is that we will need some way to persist this data - and, using this approach, you can save the status of each level when you save the game - simply loop through the list of levels to save the status of each level - including the status of each gem.

These are just broad strokes, of course - depending on your case, you could further optimize the code by only saving those levels that have changed and only loading the level/gem that’s about to be played.

But, essentially, the broad outline is to a) create classes that store the data you need; b) arrange these classes into a list for easy saving/loading; and c) loop through the list to save/load game data as required.

P.S. Writing JSON saves is pretty easy - here’s an example from my project. First, create the class you will use to store save data - think of it as a “template” for your save game:

[Serializable]
public class Save {

    public List<Level> savedLevels = new List<Level>();
 
}

When you’re reading to start saving, create an instance of the Save class and loop through your list of levels to store them:

    void SaveLevelsToFile()
        {
        save.savedLevels.Clear();
        for (int i = 0; i < levels.Count; i++)
            {
            data.savedLevels.Add(levels[i]);
            }
        }

And, finally, write the contents of the Save class to system storage using JSON serialization:

string jsonData = JsonUtility.ToJson(save, true);
        File.WriteAllText(Application.persistentDataPath + "/playerSave.json", jsonData);

Good luck,
George