Menu
CoddyTech

Estados como Classes

Parte da seção Arquitetura de jogos no Unity do Journey de Unity da Coddy. Lição 28 de 50.

O switch de enum da Seção 3 mantém o trabalho de cada estado em um único Update. Isso deixa de escalar quando os estados passam a ter dados próprios: um temporizador 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 estado de C# dá a cada estado sua própria classe, e cada classe implementa uma interface. Este sinalizador rodoviário pisca ou permanece aceso, e Space 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 seus métodos: Beacon é o MonoBehaviour, então seu Update chama current.Tick() a cada frame.

O timer pertence somente 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: Space 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 Exit do estado antigo e, em seguida, Enter do novo estado. Um terceiro estado, como um pulso lento, é mais uma classe, e o Update de Beacon não muda.

challenge icon

Desafio

Médio

Uma torre sentinela protege o pátio. As setas movimentam o Player (pronto). Dê dois estados à torre, escritos como classes:

  • Em IState.cs, declare public interface IState com void Enter(), void Tick() e void Exit().
  • Em TurretStates.cs, escreva duas classes simples que implementem essa interface. ScanState recebe a cabeça da torre no construtor. Ela varre de um lado para o outro: o ângulo y local da cabeça se move a 90 graus por segundo entre -45 e 45, começando em 0 e virando para cima sempre que a varredura começa. Seu Enter também colore a cabeça com Color.green.
  • AlertState recebe a cabeça e o jogador. Seu Enter colore a cabeça com Color.red e registra Intruder!; seu Tick vira a cabeça para encarar o jogador somente em torno do eixo y, sem inclinação; seu Exit registra All clear.
  • Em Turret.cs, crie os dois estados em Start e comece a varredura. A cada quadro, mude para o estado de alerta quando o jogador estiver mais perto da torre do que range (4) e volte à varredura quando não estiver; em seguida, execute o Tick do estado atual. Uma mudança executa o Exit do estado antigo e, depois, o Enter do novo estado.

Pressione Play, aproxime-se da torre e depois se afaste; em seguida, pressione Check.

Experimente você mesmo

using UnityEngine;

// ScanState e AlertState
quiz iconTeste seus conhecimentos

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