Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

C# Managers Static Functions

Discussion in 'Scripting' started by liquidgraph, Aug 13, 2010.

  1. liquidgraph

    liquidgraph

    Joined:
    Feb 26, 2009
    Posts:
    324
    I have a high-level limitation when working with C# in Unity. I'm not clear on the best approach. A lot of times I create manager or controller-type classes and it becomes tedious to call their functions from other classes. Here's an example:

    Class: Meta <-- runs the whole application at the highest level. Hold variables for universal settings like MusicOn, SoundOn, etc. In charge of loading various scenes.

    Class: Game <-- runs the gameplay portion of the application. Holds game-related settings like player speed, gravity, jumpHeight, etc. In charge of creating most of the gameplay objects and their controllers.

    Class: GUI <-- handles menus and HUD. It needs access to settings and functions from high-level classes like Meta and Game, but also low-level instances like Enemy, Player, or Platform.

    Questions:
    ========================
    1. First of all, right now Meta and Game are scripts attached to an empty gameObject I set up in the Scene. This is kludgy. Ideally I want these classes to exists independent of any objects (Abstract Class?). Meta should always exist anywhere in the application. There I think I can use a static class, but Game doesn't always exist -- it is created by Meta -- but I still want to be able to access Main's functions from any object with a simple one-liner like this:

    Code (csharp):
    1.  
    2. Main.DoSomething();
    3.  
    Right now I'm doing this by adding a GetComponnent call in the Start event of every single class. This becomes too much when I have more and more controllers that need to be referenced in this way. How can I do the above?

    2. On the Wiki there's an AManager C# class available but I don't understand why functions are called like this:

    Code (csharp):
    1.  
    2. AManager.instance.Foo();
    3.  
    Instead of like this:

    Code (csharp):
    1.  
    2. AManager.Foo();
    3.  
    Must "Instance" be used? Is there a way to just call AManager.Foo() directly?

    3. I'm not entirely clear on how static classes work. When I set a class to static, does is instantiate itself at the start of the application? Regardless of Scene? What if I want to have different static classes depending on the Scene loaded?

    4. Can a static class still have private functions and properties? I want to make use of Getters and Setters.

    5. How does a static class work behind the scenes? Is it literally creating an empty game object and attaching itself to that?

    6. What is the best way to organize multiple manager classes? Should they all be static? The problem there is, sometimes I don't need all the manager classes to exist, so I set up a class like Meta or Game to create them. But if I do that, tracking the gameObjects each class is attached to becomes hairy. Would it be better to attach all manager scripts to a single gameObject with AddComponent? And then destroy them with RemoveComponent?

    I feel I understand Unity pretty well now, but not knowing how to approach these high-level OO issues is holding me back. Please advise.
     
  2. Chris-Sinclair

    Chris-Sinclair

    Joined:
    Jun 14, 2010
    Posts:
    1,326
    1. I've made a similar application and what I did was have a single "bootstrapper" script attached to an empty game object. This in turn instantiated and executed my "main game" class. The vast majority of my classes are custom and do not inherit from MonoBehaviour and are not unity "scripts". I do have a handful which manage issuing events ("OnUpdate", mouse handling, keyboard handling) that directly interface with Unity.

    I don't have too many static classes, and instead pass an "ApplicationManager" around to the various managers and other classes which exposes most of my main API. I do have some statics though where it makes sense.

    All of my "GameObject" objects are instantiated at runtime and are wrapped by my own custom class. (kinda like the Facade pattern: http://en.wikipedia.org/wiki/Facade_pattern)

    2. This is coming from the Singleton Pattern (http://en.wikipedia.org/wiki/Singleton_pattern) which has its uses. The description on that page should describe why "instance" must be used.

    3. Static class instantiation occurs differently based on the language (some on application startup, some when you first access them). But most of the time it should be irrelevant (except for some of the more extreme cases, but it should not matter for Unity). I don't have too much time to go into the details of them, but essentially you work in scope of the class/type itself rather than a particular instance of it. Some more reading here: http://msdn.microsoft.com/en-us/library/79b3xss3(VS.80).aspx

    4. Yes.

    5. A static class isn't a GameObject. It's its own type and does not inherit from another class. It works "behind the scenes" in the way that it does not exist as a concrete object in the scene, but rather "just is" and can be accessed at anytime from any script.

    6. There are various ways to do this and you'll experiment and find ways that work for you. You can do it one way I described above, or you can attach all the managers to one governing static class, or however.

    I guess the point of all this is that your C# classes do not have to be MonoObject, GameObjects or anything. As long as they have a unique name you can work with them like a general application that happens to employ some of the Unity API.
     
  3. liquidgraph

    liquidgraph

    Joined:
    Feb 26, 2009
    Posts:
    324
    I'm still not clear on 3 things:

    #1
    ==========================
    So I MUST use:

    Main.instance.DoSomething();

    There's no way to use:

    Main.DoSomething();

    How come an iTween function can be called like:

    iTween.DoSomething();


    #2
    ==========================
    Can I just declare a static class and use it? Or must I instantiate it in itself as well?


    #3
    ==========================
    Is it possible to have a static class not exist at runtime, but have it created later on?


    Thank you.
     
  4. Chris-Sinclair

    Chris-Sinclair

    Joined:
    Jun 14, 2010
    Posts:
    1,326
    1. If the class is implementing the Singleton pattern, then yes, you must call instance first to grab a reference to the instance. (though at that point you may store that reference in other local variables for easy access)

    2. Yes, declare the static class and use it. You do not need to "instantiate" a static class. (Some advanced languages allow you to run essentially constructor logic, but you do not need to worry about this). Often I will give my static classes an "Initialize" method that I call once when my game starts up.

    3. Static classes are designed to exist at compile time. In the case of C#, I believe they are loaded into memory when you first try to access them and not before. Remember, static classes are not "created" or "instantiated" like other classes; they exist globally always.
     
  5. Ntero

    Ntero

    Joined:
    Apr 29, 2010
    Posts:
    1,436
    You only need instance for non static variables.

    Static means it is owned by the Class and not the particular instance of the class, which also means you only have one.

    instance allows you to have a static accessor to a non static class.

    So that you can call functions that require instances of that class (like Start Coroutine or Update or Start or ones you make yourself).

    You have 2 options:
    1: make your functions static so that you can call them without the instance element.

    2: make shortcuts, so that you have a static function DoSomething() that calls instance.DoSomethingNonStatic()
    It turns it into a shortcut.


    2)No instantiation required. Those variables and functions exist directly off the class. The only time you need to instantiate anything is if you have non static functions or variables, and then only if you want to access/store those variables.

    3)In some languages possibly, but it's not particularly feasible in .NET (outside of constructing custom classes at runtime, which would be too much I think).



    Think of GameObject.

    There is GameObject(class) and gameObject(property to instance of class). You can call GameObject.Find because it is static. You are not using a particular gameobject but rather using a general helper or utility. Find does not need to know about any particular instance but rather the class as a whole. It will always exist, even before there is a single GameObject created.

    You cannot to GameObject.GetComponent(). It requires gameObject the instance. This is because it needs to know about the particular instance of the GameObject that it is being used on. Because each GameObject has different Components.

    Statics cannot be instantiated or created. They just exist. As soon as the assembly is loaded they are there. They are stored within the class definition.

    Instances MUST be instantiated and created. They do not exist until you explicitly create that particular version you want to use.

    You can mix the two of them, and that's exactly what the static Instance property does. It allows you to store the current instantiation of that object inside a static variable. So that you can always access the Instance without having to know where it is.
     
  6. liquidgraph

    liquidgraph

    Joined:
    Feb 26, 2009
    Posts:
    324
    Thanks, I have a lot to play with here.

    I'm still puzzled about the best strategy to take when creating high-level manager classes. For example, I need a Scores class that will handle storage and retrieval of the player's high scores. It needs to run when the application is in menus mode and while the actual game is being played. In this case is it wiser to make Scores a static class, or instantiate it when it's needed, like when the score menu is open and when the player earns a high score.

    I guess I'm hesitant to start my application with a bunch of static manager objects that aren't strictly required then-and-there. For example, the application would start, we're still in the menu mode, but I would already have a controller class existing for Game, Player, HUD, etc. even those I haven't loaded the 1st Level. Is that how you guys code? Or you create those only when needed? And if so, how do you get easy-to-access pointers to those objects from other classes?
     
  7. Ntero

    Ntero

    Joined:
    Apr 29, 2010
    Posts:
    1,436
    This is what the Singleton example in the Unity Wiki does.

    It creates a class, so it's not always there like static classes, but it does so with a Global accessor (Instance) and only creates the object the first time you need it, while making sure it will never create duplicates. This is because Scores.Instance will actually create the new Scores class if it doesn't exist, but if it never gets called then that Scores instantiation will never get created.

    This means that if you set it so it gets destroyed on level change that it will only exist for the levels that use it. Or otherwise you can set it to be persistent and make sure that every object that modifies scores will always modify the same score.

    You can store the Instance in a reference on any particular class as well to avoid using Instance.

    i.e.

    MyStaticClass myInstance = MyStaticClass.Instance;
    myInstance.DoStuff();

    This allows you to avoid using Instance, as well as guarantee that there is only one Manager in effect ever. It also provides you with a consistent reference to that Object (think pointer) so that you can always access is quickly through the static instance class.


    For what you are doing, I would suggest a non-static class with a Static Instance Property. This will give you the greatest control for when to instantiate it, while also allowing for a very simple accessor for getting it from any class that needs it.
     
  8. liquidgraph

    liquidgraph

    Joined:
    Feb 26, 2009
    Posts:
    324
    Can you provide a C# code example of that please? Sounds like what I'm after.
     
  9. liquidgraph

    liquidgraph

    Joined:
    Feb 26, 2009
    Posts:
    324
    Man, this I'm pulling my hair out over this. Here's what I'm trying to accomplish but can't:

    I have a game object in the scene that I want to attached a script to called Meta. I do this by hand. What code do I need to write in Meta so that I can access it from any other script in the scene by simply saying:

    Code (csharp):
    1.  
    2. Meta.DoSomething();
    3.  
    Note, I don't want it to instantiate itself. It's already attached to an object.
     
  10. Chris-Sinclair

    Chris-Sinclair

    Joined:
    Jun 14, 2010
    Posts:
    1,326
    Assuming you only have one Meta:
    Code (csharp):
    1. public class Meta : MonoBehaviour
    2. {
    3.  
    4.     private static Meta m_Instance;
    5.     public static Meta Instance
    6.     {
    7.         get
    8.         {
    9.             return m_Instance;
    10.         }
    11.     }
    12.  
    13.     public void Awake()
    14.     {
    15.         m_Instance = this;
    16.     }
    17.  
    18.     public void SomeMethod()
    19.     {
    20.         //do stuff
    21.     }
    22. }
    23.  
    24. //access the "Meta" by:
    25. Meta.Instance.SomeMethod();
    26.  
    Just code off the top of my head. You were asking for samples of singleton pattern C# code: there were some in the wikipedia singleton pattern I linked previously. Included is a C# example. http://en.wikipedia.org/wiki/Singleton_pattern
     
  11. HoMeBoYErik

    HoMeBoYErik

    Joined:
    Mar 12, 2014
    Posts:
    23
    I share both the Bootstrap and the Singleton approach. I create an empty scene where all my "Global" manager are attached to a gameobject and setted to not be destroyed on load. Then the code load the first real scene.
    I share here my implementation of an ApplicationManager or ApplicationController (and I generally create various controllers, each one with a different job, as managing user data and preferences, managing the communication with a remote server, event managing, etc)

    Code (CSharp):
    1. public class ApplicationController : MonoBehaviour
    2.     {
    3.  
    4.         // Static singleton reference
    5.         public static ApplicationController Instance { get; private set; }
    6.         // whether or not this object should persist accross scenes (DontDestroyOnLoad)
    7.         public bool makePersistent = true;
    8.  
    9.         // Constants that are compiled with the app to determine current app version
    10.         // Values are matched with the server and eventually advice the user to update to a new version
    11.         // CHECK BEFORE PUBLISH : control app release version number
    12.         public static int IOS_VERSION = 1;
    13.         public static int ANDROID_VERSION = 1;
    14.  
    15.         // One Time Initializations
    16.         void Awake()
    17.         {
    18.             // First we check if there are any other instances conflicting
    19.             if(Instance != null && Instance != this)
    20.             {
    21.                 // If that is the case, we destroy other instances
    22.                 Destroy(gameObject);
    23.  
    24.             }
    25.          
    26.             // Here we save our singleton instance
    27.             Instance = this;
    28.          
    29.             // Furthermore we make sure that we don't destroy between scenes (this is optional)
    30.             if( makePersistent )
    31.             {
    32.                 DontDestroyOnLoad(this.gameObject);
    33.             }
    34.          
    35.             // Others "one time" initializations...
    36.  
    37.  
    38.             // Just a demo on how to encapsule all Debug code in a pre-compiler #if
    39.             // to strip out debug code when compiling for release
    40. #if AF_DEBUG  
    41.             Debug.Log ("[Application Controller]: Current version is " + IOS_VERSION);
    42. #endif
    43.          
    44.         }
    Then from everywhere you access to its functions like this:

    Code (CSharp):
    1. ApplicationController.Instance.DoSomething();
    Hope it helps
     
  12. A.Killingbeck

    A.Killingbeck

    Joined:
    Feb 21, 2014
    Posts:
    483
    Making everything static for the sake of easy access is not a good design strategy(also making everything singletons). I've used this setup quite a bit:

    Code (CSharp):
    1. class GameGlobals : MonoBehaviour
    2. {
    3.   private GameManager m_gameManager;
    4.    void Start()
    5.    {
    6.       m_gameManager =      GameObject.FindObjectOfType<GameManager>();
    7.    }
    8.  
    9. public static GameManager GameInstance()
    10. {
    11.      return m_gameManager;
    12.   }
    13.  
    14. }
    Use:

    Code (CSharp):
    1.  
    2. class AudioStuff : MonoBehaviour
    3. {
    4.    void Start()
    5.     {
    6.          GameGlobals.GameInstance()....
    7.     }
    8. }
    9.  
     
  13. Todd-Wasson

    Todd-Wasson

    Joined:
    Aug 7, 2014
    Posts:
    1,077
    This is probably way too late for the original poster, but for future folks stumbling across this thread:

    I used a singleton approach in my first app to hold global variables and didn't really like it, personally. It has to be instantiated, then you have to call it in (to my mind) a wierd way. Now I use a regular class with static variables and functions, but with the constructor set to private so it becomes impossible to create any instances of the class at all. It acts pretty much (exactly?) the same as a static class, and it can inherit MonoBehavior or whatever else which a static class can't do. It's nice to still have MonoBehavior print() statements and so forth during development.

    Here's a static class:
    Code (csharp):
    1.  
    2. public class SomeManagerClass : MonoBehaviour
    3. {
    4. private SomeManagerClass() { } //This is an emptry constructor that is private to prevent instantiation.  I.e., you can't make SomeManagerClass objects by mistake.  Not even one like you do with a singleton.   The compiler will stop you.
    5.  
    6. public static float score;
    7. public static bool someFlag;
    8.  
    9. //This is a private function that can not be called from anything outside of this SomeManagerClass.
    10. private static void DoSomething()
    11. {
    12. }
    13.  
    14. //This next one is a function that you can call from anywhere in your program.
    15. public static void DoSomethingFromAnywhereInYourProgram(GameObject gameObject)
    16. {
    17. //Do something to the gameObject that was passed in, or use any other argument you want.
    18. }
    19.  
    20. //This is a property with a get and set function:
    21. private static float _someFloatProperty = 30;
    22.     public static float SomeFloatProperty
    23.     {
    24.         get
    25.         {
    26.             return _someFloatProperty;
    27.         }
    28.  
    29.         set
    30.         {
    31.             someFloatProperty = value;
    32.         }
    33.     }
    34.  
    35. }
    36.  
    A class like this is never attached to a game object. I haven't tested for sure, but I think trying to do so may result in a compiler error, preventing a mistake or misuse of the class. When you want to call DoSomethingFromAnywhereInYourProgram() or change a variable, set/get a property, or whatever, from any script anywhere on any object in any scene, you just do this:

    Code (csharp):
    1.  
    2. //This is all in some other script somewhere:
    3. SomeManagerClass.DoSomethingFromAnywhereInYourProgram(gameObject) //Call a function.  Pass it the gameObject from this script or whatever you want the function to do.
    4.  
    5. SomeManagerClass.score = 5000;  //Setting a public float field directly
    6.  
    7. SomeManagerClass.SomeFloatProperty = 100 //Setting a public property directly
    8.  
    9. float getValue = SomeManagerClass.PadLengthPercent;  //Get a value from a property
    10.  
    There's no instance or object there like there would be in a singleton, so you don't end up having to do something like this:
    Code (csharp):
    1.  
    2. //-----DO NOT DO THIS-----
    3. SomeManagerClass.SomeObject.SomeFloatProperty = 100//
    4.  
    For my mind this is more straightforward and simple, and I never have to think about instantiating a SomeManagerClass object, even if it's only once for a game object. You can inherit from MonoBehavior with this whereas a static class will not let you do that. I don't think a singleton will let you do that either, but I might be remembering wrong. I used a singleton once earlier this year and never did it again.

    This turns out to be easier for me anyway and sounds like what the OP was looking for.