I have created a static class “AppSettings.cs” to store all game’s settings and values.
using UnityEngine;
/// <summary>
/// Controls the app settings
/// </summary>
public static class AppSettings
{
private static string qualityLevel;
private static bool bloomAllowed;
public static float[] cubesTextFontSizes = {10, 10, 10, 10};
// public static float size1;
// public static float size2;
// public static float size3;
// public static float size4;
public static float vfxTextSize;
.....
}
I can call any setting directly from any class like this: AppSettings.settingName without the need to assign the script to any gameObject.
Is this the right way to do that? am i suppose to make it non-static and make it inherit from
MonoBehaviour and assign to an empty gameObject in the Scene?
I don’t see any problem with this. Static data has more or less the same lifecycle as your application. That seems like a good match for this type of data.
The main issue I see with using a singleton like this is that you won’t be able to serialize it, and if this is settings, presumably at some point you will want to save/load them. The approach that I like is to use a non-Unity class to store the settings, and reference that class from a MonoBehaviour. That MonoBehaviour can be a singleton for easy access.
[Serializable]
public class MySettings {
public string qualityLevel;
//etc
}
public class GameController : MonoBehaviour {
public static GameController instance;
void Awake() {
instance = this;
}
public MySettings settings; //because this is marked as Serializable you can change these settings in the inspector
}
// anywhere else in your game
if (GameController.instance.settings.qualityLevel == "High") {
// do high quality stuff
}
The MySettings object can also be sent to classes like JsonUtility or Json.NET to save the user’s settings to a json file, or BinaryFormatter to save the raw data to disk, and so on. This is all in addition to, as mentioned, being able to set those values in the inspector if you so desire. It’s a LOT more versatile than static variables.
I would not bother with this unless you need regular “pumps” from Unity via the Update() method, or you’re a unit test advocate, which lets you mock the class for testing. (Edit: or as pointed out above you want to serialize it to write it to disk.)
Some super-simple Singleton examples to take and modify:
Another unity specific approach would be to use UnityEngine.PlayerPrefs.
The advantage of using this class is, that simple key-value pairs (supported values are strings, integers, boolean and floats) are persisted between user sessions.
After reading the posts above, a scriptable object singleton wouldn’t really be the best approach here since you would need to save/load settings. This would be more suited for globally shared settings that wouldn’t change at runtime.
But actually i don’t understand how can a static class keep the values of its static variables through the entire lifespan of the App (game) and through different Scenes without assigning it to some gameObject in the scene?
Whe’re just using it as a .cs file ?
This is confusing, how is it working without being attached to a gameObject? and where does it store the values?
It’s stored in the core scripting runtime that gets kicked off when you either start the application, or (in the Unity Editor) compile scripts. It’s basically a part of the core application itself.
Sidenote: this does mean that you can set a static variable to some value, exit play mode, start play mode, and retrieve the value that you set in the previous run, as long as you don’t trigger a script recompile in between. But the same is not true in play mode. Therefore, you can have inconsistent behavior from one run to the next despite making no changes, which makes debugging more difficult, and is one of the reasons I try to avoid holding actual data in static variables.
Storing references to Unity objects in static variables (such as a singleton pattern) does not have the same problems, because when a Unity object is destroyed (as it is when you exit play mode) its value reads as null (due to some convenient overrides).
That’s just how static variables work basically. They are just a way to access a single spot in memory: they are initialized to some default value when the app loads (i.e., 0, 0.0f, false, or null), and the only time they change is if someone assigns a value to them.
Static variables are associated with the class itself, rather than an instance of the class as with non-static variables. So an instance of the class doesn’t even need to exist, and destroying instances of the class have no effect on the static variables (unless you specifically code that in yourself).
The class, and its static variables, exist from the moment your game initially loads, and disappear when your game exits. But since static variables are associated with the class instead of instances of the class, there is only a single “copy” of these variables. Multiple instances of the class all effectively share the same static variables.
@StarManta
But i’m only using the static class to store values that i’m planning to use in the same game run, i don’t want to save them on disk. I’m just assigning values to those static variables everytime the user runs the game. If the static variables are always stored in memory as long as the game is in memory, why can’t i use my method?
That’s not true. I tested this with Unity 2019.4 and the static classes/variables are (re-)initialized just fine everytime I press the play button no matter if the scripts were recompiled or not and that’s good, because it would be kinda weird if you have static values from a previous play mode.
So for the OP using a static class should work fine in your case.
That’s what i was expecting, why would a static variable stay in memory when you quit the game.
But i have another question: what happens to memory and static variables when you quit the game by only hitting the “home” button (without really exiting the game) on Android and iOS?
It depends, do you mean fully close the game or just “pause” it? If I press the home button on my (android) phone it doesn’t fully close the apps, it’s just in the background and I can continue the app, in this case the static variable would still be there, but if you fully close the app, then the full memory should be released and the static stuff is gone too.
Great explanation, but sometimes when you press the home button and put the game in the background, when you go back to the game after few hours, the game won’t just resume; it’ll restart and i think this is because the device has to wipe its data to release some memory?
They will stay in memory as long as your app is not killed by the operating system. However, modern version of Android and iOS are quite judicious with system resources, and there is a good chance the OS will stop your application at some point while it is suspended in the background. The user can also kill your app by swiping it and you will not get any chance to respond in your code at all.
It’s a good idea to regularly save your data to persistent storage, such as a file, pretty often. Especially when your app is suspended. Android/iOS provide callback mechanisms for your app to do this when it is about to be suspended.