Estados como classes
Parte da seção Arquitetura de Jogos no Unity do Journey de Unity da Coddy. Lição 35 de 64.
O switch sobre um enum da Seção 3 mantém o trabalho de cada estado em um único Update. Isso deixa de funcionar bem quando os estados têm dados próprios: um timer usado por apenas um estado acaba como um campo do MonoBehaviour, ao lado dos campos de todos os outros estados, e cada case precisa se lembrar de redefinir o que usa. O padrão de estados do C# dá a cada estado sua própria classe, e cada classe implementa uma interface. Este sinalizador rodoviário pisca ou permanece aceso, e a tecla Espaço alterna entre os dois:
public interface IState
{
void Enter();
void Tick();
void Exit();
}
public class BlinkState : IState
{
private Renderer lamp;
private float timer;
public BlinkState(Renderer lamp)
{
this.lamp = lamp;
}
public void Enter() { timer = 0f; }
public void Tick()
{
timer += Time.deltaTime;
if (timer >= 0.5f)
{
timer = 0f;
lamp.enabled = !lamp.enabled;
}
}
public void Exit() { lamp.enabled = true; }
}
public class SteadyState : IState
{
public void Enter() { }
public void Tick() { }
public void Exit() { }
}
public class Beacon : MonoBehaviour
{
public Renderer lamp;
private IState blink;
private IState steady;
private IState current;
void Start()
{
blink = new BlinkState(lamp);
steady = new SteadyState();
SetState(steady);
}
void Update()
{
if (Keyboard.current.spaceKey.wasPressedThisFrame) SetState(current == steady ? blink : steady);
current.Tick();
}
void SetState(IState next)
{
if (current != null) current.Exit();
current = next;
current.Enter();
}
}Os estados são classes simples de C#, não MonoBehaviours. Você os cria com new e passa a eles o que precisam pelo construtor — aqui, o Renderer da lâmpada — porque não são componentes e não podem chamar GetComponent nem exibir campos no Inspector. A Unity também nunca chama os métodos deles: Beacon é o MonoBehaviour, então seu Update chama current.Tick() a cada quadro.
O timer pertence apenas a BlinkState, e seu Enter o define como 0 sempre que o sinalizador começa a piscar. Exit faz a limpeza quando o estado termina: a tecla Espaço pode ser pressionada enquanto a lâmpada está apagada, e Exit a acende novamente, para que SteadyState nunca comece com a lâmpada apagada. SetState executa o Exit do estado antigo e, em seguida, o Enter do novo estado. Um terceiro estado, como um pulso lento, é mais uma classe, e o Update de Beacon não muda.
Desafio
MédioEscreva o estado de varredura da torre.
- Em
IState.cs, declarepublic interface IStatecomvoid Enter();,void Tick();evoid Exit();. - Em
TurretStates.cs, escrevaScanState : IState, recebendo a cabeça. Ao entrar: ângulo 0, cabeçaColor.green. No Tick: faça uma varredura com o ângulo y local da cabeça entre-45e45, a90graus por segundo. Turret: entre em um estado no Start e atualize-o no Update.
Pressione “Jogar”: a cabeça verde faz a varredura. Em seguida, pressione “Verificar”.
Experimente você mesmo
using UnityEngine;
// ScanState
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 Loot7Máquinas de estados
Estados como classesO estado de alertaUma máquina de estadosTransiçõesCérebros dos inimigosO cavaleiro atacaRevisão: estados da porta2Interfaces 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 LojaPratique por conta própria: Playground de Unity