- Home /
Static class not working properly on game build
I'm making a rpg-like game and I'm using a static class to carry the payer's basic information between scenes. Before loading a new scene my GameManager class saves the inventory and the player's HP on the static class, then on the new scene on it's Start function it loads the inventory and the HP. If I try it on the editor everything works fine, but when I build the game and try it out only the inventory is saved between the scenes, wich is weird because they are both handled by the same function.
Answer by kala-hari · Jul 17, 2019 at 05:26 PM
I don't know if it is defined how static members behave in the Editor. If the class is not unloaded when leaving Play mode, the assigned values might survive when switching from Edit to Play mode again.
An alternative you could check out is to keep the player information in a script attached to a game object that is shared between scenes.
The Object.DontDestroyOnLoad() method allows you to keep the (game) object when loading new scenes.
This is not the case. Upon entering/leaving play mode, static fields are reset. If I understand correctly, scripts in play mode run in a separate application domain (almost as if they were a separate program entirely), and so static constructors are always called first in play mode (and thus static fields are reset).
That being said, your advice around using DontDestroyOnLoad() is still sound advice. Persistent data between scenes is best done with a persistent object, while data that is being shared across all scripts during the same point in time is a better candidate for static classes. This is because static classes can get reset for a number of reasons, since if that class is unloaded from the program for any reason (say, nothing else references it for a while), it can get reset. If your inventory is an array or class, but your HP is a float, this might mean that the inventory survives because it is referenced by something else, while the float gets reset. There's a lot of confusing stuff that can happen behind the scenes here and I am in no way an expert on how .NET runtime or Unity work at that deep a level.
The part that can also get tricky is editor serialization. Static variables are not serialized, and so the editor doesn't save/load them. Instance variables are serialized by the editor. The same cannot be said in build, where these variables are initialized from a serialized representation but then are left alone- there's no editor to mess with them any more. This is most easily noticed when using a slider on a float. In the editor, that float is clamped to a certain range, while in build it isn't, making it easy to forget to clamp the float yourself if needed.
I created a singleton class with don't destroy on load, but the problem remains. It works fine on the unity player, the data is saved between scenes and the singleton isn't destroyed on load but when I build the game only the inventory is saved between the scenes, the HP reset to the default value. I don't know if it's important but, the inventory is an Item array (Item being a custom class) and the hp is a float array .
Should I create a Class for the hp or is there a more elegant solution?
Answer by Cornelis-de-Jager · Jul 17, 2019 at 09:44 PM
Hi g-s-100, Static classes in Unity work a bit differently than they would in C# normally. The reason why is complicated, but should you want to define a propper static class this is how you do it in Unity.
public class GameManager : MonoBehaviour
{
//Static instance of GameManager which allows it to be accessed by any other script.
public static GameManager instance = null;
/* Safe player info here */
public int score;
public string playerName;
public int level;
...
//Awake is always called before any Start functions
void Awake()
{
//Check if instance already exists
if (instance == null)
//if not, set instance to this
instance = this;
//If instance already exists and it's not this:
else if (instance != this)
//Then destroy this. This enforces our singleton pattern,
// meaning there can only ever be one instance of a GameManager.
Destroy(gameObject);
//Sets this to not be destroyed when reloading scene / Switching scenes
DontDestroyOnLoad(gameObject); // VERY IMPORTANT
}
}
Now the most important part. This class needs to actually exist in game. It needs to be attached to an in-game object. Not having this will result in your class not working as Static.
This is entirely false. You need to have a script attached to a gameobject ONLY if you are using Awake(), Update(), or other $$anonymous$$onoBehaviour things. It is perfectly sensible to use a static class in many other contexts, especially for things like helper methods and short-term persistent state storage. What you have described is called a singleton, and is useful when you want static functionality and instance functionality at the same time. Singletons and static classes have similarities but are definitely NOT the same.
Static classes DO work just fine in Unity, as do non-monobehaviour instance classes. C# is C#, and all of its features will work the same in Unity as anywhere else. Unity does add a bit of magic with its AppDomain reload and the bizzare not-really-reflection that goes on around Update() and the like, but none of that really changes the behaviour of C#, it's just a behaviour that most non-Unity C# projects don't have.
Answer by g-s-100 · Jul 17, 2019 at 11:38 PM
Thanks for your help, but actually the issue was somewhere else. After Loading the scene I couldn't acess the player's change health function (where i get the value from the static class). I fixed it with a coroutine so the function would execute properly on the next frame. I'm not sur if it's the best method to fix this but it seems to work properly now.
Your answer

Follow this Question
Related Questions
Distribute terrain in zones 3 Answers
Multiple EasyAR ImageTracker in different Unity scenes 0 Answers
Triggers not working after building game on mobile 0 Answers
VR EXE not working correctly on other PC 1 Answer
Built game not working. Again. 1 Answer