Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
5
Question by mau5trap · Feb 18, 2014 at 03:35 AM · referencesstatic variables

Static References to Game Objects: Bad Idea?

Hey guys,

I'm relatively new to Unity, but I've been programming for some time now. Some friends and I are building a game and I had the idea of making a central manager that has references to certain scripts or objects that are consistent throughout the game to make it easier for us to code. I did this by making a Game Object and adding to it a script, GlobalManager.

Now, the idea here is that instead of having to constantly make references to scripts and find them on the scene, etc., the objects and scripts that aren't instantiated or destroyed in the scene have a static reference from this GlobalManager.

Example: Let's say our main player is the game object Player and its script is the PlayerScript. Then this GlobalManager script will have variables

 public static GameObject player;
 public static PlayerScript playerScript;

To the playerpublic var, I will drag the player object and the playerScript will be declared on start

 playerScript = player.getComponent<PlayerScript>();

So why do this? It's basically so from every other class that needs to reference either of these things, I can just simply do

 GlobalManager.player;

Rather than having to declare new references to the player or potentially complex getComponent chains for these two things that are, for all intents and purposes, static.

That being said, OOP design principles hate static variables and pretty much every advice on the internet is DON'T USE STATIC VARIABLES.

Is there a particular reason why this would be a bad design style in Unity?

Thanks guys!

Comment
Add comment · Show 8
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Benproductions1 · Feb 18, 2014 at 08:56 AM 0
Share

A singleton would be much better for this. None of this static stuff.

One really big flaw with static variables that reference Unity objects, is that Unity objects can be Destroyed at any point by anything, freeing the memory and nullifying all references. But then again, that goes for any reference to Unity objects.

Personally static anything should only be for singular functionality, without any side effects, such as $$anonymous$$athf.sin. Thats a static function that causes no side effects and therefore has a valid reason for being static, because it doesn't rely on an instance. static variables should solely be constants.
There are of course exception for libraries and such, but thats generally the rules I follow for static stuff.

avatar image wibble82 · Feb 18, 2014 at 09:13 AM 2
Share

After many years of game development, the general principle I $$anonymous$$ch junior programmers straight out of computer science degrees is "forget what you've been taught about fancy architecture - do whatever makes the code simple!". You can always clean it up later if your design decisions turn out to have caused issues. Over engineering is a much bigger time sink than the odd dodgy shortcut!

You'll need to make sure you initialize your static variables at the correct times, but provided that's done things will work fine.

The typical reason to avoid statics or singletons (statics are really just a very simple type of singleton) is that it prevents you changing your $$anonymous$$d about having just 1 global manager at a later date. But as I said, if you don't expect that to happen, keep the code simple. You can always fix it later if you need to!

avatar image vexe · Feb 18, 2014 at 09:18 AM 1
Share

Have a look here, skip to the good coding habits section, I talked about when it is a good idea to use static, and when it is not.

@wibble82 I agree with you, but most the times new-comers (to unity and/or program$$anonymous$$g) tend to get use statics in very wrongly manner that's why we tell them that if you're not sure what you're doing with your static usage, keep your distance from them...

avatar image mau5trap · Feb 18, 2014 at 04:21 PM 0
Share

@Benproductions1, I looked into using Singletons in Unity before posting this question and came across this article: http://redframe-game.com/blog/global-managers-with-generic-singletons/ It was very insightful, but it confirmed my feelings about not using singletons for two reasons: 1, the model I want is more along the lines of the monolithic manager they mention at the beginning and 2, I would hate to run into any of the singleton leaks they talk about towards the end.

@wibble82, I've gotten that advice several times, but it doesn't hurt to learn better design and architectural skills along the way :D I appreciate the comment, though, I understand what you're getting at and you're right, spending too much time overengineering is a problem.

@vexe, that article is perfect!!! It showed me exactly what I want to do, which is ultimately create and abstract class like the Tags class they have there. The only problem is I also want my monolithic manager to contain references to scripts so I would have it be able to cross-reference anything so I might not be able to make it abstract.

Thanks for all the help guys. While I understand that static references to objects mihgt be dangerous for construction/destruction purposes of objects, most of the references are to objects that are consistent across the game, so I think it will be fine. Worst case I just have to replace the static references with references to actual objects later on in case of bugs or performance hits, but it shouldn't be too bad work-wise.

avatar image vexe · Feb 18, 2014 at 04:50 PM 1
Share

@$$anonymous$$au5trap: $$anonymous$$ost the times you don't need managers! - For example, recently I was working on a system that displays text to the user (ex if an item is not used in the right place "You can't use this item here", etc) - I'm using NGUI there we use UILabel. Now, it would be inconvenient to inject a UILabel everywhere I want to print a msg, so I thought oh well, I'll use some static class or a singleton (some sort of "manager") and have it store a reference to the UILabel I want... but then I thought, wait a $$anonymous$$ute, if I do this then, what if I wanted to use a dif kind of label? it would be nice to inject what I want to use. But most the times, I'll be using one UILabel, like a default fallback type of label. So what's the best of the two worlds?

Inside my abstract TextObject class (which has children to manage different type of texts, user interaction, etc) I did this:

 private static UILabel defaultTextLabel;
 public static UILabel DefaultTextLabel { get { if (defaultTextLabel == null) defaultTextLabel = GetDefaultInteractionTextLabel(); return defaultTextLabel; } }

 [SerializeField]
 private UILabel mTextLabel;
 public UILabel textLabel { get { if (mTextLabel == null) return mTextLabel = DefaultTextLabel; return mTextLabel; } }

So now if somebody wants to access textLabel, he would definitely get a label (let it be injected, or the default one)

So now I could 'statically' create msgs, not caring about if there's a label or not.

 public static T CreateTextObject<T> (string[] msgs) where T : TextObject
 {
     var text = Utils.CreateGoWith$$anonymous$$b<T>("[Generated] " + typeof(T));
     text.msgs = msgs.ToList();
     text.handleUserInput = true;
     text.Show$$anonymous$$sg(true);
     text.CycleText();
     EventDelegate.Add(text.onCycleFinish, () => { Object.Destroy(text.gameObject); thereIsAlreadyAnObject = false; });
     return text;
 }

Bottom line, you could always find ways that don't require the use of a manager. Use your imagination.

Show more comments

2 Replies

· Add your reply
  • Sort: 
avatar image
7

Answer by Immanuel-Scholz · Feb 20, 2014 at 11:12 AM

As you already figured out, there are tons of very strong opinions about whether statics aka Singletons aka global variables are good or the root of all evil or make children cry etc.. pp. Each side has very convincing arguments about why its very bad or totally cool to have these.

I won't even try to start that meta-discussion going here. ;) I just assume you decide to use global variables in Unity and are more interested about the cave-eats of doing so.

So specifically about Unity, keep the following in mind:

  1. Static variables are nulled on an "assembly reload" and on certain other events in the editor, e.g. when you press "Play" or when you change a script file.

  2. The value of static variables are never persisted in the map, prefabs or in custom asset files.

  3. Although you can use "Script Execution Order" to manipulate the order in which Awake / Start is called, this feature is VERY buggy in Unity at the moment (4.3.4). You are probably better off writing the classes in a way that will still work if the order gets messed up.

  4. The order of OnDestroy() and OnDisable can NOT be controlled and is always random. This is a major headache when you try to access these global variables during shutdown.

  5. If you create an GameObject during the game shutdown-phase in the editor (e.g. OnDestroy), it will END UP IN THE PERSISTED SCENE.

  6. FindObjectsOfType during OnDestroy won't find gameobjects that already got their OnDestroy.

What does this list mean? You should try to solve 1., 2. and 3. by providing some kind of intelligent static getter that retrieve the game object on-demand if its not initialized yet.

 static GameObject _m
 public static GameObject manager
 { get { return _m ? _m : (_m = FindObjectsOfType<MyManager>()); } }

That way, you will return the manager regardless of whether its own Awake has been called already or not. To speedup the lookup, you can add a function void Awake() { _m = this; } into the manager. (Or use OnEnable, which is called during Assembly Reload as well. Awake is only called when loading the scene the first time.)

What you should NOT do is, try to create a new manager via new GameObject if it does not exist. That is because of 4. and 5.! You would end up with multiple instances of your manager saved into the map when accidently accessing the global manager during OnDestroy (or OnDisable)

Because of 6., it is probably easier to not clear out the manager in OnDestroy / OnDisable, because then it is undefined whether you can still access the manager during shutdown functions of other scripts.

Hope it helped.

Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image whydoidoit · Feb 21, 2014 at 05:22 AM 0
Share
  • Well put.

avatar image vexe · Feb 21, 2014 at 05:53 AM 1
Share

nice - I'll reference this answer to other static-related question in the future.

avatar image whydoidoit · Feb 21, 2014 at 05:54 AM 1
Share

Just out of interest - I use Script Execution Ordering all over the place - is this something you think broke recently? Just about to upgrade to 4.3.4

avatar image Nition · Aug 02, 2014 at 02:26 AM 0
Share

@whydoidoit The answer on this question covers the behaviour well for 3.5.2: http://answers.unity3d.com/questions/217941/onenable-awake-start-order.html I haven't tested myself but people seem to think it's much the same (it not exactly the same) in the latest.

@Immanuel Scholz Re the OnDestroy/OnDisable ordering issues, for doing stuff on quit you can at least rely on OnApplicationQuit being called before OnDestroy... I think.

avatar image
0

Answer by ClearRoseOfWar · Dec 02, 2020 at 06:12 PM

Sorry to necro, but this is one of the first pages that appear on google so people will find this first I hope.

I realize this is not the best scenario, but lets roll with it. What is easier on the cpu?

1.

 //Gameobject1 has script attached to it called 'GameMaster.cs' ->
 public class GameMaster: MonoBehaviour{
     public bool fooBool = false;
     public int fooInt = 4;
 }

and then...

 // GameObject2 has script attached to it called 'MainMenuOptions.cs'
 public class MainMenuOptions: MonoBehaviour{
     public Text fooScore;
     public GameMaster gameMaster;

     public void Update(){
         fooScore.text = gameMaster.fooInt.ToString();
     }
 }


OR

2.

 //Gameobject1 has script attached to it called 'GameMaster.cs' ->
 public class GameMaster: MonoBehaviour{
     private static GameMaster _instance;
     public static GameMaster Instance { get { return _instance; } }

     public bool fooBool = false;
     public int fooInt = 4;

     public void Awake(){
         if (_instance != null && _instance != this)
             Destroy(this.gameObject);
         else
             _instance = this;
     }
 }

and then...

 // GameObject2 has script attached to it called 'MainMenuOptions.cs'
 public class MainMenuOptions: MonoBehaviour{
     public Text fooScore;

     public void Update(){
         fooScore.text = gameMaster.Instance.fooInt.ToString();
     }
 }



Lets say were not calling things in an update, is it easier on memory to go with case 1, instead of 2? Whats best here, in terms of cpu / memory consumption. Is there any difference?

Kind regards.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

25 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Unity on github 3 Answers

How do I find which objects are referencing another? 10 Answers

Simplest way to attach toggles to booleans, maybe some kind of reference variable? 0 Answers

Sound Clip isn't playing when triggered. 1 Answer

Serialize, deserialize and keep references alive 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges