Unity3D: Agregador automático del Administrador de scripts

Introducción


Este artículo se centrará en un tipo de organización de interacción entre los administradores de scripts (llamados singletones) y, específicamente, el uso de una clase de agregador separada, que contiene enlaces a todos los administradores de instancias. La idea de crear una clase de agregador se me ocurrió después de leer este artículo .

Tareas


Llegué a la conclusión de que meter a los gerentes en la clase de agregador con sus propios bolígrafos cada vez es muy inconveniente. Al crear un nuevo administrador, deberá abrir la clase de agregador y realizar cambios. Con suficiente experiencia, puede automatizar procesos tan tediosos. Así, se establecieron las tareas: creación automática de singletones y su colector automático.

Clase Singleton


using UnityEngine;
public class Singleton<T>: MonoBehaviour where T: MonoBehaviour
{
	public static T instance { get; private set; }

	public void Awake()
	{
		if (instance == null)
		{
			instance = GetComponent<T>();
			ManagersAregator.addManager(instance);
		}
		else
		{
			Debug.Log($"<color=red>   {typeof(T).ToString()}</color>");
			Destroy(gameObject);
		}
	}

	public void OnDestroy()
	{
		ManagersAregator.removeManager<T>();
	}
}

La implementación clásica de singleton en Unity usa la variable estática de instancia . El método Awake () verifica si la instancia está definida . Si no, obtenemos una referencia a la instancia de clase usando la palabra clave this . Pero desde en una implementación particular, se usa una variable de "plantilla" de clase T , esto no se podría usar. Pero podemos obtener fácilmente el componente T del objeto en el que se cuelga el script. Si se define la instancia , entonces debe ser destruida. Por lo tanto, el objeto siempre estará en el escenario en una sola copia.

En el método Awake ()se agrega un nuevo elemento a la clase de agregador, y en el método OnDestroy () , el elemento se elimina de la clase de agregador.

La creación de un singleton de la clase MyClass es la siguiente:

public class MyClass: Singleton<MyClass>

Si necesita usar el método Awake () en la clase MyClass , entonces necesita usar la palabra clave base ( más sobre base y herencia ):

new void Awake()
	{
		base.Awake(); //  Awake() -
		// 
	}

Agregador de clase


using System.Collections.Generic;
using UnityEngine;

public static class ManagersAregator
{
	static Dictionary<string, MonoBehaviour> Managers = new Dictionary<string, MonoBehaviour>();

	public static void addManager<T>(T newManager)
	{
		string keyWord = typeof(T).ToString();

		if(Managers.ContainsKey(keyWord))
		{
			Debug.Log($"[ManagersAregator]  -{newManager}-   -{keyWord}-  ");
		}
		else
		{
			Managers.Add(keyWord, newManager as MonoBehaviour);
			Debug.Log($"<color=green>[ManagersAregator]    -{newManager}-   -{keyWord}-</color>");
		}
	}

	public static T getManager<T>(string callback) where T: Singleton<T>
	{
		string keyWord = typeof(T).ToString();

		if(Managers.ContainsKey(keyWord))
		{
			Debug.Log($"<color=yellow>[{callback}]   -{keyWord}-</color>");

			MonoBehaviour mbTemp = null;
			T manager = null;

			if(Managers.TryGetValue(keyWord, out mbTemp))
			{
				manager = (T)mbTemp;
				Debug.Log($"<color=green>[{callback}]  -{manager}- </color>");
			}
			else
			{
				Debug.Log($"<color=red>[{callback}]    -{keyWord}-</color>");
			}

			return manager;
		}

		Debug.Log($"<color=red>[ManagersAregator]    -{keyWord}-   .</color>");
		return null;
	}

	public static void removeManager<T>()
	{
		string keyWord = typeof(T).ToString();

		if(Managers.ContainsKey(keyWord))
		{
			Managers.Remove(keyWord);
			Debug.Log($"[ManagersAregator]    -{keyWord}-   ");
		}
		else
		{
			Debug.Log($"[ManagersAregator]    -{keyWord}-   .");
		}
	}
}

La clase es estática, es decir. No puede tener una instancia en el escenario. Por lo tanto, estará disponible desde cualquier escena en cualquier momento.

Todos los gestores de script (singletones) se almacenan en el diccionario Managers . La clave para cada administrador es el nombre de clase de ese administrador. Quizás los recién llegados a la programación hagan la pregunta: "Bah, pero ¿qué almacena este diccionario MonoBehaviour , y todas las clases heredan de Singleton ?". Esta es una buena pregunta, cuya respuesta es la clave para la implementación de un agregador automático de gerentes de cualquier clase.

En programación, existe el concepto de conversión de tipo upcasting a una clase base. Debido al hecho de que todas las clases en Unity heredan de MonoBehaviour ,Se pueden aplicar a MonoBehabiour . Por lo tanto, el diccionario Managers contiene solo objetos de la clase MonoBehaviour .

Considere los métodos de la clase agregador:

void addManager<T>(T newManager)

Este método se llama en el método Awake () de la clase Singleton . El argumento es una variable estática de la clase de instancia . A continuación, se crea una clave con el nombre de la clase a la que pertenece la instancia y el administrador se agrega al diccionario.

T getManager<T>(string callback) where T: Singleton<T>

La función toma como argumento una cadena con el nombre de la clase desde donde se llama el método. Esto se hace exclusivamente para una depuración conveniente (la consola muestra la clase desde donde se llama el método). Un ejemplo de uso de este método en la clase AnotherMyClass :

public class AnotherMyClass: MonoBehaviour
	void Start()
	{
		string cb = GetType().ToString(); //     
		MyClass MC = ManagersAregator.getManager<MyClass >(cb);
	}

Aparecerá un mensaje en la consola: " Hu ** I, rehacer [AnotherMyClass] Manager -MyClass- recibido".

void removeManager<T>()

Elimina un administrador de tipo T del diccionario si está contenido en el diccionario.

Resumen


De hecho, de las tres funciones de la clase de agregador, un desarrollador solo necesita usar el método getManager . Una ventaja especial es la buena visibilidad de los mensajes de depuración para todas las ocasiones. Opcionalmente, por supuesto, puede desactivarlos. Creo que será muy conveniente ver en qué momento, qué clase está tratando de obtener algo y qué está tratando de obtener.

¡Espero que este artículo te haya sido útil y hayas descubierto algo útil para ti!

All Articles