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.
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 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”.
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