Clases de administrador singleton de Unity

En Unity, ¿cuál es una buena forma de crear un administrador de juegos singleton al que se pueda acceder en todas partes como una clase global con variables estáticas que escupirán los mismos valores constantes a cada clase que extraiga esos valores? ¿Y cuál sería la forma de implementarlo en Unity? ¿Tengo que adjuntarlo a un GameObject? ¿Puede estar allí en una carpeta sin estar en la escena visualmente?

Como siempre: depende. Utilizo singletons de ambos tipos, componentes adjuntos a GameObject y clases independientes no derivadas de MonoBehaviour . IMO, la pregunta general es cómo están las instancias vinculadas al ciclo de vida de las escenas, los objetos del juego, … Y para no olvidar, a veces es más conveniente tener un componente que haga referencia especialmente a otros objetos MonoBehaviour es más fácil y seguro.

  1. Hay clases que solo necesitan proporcionar algunos valores como, por ejemplo, una clase de configuración que necesita cargar configuraciones desde la capa de persistencia cuando se llama. Yo diseño estas clases como simples singletons.
  2. Por otro lado, algunos objetos necesitan saber cuándo se inicia una escena, es decir, se llama a Start o se deben realizar acciones en Update u otros métodos. Luego los implemento como componente y los adjunto a un objeto del juego que sobrevive al cargar nuevas escenas.

GameObject singletons basados ​​en componentes (tipo 2) con dos partes: un GameObject persistente llamado Main , que contiene todos los componentes y un singleton plano (tipo 1) llamado MainComponentManager para su administración. Algunos códigos de demostración:

 public class MainComponentManger { private static MainComponentManger instance; public static void CreateInstance () { if (instance == null) { instance = new MainComponentManger (); GameObject go = GameObject.Find ("Main"); if (go == null) { go = new GameObject ("Main"); instance.main = go; // important: make game object persistent: Object.DontDestroyOnLoad (go); } // trigger instantiation of other singletons Component c = MenuManager.SharedInstance; // ... } } GameObject main; public static MainComponentManger SharedInstance { get { if (instance == null) { CreateInstance (); } return instance; } } public static T AddMainComponent  () where T : UnityEngine.Component { T t = SharedInstance.main.GetComponent (); if (t != null) { return t; } return SharedInstance.main.AddComponent  (); } 

Ahora otros singletons que quieren registrarse como componente Main ven así:

 public class AudioManager : MonoBehaviour { private static AudioManager instance = null; public static AudioManager SharedInstance { get { if (instance == null) { instance = MainComponentManger.AddMainComponent (); } return instance; } } 

Los ingenieros que son nuevos en Unity a menudo no notan que

no puede tener un “singleton” en un sistema ECS.

No tiene sentido

Todo lo que tienes en Unity es GameObjects, at, XYZ positions. Pueden tener componentes adjuntos.

Sería como tratar de tener “un singleton” o “herencia” en …. Photoshop o Microsoft Word.

Archivo de Photoshop : píxeles en posiciones XY
Archivo de editor de texto – letras en posiciones X
Archivo de unidad – GameObjects en posiciones XYZ

Es así de sencillo”.

Es absolutamente necesario tener una escena de precarga de todos modos, por supuesto, en todos los proyectos de Unity.

Instrucciones increíblemente simples: https://stackoverflow.com/a/35891919/294884

Es tan simple que no es un problema.

Una vez que Unity incluye una “escena de precarga incorporada” (es decir, para ahorrarle un clic al crear una), esto finalmente nunca será discutido nuevamente.

(Nota A: algunos de los lenguajes que utiliza para comstackr Componentes para la Unidad, por supuesto, tienen conceptos OO; la Unidad en sí misma no tiene ninguna conexión con OO).

(Nota B: en los primeros días de Unity verías bashs de crear código que “crea un objeto de juego sobre la marcha y lo mantiene único” y se adhiere a él “ . Además de ser extraño, solo FWIW no es teóricamente es posible garantizar la singularidad (en realidad, ni siquiera dentro de un marco). De nuevo, es completamente irrelevante porque es un tema sin importancia, en los comportamientos generales de Unity solo ingresa en la escena de precarga).

Si esta clase es solo para acceder a variables globales, entonces realmente no necesita un patrón singleton para esto, o usa un GameObject.

Simplemente crea una clase con miembros públicos estáticos.

 public class Globals { public static int mStatic1 = 0; public static float mStatic2 = 0.0f; // ....etc } 

Las otras soluciones son buenas pero exageradas si todo lo que necesitas es acceso global a las variables.

Escribí una clase singleton que facilita la creación de objetos singleton. Es una secuencia de comandos MonoBehaviour, por lo que puede utilizar las Coroutines. Está basado en este artículo de Unity Wiki , y agregaré una opción para crearlo desde Prefab más adelante.

Entonces no necesita escribir los códigos de Singleton. Simplemente descargue esta clase base Singleton.cs , agréguela a su proyecto y cree su singleton extendiéndola:

 public class MySingleton : Singleton { protected MySingleton () {} // Protect the constructor! public string globalVar; void Awake () { Debug.Log("Awoke Singleton Instance: " + gameObject.GetInstanceID()); } } 

Ahora su clase MySingleton es un singleton, y puede llamarla por instancia:

 MySingleton.Instance.globalVar = "A"; Debug.Log ("globalVar: " + MySingleton.Instance.globalVar); 

Aquí hay un tutorial completo: http://www.bivis.com.br/2016/05/04/unity-reusable-singleton-tutorial/

Esta es la configuración que he creado.

Primero crea este script:

MonoBehaviourUtility.cs

 using UnityEngine; using System.Collections; using System.Collections.Generic; using System.IO; static public class MonoBehaviourUtility { static public T GetManager( ref T manager ) where T : MonoBehaviour { if (manager == null) { manager = (T)GameObject.FindObjectOfType( typeof( T ) ); if (manager == null) { GameObject gameObject = new GameObject( typeof( T ).ToString() ); manager = (T)gameObject.AddComponent( typeof( T ) ); } } return manager; } } 

Entonces en cualquier clase que quieras ser un singleton haz esto:

 public class ExampleManager : MonoBehaviour { static public ExampleManager sharedManager { get { return MonoBehaviourUtility.GetManager( ref _sharedManager ); } } static private ExampleManager _sharedManager; } 

Una forma de hacerlo es crear una escena solo para inicializar tu administrador de juegos de esta manera:

 public class GameManager : MonoBehaviour { GameManager static instance; //other codes void Awake() { DontDestroyOnLoad(transform.gameObject); instance = this; } //other codes } 

Eso es todo, eso es todo lo que necesitas hacer. Y luego, inmediatamente después de inicializar el administrador del juego, cargue la siguiente escena y nunca más vuelva a esta escena.

Eche un vistazo a este tutorial: https://youtu.be/64uOVmQ5R1k?list=WL