Skip to content

Instantly share code, notes, and snippets.

@timofei7
Last active October 1, 2022 10:06
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timofei7/fed468b0d23c58875bb9 to your computer and use it in GitHub Desktop.
Save timofei7/fed468b0d23c58875bb9 to your computer and use it in GitHub Desktop.
unity3d c# singleton class with automatic prefab loading
using UnityEngine;
using System.Collections;
using System;
/// <summary>
/// Prefab attribute. Use this on child classes
/// to define if they have a prefab associated or not
/// By default will attempt to load a prefab
/// that has the same name as the class,
/// otherwise [Prefab("path/to/prefab")]
/// to define it specifically.
/// </summary>
[AttributeUsage(AttributeTargets.Class,Inherited = true)]
public class PrefabAttribute : Attribute
{
string _name;
public string Name { get { return this._name; } }
public PrefabAttribute() { this._name = ""; }
public PrefabAttribute(string name) { this._name = name; }
}
/// <summary>
/// MONOBEHAVIOR PSEUDO SINGLETON ABSTRACT CLASS
/// usage : can be attached to a gameobject and if not
/// : this will create one on first access
/// example : '''public sealed class MyClass : Singleton<MyClass> {'''
/// references : http://tinyurl.com/d498g8c
/// : http://tinyurl.com/cc73a9h
/// : http://unifycommunity.com/wiki/index.php?title=Singleton
/// </summary>
public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T _instance = null;
public static bool IsAwake { get { return (_instance != null); } }
/// <summary>
/// gets the instance of this Singleton
/// use this for all instance calls:
/// MyClass.Instance.MyMethod();
/// or make your public methods static
/// and have them use Instance internally
/// for a nice clean interface
/// </summary>
public static T Instance {
get {
Type mytype = typeof(T);
if (_instance == null) {
_instance = (T)FindObjectOfType (mytype);
if (_instance == null) {
//Debug.Log("initializing instance of: " + mytype.Name);
string goName = mytype.ToString ();
GameObject go = GameObject.Find (goName);
if (go == null) // try again searching for a cloned object
{
go = GameObject.Find (goName+"(Clone)");
if (go != null)
{
//Debug.Log("found clone of object using it!");
}
}
if (go == null) //if still not found try prefab or create
{
bool hasPrefab = Attribute.IsDefined(mytype, typeof(PrefabAttribute));
// checks if the [Prefab] attribute is set and pulls that if it can
if (hasPrefab)
{
PrefabAttribute attr = (PrefabAttribute)Attribute.GetCustomAttribute(mytype,typeof(PrefabAttribute));
string prefabname = attr.Name;
//Debug.LogWarning(goName + " not found attempting to instantiate prefab... either: " + goName + " or: " + prefabname);
try
{
if (prefabname != "")
{
go = (GameObject)Instantiate(Resources.Load(prefabname, typeof(GameObject)));
}
else
{
go = (GameObject)Instantiate(Resources.Load(goName, typeof(GameObject)));
}
} catch (Exception e)
{
Debug.LogError("could not instantiate prefab even though prefab attribute was set: " + e.Message + "\n" + e.StackTrace);
}
}
if (go == null)
{
//Debug.LogWarning(goName + " not found creating...");
go = new GameObject ();
go.name = goName;
}
}
_instance = go.GetComponent<T>();
if (_instance == null)
{
_instance = go.AddComponent<T>();
}
}
else
{
//Debug.Log(mytype.Name + " had to be searched for but was found");
int count = FindObjectsOfType(mytype).Length;
if (count > 1)
{
Debug.LogError("Singleton: there are " + count.ToString() + " of " + mytype.Name);
throw new Exception("Too many (" + count.ToString() + ") prefab singletons of type: " + mytype.Name);
}
}
}
return _instance;
}
}
/// <summary>
/// for garbage collection
/// </summary>
public virtual void OnApplicationQuit ()
{
// release reference on exit
_instance = null;
}
// in your child class you can implement Awake()
// and add any initialization code you want such as
// DontDestroyOnLoad(this.gameObject);
// if you want this to persist across loads
// or if you want to set a parent object with SetParent()
/// <summary>
/// parent this to another gameobject by string
/// call from Awake if you so desire
/// </summary>
protected void SetParent (string parentGOName)
{
if (parentGOName != null) {
GameObject parentGO = GameObject.Find (parentGOName);
if (parentGO == null) {
parentGO = new GameObject ();
parentGO.name = parentGOName;
parentGO.transform.parent = null;
}
this.transform.parent = parentGO.transform;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment