by

ScriptableObject architecture series part 2 – fancy variables

Aims:

  • To have ints / floats / strings manage saving & loading their own state.
  • To have ints / floats / strings be reference-able in the inspector
  • To separate data (e.g. currency, health, score) from components (displays, calculators, shopfronts, managers).

Let’s remind ourselves of the problem. You’re storing “coins” as an int and you stick it on a GameManager singleton:

All the other things that need to know how many coins there are will reference it with  GameManager.Instance.coins .

Ok, but now the GameManager also has to persist that data so it starts to look like this:

Suddenly our GameManager is not only managing the game but also looking after data. Also, now your Shop UI or coin display can’t work on its own because it needs the GameManager to know how many coins you have. Things have become coupled (one cannot work without the other). If we made a scene just for the shop, our team would have to remember to drag the GameManager into it as well. That might not sound like a big deal but it quickly gets out of control as more managers are introduced.

Like in real life, managers quickly become a dump for all the leftover tasks.

Since we are striving for clean, decoupled, single-responsibility code – we can do better than this! Let’s start by creating a scriptableobject that just stores an int:

This step on its own already gets rid of the need for a manager & singleton. Once you create an instance of this class through the right click menu, some shop UI can reference and use it directly:

Let’s go a step further and get our ints to look after their own state. There are many options to storing data, but for demo, let’s store this int in Playerprefs.

Alright, now the int’s are managing their own persistence. How about an event notifying listeners of a value change?

Registering a callback to OnChange lets us write a counter as small as this:

Now let’s cache the value from Playerprefs so we’re not going in and out all the time:

And maybe a few Odin buttons for resetting the stored value and testing:

And there we have it. From here, you can add other features like saving to the cloud instead of PlayerPrefs, string formatting, and so on. Most importantly – data and behaviour is separate and scenes are easier to reason about and test.

Happy scripting!

Write a Comment

Comment