Um Singleton Genérico
Parte da seção Arquitetura de Jogos no Unity do Journey de Unity da Coddy. Lição 43 de 64.
O singleton da Seção 3 tem cinco linhas que cada gerenciador repete: um Instance estático, um Awake que o define e a verificação de duplicatas. Uma classe-base genérica escreve essas linhas uma vez. Cada gerenciador deriva dela, nomeando a si mesmo como o tipo:
public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
public static T Instance { get; private set; }
protected virtual void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this as T;
}
}
public class ScoreManager : Singleton<ScoreManager>
{
public int score;
public void Add(int points) { score += points; }
}
public class SoundManager : Singleton<SoundManager>
{
public void Play(string clip) { Debug.Log("Playing " + clip); }
}// em qualquer script
ScoreManager.Instance.Add(10);
SoundManager.Instance.Play("coin");Um membro estático de uma classe genérica pertence a cada tipo criado a partir dela: Singleton<ScoreManager> e Singleton<SoundManager> são dois tipos, cada um com seu próprio Instance, então os gerenciadores nunca compartilham um. ScoreManager.Instance já tem o tipo ScoreManager, que é para isso que serve T. Dentro da classe-base, this só é conhecido como um Singleton<T>, então this as T o entrega como o gerenciador que ele realmente é.
A classe-base é abstrata: o Unity coloca apenas os gerenciadores nos objetos. Um gerenciador que precisa de um Awake próprio não deve escrever um void Awake() simples. Isso oculta o método da classe-base (o compilador avisa sobre isso), o Unity chama apenas o método do gerenciador, e Instance nunca é definido. Sobrescreva-o e chame primeiro o método da classe-base:
protected override void Awake()
{
base.Awake();
score = 0;
}Desafio
MédioDê aos dois gerenciadores uma base que persista ao carregar cenas.
- Em
PersistentSingleton, escrevaprotected virtual void Awake(): o primeiro se tornaInstancee permanece (DontDestroyOnLoad); um posterior se destrói. WalleteMusicPlayerderivam dele; exclua oInstancedeles e o Awake de Wallet.MusicPlayersobrescreve Awake:base.Awake()e, em seguida, se for o Instance, registraNow playing: Adventure.
Pressione “Jogar”, visite a floresta e volte: 1 moeda. Depois, pressione “Verificar”.
Experimente você mesmo
using UnityEngine;
public abstract class PersistentSingleton<T> : MonoBehaviour where T : MonoBehaviour
{
public static T Instance { get; private set; }
// Awake: mantenha o primeiro entre os carregamentos de cena e destrua qualquer outro que surgir depois
}
Todas as lições de Arquitetura de Jogos no Unity
1Componentes, não hierarquias
Componentes pequenosUm script base de inimigoComponentes abstratosComponentes trabalhando juntosRevisão: torre modularRevisão: canhão duplo4Dados Serializados
Classes SerializáveisListas no InspectorEnums no InspectorRevisão: Tabela de LootRevisão: Sorteie o Loot2Interfaces no Unity
IDamageableInterfaces e TryGetComponentGetComponentsRevisão: tecla de interaçãoRevisão: mais próximo ao alcance5ScriptableObjects
Ativos de DadosAtributos da ArmaConfigurações CompartilhadasSalve o VentoOndas como DadosRevisão: Banco de ItensRevisão: Comprar na Loja8Código Reutilizável
Métodos de ExtensãoUm Singleton GenéricoMétodos Auxiliares GenéricosRevisão: FindNearestPratique por conta própria: Playground de Unity