Singleton

From Unify Community Wiki
(Difference between revisions)
Jump to: navigation, search
(Component-based example)
(Added example of using static methods for singleton functionality)
Line 27: Line 27:
 
private static MySingleton instance;
 
private static MySingleton instance;
 
 
public MySingleton()  
+
public MySingleton ()  
 
{
 
{
if( instance != null )
+
if (instance != null)
 
{
 
{
Debug.LogError( "Cannot have two instances of singleton. Self destruction in 3..." );
+
Debug.LogError ("Cannot have two instances of singleton. Self destruction in 3...");
 
return;
 
return;
 
}
 
}
Line 42: Line 42:
 
get
 
get
 
{
 
{
if( instance == null )
+
if (instance == null)
 
{
 
{
new MySingleton();
+
new MySingleton ();
 
}
 
}
 
 
Line 67: Line 67:
 
{
 
{
 
go = new GameObject ("MySingleton");
 
go = new GameObject ("MySingleton");
instance = (MySingleton) go.AddComponent (typeof (MySingleton));
+
instance = (MySingleton)go.AddComponent (typeof (MySingleton));
 
}
 
}
  
Line 74: Line 74:
 
}
 
}
 
 
public void OnApplicationQuit()
+
public void OnApplicationQuit ()
 
{
 
{
 
instance = null;
 
instance = null;
Line 83: Line 83:
 
The singleton in this example keeps track of the game score. Getting and setting this value is done like so:
 
The singleton in this example keeps track of the game score. Getting and setting this value is done like so:
 
<csharp>MySingleton.Instance.Score += 5;
 
<csharp>MySingleton.Instance.Score += 5;
Debug.Log( "Score is now: " + MySingleton.Instance.Score );</csharp>
+
Debug.Log ("Score is now: " + MySingleton.Instance.Score);</csharp>
  
 
And the singleton class:
 
And the singleton class:
Line 90: Line 90:
 
     private static MySingleton instance;
 
     private static MySingleton instance;
 
      
 
      
     public MySingleton()  
+
     public MySingleton ()  
 
     {
 
     {
         if( instance != null )
+
         if (instance != null)
 
         {
 
         {
             Debug.LogError( "Cannot have two instances of singleton. Self destruction in 3..." );
+
             Debug.LogError ("Cannot have two instances of singleton. Self destruction in 3...");
 
             return;
 
             return;
 
         }
 
         }
Line 105: Line 105:
 
         get
 
         get
 
         {
 
         {
             if( instance == null )
+
             if (instance == null)
 
             {
 
             {
                 new MySingleton();
+
                 new MySingleton ();
 
             }
 
             }
 
              
 
              
Line 135: Line 135:
 
== Time tracking and GameOver broadcasting singleton ==
 
== Time tracking and GameOver broadcasting singleton ==
 
This singleton works similarly to the score tracking singleton by also maintaining a list of GameObjects which register and unregister themselves with the singleton in order to receive a "GameOver" message when the tracked timer reaches zero or lower. The timer is set just like the score is in the singleton above and GameObjects register and unregister with the singleton like so:
 
This singleton works similarly to the score tracking singleton by also maintaining a list of GameObjects which register and unregister themselves with the singleton in order to receive a "GameOver" message when the tracked timer reaches zero or lower. The timer is set just like the score is in the singleton above and GameObjects register and unregister with the singleton like so:
<csharp>MySingleton.Instance.Register( gameObject );
+
<csharp>MySingleton.Instance.Register (gameObject);
MySingleton.Instance.Unregister( gameObject );</csharp>
+
MySingleton.Instance.Unregister (gameObject);</csharp>
 
Registering and unregistering would likely make sense to do in Awake and OnDisable of a script attached to the GameObjects needing it.
 
Registering and unregistering would likely make sense to do in Awake and OnDisable of a script attached to the GameObjects needing it.
 
And the singleton class:
 
And the singleton class:
Line 148: Line 148:
 
     private static MySingleton instance;
 
     private static MySingleton instance;
 
      
 
      
     public MySingleton()  
+
     public MySingleton ()  
 
     {
 
     {
         if( instance != null )
+
         if (instance != null)
 
         {
 
         {
             Debug.LogError( "Cannot have two instances of singleton. Self destruction in 3..." );
+
             Debug.LogError ("Cannot have two instances of singleton. Self destruction in 3...");
 
             return;
 
             return;
 
         }
 
         }
 
          
 
          
 
         instance = this;
 
         instance = this;
         Init();
+
         Init ();
 
     }
 
     }
 
      
 
      
Line 164: Line 164:
 
         get
 
         get
 
         {
 
         {
             if( instance == null )
+
             if (instance == null)
 
             {
 
             {
                 new MySingleton();
+
                 new MySingleton ();
 
             }
 
             }
 
              
 
              
Line 180: Line 180:
 
 
 
 
private void Init()
+
private void Init ()
 
{
 
{
listeners = new ArrayList();
+
listeners = new ArrayList ();
 
}
 
}
 
 
Line 196: Line 196:
 
{
 
{
 
timer = value;
 
timer = value;
if( timer <= 0 )
+
if (timer <= 0)
 +
{
 +
foreach (GameObject listener in listeners)
 +
{
 +
listener.SendMessage ("GameOver");
 +
}
 +
}
 +
}
 +
}
 +
 +
 +
 +
public GameObject RegisterListener (GameObject listener)
 +
{
 +
listeners.Add (listener);
 +
 +
return listener;
 +
}
 +
 +
 +
 +
public bool UnregisterListener (GameObject listener)
 +
{
 +
if (!listeners.Contains (listener))
 +
{
 +
return false;
 +
}
 +
 +
listeners.Remove (listener);
 +
}
 +
}</csharp>
 +
 
 +
== Mapping static methods to singleton methods ==
 +
Having to go through the Instance property for every function of the singleton gets old fast. Really the user most of the time does not need to know that he is dealing with a singleton, so this:
 +
<csharp>MySingleton.Instance.Register( gameObject );
 +
MySingleton.Instance.Unregister( gameObject );</csharp>
 +
is really quite simple when it should just be this:
 +
<csharp>MySingleton.Register (gameObject);
 +
MySingleton.Unregister (gameObject);</csharp>
 +
To make the above true, simply make your methods static and have *them* take the pain of going through the Instance property - like so:
 +
<csharp>using System.Collections;
 +
using UnityEngine;
 +
 
 +
 
 +
 
 +
public class MySingleton
 +
{
 +
    private static MySingleton instance;
 +
   
 +
    public MySingleton ()
 +
    {
 +
        if (instance != null)
 +
        {
 +
            Debug.LogError ("Cannot have two instances of singleton. Self destruction in 3...");
 +
            return;
 +
        }
 +
       
 +
        instance = this;
 +
        Init ();
 +
    }
 +
   
 +
    private static MySingleton Instance
 +
    {
 +
        get
 +
        {
 +
            if (instance == null)
 +
            {
 +
                new MySingleton ();
 +
            }
 +
           
 +
            return instance;
 +
        }
 +
    }
 +
 
 +
 
 +
 
 +
private int timer;
 +
private ArrayList listeners;
 +
 +
 +
 +
private void Init ()
 +
{
 +
listeners = new ArrayList ();
 +
}
 +
 +
 +
 +
public static int Timer
 +
{
 +
get
 +
{
 +
return Instance.timer;
 +
}
 +
set
 +
{
 +
Instance.timer = value;
 +
if (value <= 0)
 
{
 
{
foreach( GameObject listener in listeners )
+
foreach (GameObject listener in Instance.listeners)
 
{
 
{
listener.SendMessage( "GameOver" );
+
listener.SendMessage ("GameOver");
 
}
 
}
 
}
 
}
Line 208: Line 305:
 
 
 
 
public GameObject RegisterListener( GameObject listener )
+
public static GameObject RegisterListener (GameObject listener)
 
{
 
{
listeners.Add( listener );
+
Instance.listeners.Add (listener);
 
 
 
return listener;
 
return listener;
Line 217: Line 314:
 
 
 
 
public bool UnregisterListener( GameObject listener )
+
public static bool UnregisterListener (GameObject listener)
 
{
 
{
if( !listeners.Contains( listener ) )
+
if (!Instance.listeners.Contains (listener))
 
{
 
{
 
return false;
 
return false;
 
}
 
}
 
 
listeners.Remove( listener );
+
Instance.listeners.Remove (listener);
 
}
 
}
 
}</csharp>
 
}</csharp>
 +
Voilá! Less cruft in the world! Everyone rejoice!

Revision as of 12:09, 4 May 2010

By AngryAnt.

Contents

Description

People have recently asked about singleton creation quite often in the IRC channel so rather than retyping a basic implementation each time, I'll have this to link to. Yay! :)

Curious, but not quite sure what a singleton is? Ask a friend: [1]

Singletons are generally handy for providing easy access to game state and control code. I've provided example implementation for a basic class type which needn't be attached to a game object in order to function and after this an implementation which works as any other component.

Members of both singleton types are accessed the same way:

<csharp>MySingleton.Instance.MySingletonMember;</csharp>

Note, however that for the component-based singleton (the second implementation), you shouldn't attempt to access the instance earlier than in Start of the calling component.

The non-component example

<csharp>public class MySingleton { private static MySingleton instance;

public MySingleton () { if (instance != null) { Debug.LogError ("Cannot have two instances of singleton. Self destruction in 3..."); return; }

instance = this; }

public static MySingleton Instance { get { if (instance == null) { new MySingleton (); }

return instance; } } }</csharp>

Component-based example

<csharp>using UnityEngine;

public class MySingleton : MonoBehaviour { private static MySingleton instance;

public static MySingleton Instance { get { GameObject go;

if (instance == null) { go = new GameObject ("MySingleton"); instance = (MySingleton)go.AddComponent (typeof (MySingleton)); }

return instance; } }

public void OnApplicationQuit () { instance = null; } }</csharp>

Score tracking singleton

The singleton in this example keeps track of the game score. Getting and setting this value is done like so: <csharp>MySingleton.Instance.Score += 5; Debug.Log ("Score is now: " + MySingleton.Instance.Score);</csharp>

And the singleton class: <csharp>public class MySingleton {

   private static MySingleton instance;
   
   public MySingleton () 
   {
       if (instance != null)
       {
           Debug.LogError ("Cannot have two instances of singleton. Self destruction in 3...");
           return;
       }
       
       instance = this;
   }
   
   public static MySingleton Instance
   {
       get
       {
           if (instance == null)
           {
               new MySingleton ();
           }
           
           return instance;
       }
   }


private int score;


public int Score { get { return score; } set { score = value; } } }</csharp>

Time tracking and GameOver broadcasting singleton

This singleton works similarly to the score tracking singleton by also maintaining a list of GameObjects which register and unregister themselves with the singleton in order to receive a "GameOver" message when the tracked timer reaches zero or lower. The timer is set just like the score is in the singleton above and GameObjects register and unregister with the singleton like so: <csharp>MySingleton.Instance.Register (gameObject); MySingleton.Instance.Unregister (gameObject);</csharp> Registering and unregistering would likely make sense to do in Awake and OnDisable of a script attached to the GameObjects needing it. And the singleton class: <csharp>using System.Collections; using UnityEngine;


public class MySingleton {

   private static MySingleton instance;
   
   public MySingleton () 
   {
       if (instance != null)
       {
           Debug.LogError ("Cannot have two instances of singleton. Self destruction in 3...");
           return;
       }
       
       instance = this;
       Init ();
   }
   
   public static MySingleton Instance
   {
       get
       {
           if (instance == null)
           {
               new MySingleton ();
           }
           
           return instance;
       }
   }


private int timer; private ArrayList listeners;


private void Init () { listeners = new ArrayList (); }


public int Timer { get { return timer; } set { timer = value; if (timer <= 0) { foreach (GameObject listener in listeners) { listener.SendMessage ("GameOver"); } } } }


public GameObject RegisterListener (GameObject listener) { listeners.Add (listener);

return listener; }


public bool UnregisterListener (GameObject listener) { if (!listeners.Contains (listener)) { return false; }

listeners.Remove (listener); } }</csharp>

Mapping static methods to singleton methods

Having to go through the Instance property for every function of the singleton gets old fast. Really the user most of the time does not need to know that he is dealing with a singleton, so this: <csharp>MySingleton.Instance.Register( gameObject ); MySingleton.Instance.Unregister( gameObject );</csharp> is really quite simple when it should just be this: <csharp>MySingleton.Register (gameObject); MySingleton.Unregister (gameObject);</csharp> To make the above true, simply make your methods static and have *them* take the pain of going through the Instance property - like so: <csharp>using System.Collections; using UnityEngine;


public class MySingleton {

   private static MySingleton instance;
   
   public MySingleton () 
   {
       if (instance != null)
       {
           Debug.LogError ("Cannot have two instances of singleton. Self destruction in 3...");
           return;
       }
       
       instance = this;
       Init ();
   }
   
   private static MySingleton Instance
   {
       get
       {
           if (instance == null)
           {
               new MySingleton ();
           }
           
           return instance;
       }
   }


private int timer; private ArrayList listeners;


private void Init () { listeners = new ArrayList (); }


public static int Timer { get { return Instance.timer; } set { Instance.timer = value; if (value <= 0) { foreach (GameObject listener in Instance.listeners) { listener.SendMessage ("GameOver"); } } } }


public static GameObject RegisterListener (GameObject listener) { Instance.listeners.Add (listener);

return listener; }


public static bool UnregisterListener (GameObject listener) { if (!Instance.listeners.Contains (listener)) { return false; }

Instance.listeners.Remove (listener); } }</csharp> Voilá! Less cruft in the world! Everyone rejoice!

Personal tools
Namespaces

Variants
Actions
Navigation
Extras
Toolbox