Last active
March 7, 2024 07:57
-
-
Save FleshMobProductions/a73b4c49db3c02925346a0922fd61e40 to your computer and use it in GitHub Desktop.
2 approaches to cache single instances of Unity objects in a globally accessible class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UObject = UnityEngine.Object; | |
namespace FMPUtils | |
{ | |
// Usage: UnityObjectInstance<Player>.Instance | |
public static class UnityObjectInstance<T> where T : UObject | |
{ | |
private static T instance; | |
public static T Instance | |
{ | |
get | |
{ | |
if (instance == null) | |
{ | |
instance = UObject.FindObjectOfType<T>(); | |
if (instance == null) | |
Debug.Log($"No instance of type {typeof(T)} found"); | |
} | |
return instance; | |
} | |
set => instance = value; | |
} | |
// Method not called on abstract classes, luckily instances are destroyed when exiting | |
// Playmode anyways. so the Instance references will become null | |
// The other approach would be to find all UnityObjectInstance types possibly via | |
// reflection and then call the Clear method on them | |
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] | |
private static void Clear() | |
{ | |
Instance = null; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UObject = UnityEngine.Object; | |
namespace FMPUtils | |
{ | |
public static class UnityObjectInstanceCache | |
{ | |
private static Dictionary<Type, UObject> instanceMap = new Dictionary<Type, UObject>(); | |
private static Dictionary<Type, UObject> interfaceInstanceMap = new Dictionary<Type, UObject>(); | |
public static T GetInstance<T>() where T : UObject | |
{ | |
UObject instanceAsObj; | |
bool wasFound = instanceMap.TryGetValue(typeof(T), out instanceAsObj); | |
if (wasFound && instanceAsObj != null) | |
return instanceAsObj as T; | |
T instance = UObject.FindObjectOfType<T>(); | |
if (instance != null) | |
instanceMap[typeof(T)] = instance; | |
else | |
{ | |
Debug.Log($"No instance of type {typeof(T)} found"); | |
if (wasFound) | |
instanceMap.Remove(typeof(T)); | |
} | |
return instance; | |
} | |
public static T GetInterfaceInstance<T>() where T : class | |
{ | |
if (!typeof(T).IsInterface) | |
throw new ArgumentException($"Passed type {typeof(T)} is not an interface"); | |
UObject instanceAsObj; | |
bool wasFound = instanceMap.TryGetValue(typeof(T), out instanceAsObj); | |
if (wasFound && instanceAsObj != null) | |
return instanceAsObj as T; | |
T instance = UObject.FindObjectOfType(typeof(T)) as T; | |
if (instance != null) | |
instanceMap[typeof(T)] = instance as UObject; | |
else | |
{ | |
Debug.Log($"No instance of type {typeof(T)} found"); | |
if (wasFound) | |
instanceMap.Remove(typeof(T)); | |
} | |
return instance; | |
} | |
public static bool ContainsInstance<T>() where T : UObject | |
{ | |
return instanceMap.ContainsKey(typeof(T)); | |
} | |
public static bool ContainsInterfaceInstance<T>() where T : class | |
{ | |
if (!typeof(T).IsInterface) | |
throw new ArgumentException($"Passed type {typeof(T)} is not an interface"); | |
return interfaceInstanceMap.ContainsKey(typeof(T)); | |
} | |
// Register instances in Awake() when the game/scene loads, so other scripts can access them in Start() | |
// This will prevent FindObjectOfType calls when properly setup | |
public static void RegisterIntance<T>(T instance) where T : UObject | |
{ | |
if (instance != null) | |
instanceMap[typeof(T)] = instance; | |
} | |
public static void RegisterInterfaceInstance<ObjectInterface,T>(T instance) where T : UObject, ObjectInterface | |
{ | |
Type interfaceType = typeof(ObjectInterface); | |
if (!interfaceType.IsInterface) | |
throw new ArgumentException($"Passed type {interfaceType} is not an interface"); | |
if (instance != null) | |
interfaceInstanceMap[interfaceType] = instance; | |
} | |
// Reset static state if "Domain Reloading" is disabled | |
#if UNITY_2019_2_OR_NEWER | |
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] | |
#endif | |
private static void Clear() | |
{ | |
instanceMap.Clear(); | |
interfaceInstanceMap.Clear(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment