Skip to main content
Adding link for CRTP
Source Link
DMGregory
  • 136.3k
  • 22
  • 247
  • 373

This type of thing is often implemented using some form of the Singleton pattern. Here's one version, fairly similar to what you're doing now, just without the redundant double-search for the object, then the component, when all you really wanted was the component:

public class Player: MonoBehaviour {

     static Player _instance;
     public static Player instance {
         get {
             if(_instance == null) {
                 _instance = FindObjectOfType<Player>();    
                 UnityEngine.Assertions.Assert.IsNotNull(_instance, "Failed to find player component.");
             }

             return _instance;
         }
     }
}

Now other scripts can just ask for the current instance like this:

_player = Player.instance;

...and the singleton will look it up for them. It returns a cached copy quickly if it's been asked before, and only does the slow search the first time it's asked, or after the player's been destroyed and re-created.

You can also skip the search entirely and have your player "report" itself on load:

void Awake() { _instance = this; }

...but this can cause timing issues if you have other scripts that need to reference the player in their own Awake methods that happen to run before the player got a chance to do so. If you can safely defer all references to the player until Start or Update though, this is an option.

(As an aside, some folks find they use this pattern so much that they implement it in a Singleton<T> : MonoBehaviour where T: Singleton<T>, using the curiously recurring template patternthe curiously recurring template pattern, so they can quickly add it to any class by declaring it as Player : Singleton<Player>. This can help if you're worried about the amount of boilerplate this adds to every type you want to look up this way.)

You'll find folks are often critical of the singleton pattern for good reasons, though the risk of making the data global doesn't really apply here - as your code shows, access to the player object was already available globally.

So in this case, the main risk this method introduces is that it limits you to a single player at a time. If you ever want to have multiplayer with multiple instances of the Player class active in the scene at a time, this method only lets you find the first one, and so you have some heavy refactoring to do if you've got dozens of scripts that all find "the" player this way.

That's no worse than your current code, and it's acceptable for many Unity games. And it's still solvable. You can replace your instance property with a public static GetPlayer(int playerID) function, or a GetClosestPlayer(), etc. Then systematically replace each occurrence of Player.instance with the appropriate alternative. It's work, but not an insurmountable obstacle.

This type of thing is often implemented using some form of the Singleton pattern. Here's one version, fairly similar to what you're doing now, just without the redundant double-search for the object, then the component, when all you really wanted was the component:

public class Player: MonoBehaviour {

     static Player _instance;
     public static Player instance {
         get {
             if(_instance == null) {
                 _instance = FindObjectOfType<Player>();    
                 UnityEngine.Assertions.Assert.IsNotNull(_instance, "Failed to find player component.");
             }

             return _instance;
         }
     }
}

Now other scripts can just ask for the current instance like this:

_player = Player.instance;

...and the singleton will look it up for them. It returns a cached copy quickly if it's been asked before, and only does the slow search the first time it's asked, or after the player's been destroyed and re-created.

You can also skip the search entirely and have your player "report" itself on load:

void Awake() { _instance = this; }

...but this can cause timing issues if you have other scripts that need to reference the player in their own Awake methods that happen to run before the player got a chance to do so. If you can safely defer all references to the player until Start or Update though, this is an option.

(As an aside, some folks find they use this pattern so much that they implement it in a Singleton<T> : MonoBehaviour where T: Singleton<T>, using the curiously recurring template pattern, so they can quickly add it to any class by declaring it as Player : Singleton<Player>. This can help if you're worried about the amount of boilerplate this adds to every type you want to look up this way.)

You'll find folks are often critical of the singleton pattern for good reasons, though the risk of making the data global doesn't really apply here - as your code shows, access to the player object was already available globally.

So in this case, the main risk this method introduces is that it limits you to a single player at a time. If you ever want to have multiplayer with multiple instances of the Player class active in the scene at a time, this method only lets you find the first one, and so you have some heavy refactoring to do if you've got dozens of scripts that all find "the" player this way.

That's no worse than your current code, and it's acceptable for many Unity games. And it's still solvable. You can replace your instance property with a public static GetPlayer(int playerID) function, or a GetClosestPlayer(), etc. Then systematically replace each occurrence of Player.instance with the appropriate alternative. It's work, but not an insurmountable obstacle.

This type of thing is often implemented using some form of the Singleton pattern. Here's one version, fairly similar to what you're doing now, just without the redundant double-search for the object, then the component, when all you really wanted was the component:

public class Player: MonoBehaviour {

     static Player _instance;
     public static Player instance {
         get {
             if(_instance == null) {
                 _instance = FindObjectOfType<Player>();    
                 UnityEngine.Assertions.Assert.IsNotNull(_instance, "Failed to find player component.");
             }

             return _instance;
         }
     }
}

Now other scripts can just ask for the current instance like this:

_player = Player.instance;

...and the singleton will look it up for them. It returns a cached copy quickly if it's been asked before, and only does the slow search the first time it's asked, or after the player's been destroyed and re-created.

You can also skip the search entirely and have your player "report" itself on load:

void Awake() { _instance = this; }

...but this can cause timing issues if you have other scripts that need to reference the player in their own Awake methods that happen to run before the player got a chance to do so. If you can safely defer all references to the player until Start or Update though, this is an option.

(As an aside, some folks find they use this pattern so much that they implement it in a Singleton<T> : MonoBehaviour where T: Singleton<T>, using the curiously recurring template pattern, so they can quickly add it to any class by declaring it as Player : Singleton<Player>. This can help if you're worried about the amount of boilerplate this adds to every type you want to look up this way.)

You'll find folks are often critical of the singleton pattern for good reasons, though the risk of making the data global doesn't really apply here - as your code shows, access to the player object was already available globally.

So in this case, the main risk this method introduces is that it limits you to a single player at a time. If you ever want to have multiplayer with multiple instances of the Player class active in the scene at a time, this method only lets you find the first one, and so you have some heavy refactoring to do if you've got dozens of scripts that all find "the" player this way.

That's no worse than your current code, and it's acceptable for many Unity games. And it's still solvable. You can replace your instance property with a public static GetPlayer(int playerID) function, or a GetClosestPlayer(), etc. Then systematically replace each occurrence of Player.instance with the appropriate alternative. It's work, but not an insurmountable obstacle.

Adding note on re-use.
Source Link
DMGregory
  • 136.3k
  • 22
  • 247
  • 373

This type of thing is often implemented using some form of the Singleton pattern. Here's one version, fairly similar to what you're doing now, just without the redundant double-search for the object, then the component, when all you really wanted was the component:

public class Player: MonoBehaviour {

     static Player _instance;
     public static Player instance {
         get {
             if(_instance == null) {
                 _instance = FindObjectOfType<Player>();
     
                 UnityEngine.Assertions.Assert.IsNotNull(_instance, "Failed to find player component.");
             }

             return _instance;
         }
     }
}

Now other scripts can just ask for the current instance like this:

_player = Player.instance;

...and the singleton will look it up for them. It returns a cached copy quickly if it's been asked before, and only does the slow search the first time it's asked, or after the player's been destroyed and re-created.

You can also skip the search entirely and have your player "report" itself on load:

void Awake() { _instance = this; }

...but this can cause timing issues if you have other scripts that need to reference the player in their own Awake methods that happen to run before the player got a chance to do so. If you can safely defer all references to the player until Start or Update though, this is an option.

(As an aside, some folks find they use this pattern so much that they implement it in a Singleton<T> : MonoBehaviour where T: Singleton<T>, using the curiously recurring template pattern, so they can quickly add it to any class by declaring it as Player : Singleton<Player>. This can help if you're worried about the amount of boilerplate this adds to every type you want to look up this way.)

You'll find folks are often critical of the singleton pattern for good reasons, though the risk of making the data global doesn't really apply here - as your code shows, access to the player object was already available globally.

So in this case, the main risk this method introduces is that it limits you to a single player at a time. If you ever want to have multiplayer with multiple instances of the Player class active in the scene at a time, this method only lets you find the first one, and so you have some heavy refactoring to do if you've got dozens of scripts that all find "the" player this way.

That's no worse than your current code, and it's acceptable for many Unity games. And it's still solvable. You can replace your instance property with a public static GetPlayer(int playerID) function, or a GetClosestPlayer(), etc. Then systematically replace each occurrence of Player.instance with the appropriate alternative. It's work, but not an insurmountable obstacle.

This type of thing is often implemented using some form of the Singleton pattern. Here's one version, fairly similar to what you're doing now, just without the redundant double-search for the object, then the component, when all you really wanted was the component:

public class Player: MonoBehaviour {

     static Player _instance;
     public static Player instance {
         get {
             if(_instance == null)
                 _instance = FindObjectOfType<Player>();
 
             UnityEngine.Assertions.Assert.IsNotNull(_instance, "Failed to find player component.");

             return _instance;
         }
     }
}

Now other scripts can just ask for the current instance like this:

_player = Player.instance;

...and the singleton will look it up for them. It returns a cached copy quickly if it's been asked before, and only does the slow search the first time it's asked, or after the player's been destroyed and re-created.

You can also skip the search entirely and have your player "report" itself on load:

void Awake() { _instance = this; }

...but this can cause timing issues if you have other scripts that need to reference the player in their own Awake methods that happen to run before the player got a chance to do so. If you can safely defer all references to the player until Start or Update though, this is an option.

(As an aside, some folks find they use this pattern so much that they implement it in a Singleton<T> : MonoBehaviour, using the curiously recurring template pattern, so they can quickly add it to any class by declaring it as Player : Singleton<Player>. This can help if you're worried about the amount of boilerplate this adds to every type you want to look up this way.)

You'll find folks are often critical of the singleton pattern for good reasons, though the risk of making the data global doesn't really apply here - as your code shows, access to the player object was already available globally.

So in this case, the main risk this method introduces is that it limits you to a single player at a time. If you ever want to have multiplayer with multiple instances of the Player class active in the scene at a time, this method only lets you find the first one, and so you have some heavy refactoring to do if you've got dozens of scripts that all find "the" player this way.

That's no worse than your current code, and it's acceptable for many Unity games. And it's still solvable. You can replace your instance property with a public static GetPlayer(int playerID) function, or a GetClosestPlayer(), etc. Then systematically replace each occurrence of Player.instance with the appropriate alternative. It's work, but not an insurmountable obstacle.

This type of thing is often implemented using some form of the Singleton pattern. Here's one version, fairly similar to what you're doing now, just without the redundant double-search for the object, then the component, when all you really wanted was the component:

public class Player: MonoBehaviour {

     static Player _instance;
     public static Player instance {
         get {
             if(_instance == null) {
                 _instance = FindObjectOfType<Player>();    
                 UnityEngine.Assertions.Assert.IsNotNull(_instance, "Failed to find player component.");
             }

             return _instance;
         }
     }
}

Now other scripts can just ask for the current instance like this:

_player = Player.instance;

...and the singleton will look it up for them. It returns a cached copy quickly if it's been asked before, and only does the slow search the first time it's asked, or after the player's been destroyed and re-created.

You can also skip the search entirely and have your player "report" itself on load:

void Awake() { _instance = this; }

...but this can cause timing issues if you have other scripts that need to reference the player in their own Awake methods that happen to run before the player got a chance to do so. If you can safely defer all references to the player until Start or Update though, this is an option.

(As an aside, some folks find they use this pattern so much that they implement it in a Singleton<T> : MonoBehaviour where T: Singleton<T>, using the curiously recurring template pattern, so they can quickly add it to any class by declaring it as Player : Singleton<Player>. This can help if you're worried about the amount of boilerplate this adds to every type you want to look up this way.)

You'll find folks are often critical of the singleton pattern for good reasons, though the risk of making the data global doesn't really apply here - as your code shows, access to the player object was already available globally.

So in this case, the main risk this method introduces is that it limits you to a single player at a time. If you ever want to have multiplayer with multiple instances of the Player class active in the scene at a time, this method only lets you find the first one, and so you have some heavy refactoring to do if you've got dozens of scripts that all find "the" player this way.

That's no worse than your current code, and it's acceptable for many Unity games. And it's still solvable. You can replace your instance property with a public static GetPlayer(int playerID) function, or a GetClosestPlayer(), etc. Then systematically replace each occurrence of Player.instance with the appropriate alternative. It's work, but not an insurmountable obstacle.

Adding note on re-use.
Source Link
DMGregory
  • 136.3k
  • 22
  • 247
  • 373

This type of thing is often implemented using some form of the Singleton pattern. Here's one version, fairly similar to what you're doing now, just without the redundant double-search for the object, then the component, when all you really wanted was the component:

public class Player: MonoBehaviour {

     static Player _instance;
     public static Player instance {
         get {
             if(_instance == null)
                 _instance = FindObjectOfType<Player>();

             UnityEngine.Assertions.Assert.IsNotNull(_instance, "Failed to find player component.");

             return _instance;
         }
     }
}

Now other scripts can just ask for the current instance like this:

_player = Player.instance;

...and the singleton will look it up for them. It returns a cached copy quickly if it's been asked before, and only does the slow search the first time it's asked, or after the player's been destroyed and re-created.

You can also skip the search entirely and have your player "report" itself on load:

void Awake() { _instance = this; }

...but this can cause timing issues if you have other scripts that need to reference the player in their own Awake methods that happen to run before the player got a chance to do so. If you can safely defer all references to the player until Start or Update though, this is an option.

(As an aside, some folks find they use this pattern so much that they implement it in a Singleton<T> : MonoBehaviour, using the curiously recurring template pattern, so they can quickly add it to any class by declaring it as Player : Singleton<Player>. This can help if you're worried about the amount of boilerplate this adds to every type you want to look up this way.)

You'll find folks are often critical of the singleton pattern for good reasons, though the risk of making the data global doesn't really apply here - as your code shows, access to the player object was already available globally.

So in this case, the main risk this method introduces is that it limits you to a single player at a time. If you ever want to have multiplayer with multiple instances of the Player class active in the scene at a time, this method only lets you find the first one, and so you have some heavy refactoring to do if you've got dozens of scripts that all find "the" player this way.

That's no worse than your current code, and it's acceptable for many Unity games. And it's still solvable. You can replace your instance property with a public static GetPlayer(int playerID) function, or a GetClosestPlayer(), etc. Then systematically replace each occurrence of Player.instance with the appropriate alternative. It's work, but not an insurmountable obstacle.

This type of thing is often implemented using some form of the Singleton pattern. Here's one version, fairly similar to what you're doing now, just without the redundant double-search for the object, then the component, when all you really wanted was the component:

public class Player: MonoBehaviour {

     static Player _instance;
     public static Player instance {
         get {
             if(_instance == null)
                 _instance = FindObjectOfType<Player>();

             UnityEngine.Assertions.Assert.IsNotNull(_instance, "Failed to find player component.");

             return _instance;
         }
     }
}

Now other scripts can just ask for the current instance like this:

_player = Player.instance;

...and the singleton will look it up for them. It returns a cached copy quickly if it's been asked before, and only does the slow search the first time it's asked, or after the player's been destroyed and re-created.

You can also skip the search entirely and have your player "report" itself on load:

void Awake() { _instance = this; }

...but this can cause timing issues if you have other scripts that need to reference the player in their own Awake methods that happen to run before the player got a chance to do so. If you can safely defer all references to the player until Start or Update though, this is an option.

You'll find folks are often critical of the singleton pattern for good reasons, though the risk of making the data global doesn't really apply here - as your code shows, access to the player object was already available globally.

So in this case, the main risk this method introduces is that it limits you to a single player at a time. If you ever want to have multiplayer with multiple instances of the Player class active in the scene at a time, this method only lets you find the first one, and so you have some heavy refactoring to do if you've got dozens of scripts that all find "the" player this way.

That's no worse than your current code, and it's acceptable for many Unity games. And it's still solvable. You can replace your instance property with a public static GetPlayer(int playerID) function, or a GetClosestPlayer(), etc. Then systematically replace each occurrence of Player.instance with the appropriate alternative. It's work, but not an insurmountable obstacle.

This type of thing is often implemented using some form of the Singleton pattern. Here's one version, fairly similar to what you're doing now, just without the redundant double-search for the object, then the component, when all you really wanted was the component:

public class Player: MonoBehaviour {

     static Player _instance;
     public static Player instance {
         get {
             if(_instance == null)
                 _instance = FindObjectOfType<Player>();

             UnityEngine.Assertions.Assert.IsNotNull(_instance, "Failed to find player component.");

             return _instance;
         }
     }
}

Now other scripts can just ask for the current instance like this:

_player = Player.instance;

...and the singleton will look it up for them. It returns a cached copy quickly if it's been asked before, and only does the slow search the first time it's asked, or after the player's been destroyed and re-created.

You can also skip the search entirely and have your player "report" itself on load:

void Awake() { _instance = this; }

...but this can cause timing issues if you have other scripts that need to reference the player in their own Awake methods that happen to run before the player got a chance to do so. If you can safely defer all references to the player until Start or Update though, this is an option.

(As an aside, some folks find they use this pattern so much that they implement it in a Singleton<T> : MonoBehaviour, using the curiously recurring template pattern, so they can quickly add it to any class by declaring it as Player : Singleton<Player>. This can help if you're worried about the amount of boilerplate this adds to every type you want to look up this way.)

You'll find folks are often critical of the singleton pattern for good reasons, though the risk of making the data global doesn't really apply here - as your code shows, access to the player object was already available globally.

So in this case, the main risk this method introduces is that it limits you to a single player at a time. If you ever want to have multiplayer with multiple instances of the Player class active in the scene at a time, this method only lets you find the first one, and so you have some heavy refactoring to do if you've got dozens of scripts that all find "the" player this way.

That's no worse than your current code, and it's acceptable for many Unity games. And it's still solvable. You can replace your instance property with a public static GetPlayer(int playerID) function, or a GetClosestPlayer(), etc. Then systematically replace each occurrence of Player.instance with the appropriate alternative. It's work, but not an insurmountable obstacle.

Source Link
DMGregory
  • 136.3k
  • 22
  • 247
  • 373
Loading