Um Singleton Genérico
Parte da seção Arquitetura de jogos no Unity do Journey de Unity da Coddy. Lição 34 de 50.
O singleton da seção 3 consiste em 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 as escreve 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, e é para isso que serve T. Dentro da classe base, this é conhecido apenas como um Singleton<T>, então this as T o entrega como o gerenciador que realmente é.
A classe base é abstrata: o Unity coloca apenas os gerenciadores nos objetos. Um gerenciador que precisa de seu próprio Awake 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 do gerenciador e Instance nunca é definido. Faça o override e chame primeiro a classe base:
protected override void Awake()
{
base.Awake();
score = 0;
}Desafio
MédioUma cidade e uma floresta, conectadas por portais roxos. Cada cena tem seu próprio objeto Wallet e MusicPlayer, então cada um toca por conta própria, e as moedas chamam Wallet.Instance.Add(1). Hoje, cada gerenciador é um singleton da seção 3, então cada carregamento substitui a carteira por uma vazia. Dê aos dois gerenciadores uma classe base genérica que os mantenha durante o carregamento das cenas:
- Em
PersistentSingleton.cs, escrevapublic abstract class PersistentSingleton<T>, um MonoBehaviour para qualquer tipo T de MonoBehaviour, com umInstanceestático público do tipo T que só a classe pode definir, e umprotected virtual void Awake(). - O Awake mantém a primeira instância do seu tipo: ela se torna Instance e sobrevive ao carregamento das cenas. Qualquer instância posterior destrói o próprio objeto e não altera nada.
WalleteMusicPlayerderivam dessa classe, e os camposInstancepróprios deles devem ser removidos.MusicPlayermantém seu próprio Awake, que registraNow playing: Adventure. Ele deve ser executado depois do Awake da classe base, e somente para a instância que permanece, para que a música comece uma vez por jogo.
As setas movem o Player. Pressione Jogar, pegue a moeda, vá até a floresta e volte, depois Verificar.
Experimente você mesmo
using UnityEngine;
// PersistentSingleton<T>: uma instância que persiste durante o carregamento de cenas
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Arquitetura de jogos no Unity
1Componentes, não hierarquias
Componentes pequenosUm script-base para inimigosComponentes abstratosComponentes trabalhando juntosRevisão: Torre modular4Dados Serializados
Classes SerializáveisListas no InspectorEnums no InspectorRevisão: Tabela de Loot7Máquinas de Estados
Estados como ClassesUma Máquina de EstadosTransiçõesInteligências dos InimigosRevisão: Estados da Porta10Projeto: Sobrevivente da Arena
O HeróiTipos de Inimigos5ScriptableObjects
Assets de dadosAtributos das armasConfigurações compartilhadasOndas como dadosRevisão: banco de dados de itens8Código Reutilizável
Métodos de ExtensãoUm Singleton GenéricoMétodos Auxiliares GenéricosRevisão: FindNearest