Transições
Parte da seção Arquitetura de Jogos no Unity do Journey de Unity da Coddy. Lição 38 de 64.
Quem decide quando o estado muda? Perguntar ao proprietário coloca todas as regras de volta em um único Update, como o switch fazia. A resposta usual é que cada estado sabe como sair: em seu Tick, ele verifica sua condição e pede à máquina o próximo estado. Esta bomba espera até que o jogador se aproxime, então queima seu pavio e volta a esperar se o jogador fugir:
public class Bomb : MonoBehaviour
{
public Transform player;
public StateMachine machine = new StateMachine();
public IState idle;
public IState fuse;
void Start()
{
idle = new IdleState(this);
fuse = new FuseState(this);
machine.ChangeState(idle);
}
void Update() { machine.Tick(); }
public bool PlayerNear()
{
return Vector3.Distance(transform.position, player.position) < 3f;
}
}
public class IdleState : IState
{
private Bomb bomb;
public IdleState(Bomb bomb) { this.bomb = bomb; }
public void Enter() { }
public void Exit() { }
public void Tick()
{
if (bomb.PlayerNear()) bomb.machine.ChangeState(bomb.fuse);
}
}
public class FuseState : IState
{
private Bomb bomb;
private float timer;
public FuseState(Bomb bomb) { this.bomb = bomb; }
public void Enter() { timer = 2f; }
public void Exit() { }
public void Tick()
{
if (!bomb.PlayerNear())
{
bomb.machine.ChangeState(bomb.idle);
return;
}
timer -= Time.deltaTime;
if (timer <= 0f)
{
Debug.Log("Boom!");
Object.Destroy(bomb.gameObject);
}
}
}Cada estado recebe a bomba em seu construtor e acessa por meio dela a máquina, o teste do jogador e os outros estados. A bomba cria cada estado uma única vez, em Start, então um estado nunca cria outro com new: dois estados que criassem um ao outro em seus construtores entrariam em um loop até que a pilha transbordasse. O Update da bomba apenas atualiza a máquina, e as regras ficam nos estados aos quais pertencem: o pavio de 2 segundos é responsabilidade exclusiva de FuseState.
ChangeState executa Exit de FuseState e Enter de IdleState imediatamente, mas o restante de Tick de FuseState ainda seria executado após a chamada. O return interrompe isso; caso contrário, o pavio queimaria por mais um frame em um estado que já terminou. Destroy é escrito como Object.Destroy: um MonoBehaviour herda esse método da classe Object do Unity, e uma classe simples precisa especificar o nome da classe.
Desafio
MédioEscreva as transições da planta-papa-moscas em cada Tick de FlytrapStates.cs.
- Open: quando
trap.PlayerInReach(), chametrap.machine.ChangeState(trap.snap);. - Snap: some
Time.deltaTimeatimer; em0.5, mude paratrap.chewse o jogador ainda estiver ao alcance; caso contrário, paratrap.open. - Chew: faça a contagem regressiva de
timera partir de 3; em 0, mude paratrap.open.
Pressione “Jogar”, caminhe até a armadilha e desvie dela. Em seguida, pressione “Verificar”.
Experimente você mesmo
using UnityEngine;
public class OpenState : IState
{
private Flytrap trap;
public OpenState(Flytrap trap)
{
this.trap = trap;
}
public void Enter()
{
trap.Paint(new Color(0.3f, 0.8f, 0.2f));
}
public void Tick()
{
// Fechar quando o jogador estiver ao alcance
}
public void Exit()
{
}
}
public class SnapState : IState
{
private Flytrap trap;
private float timer;
public SnapState(Flytrap trap)
{
this.trap = trap;
}
public void Enter()
{
timer = 0f;
trap.Paint(new Color(1f, 0.55f, 0.1f));
}
public void Tick()
{
// Após 0.5 segundos: mastigar se o jogador ainda estiver ao alcance; caso contrário, abrir novamente
}
public void Exit()
{
}
}
public class ChewState : IState
{
private Flytrap trap;
private float timer;
public ChewState(Flytrap trap)
{
this.trap = trap;
}
public void Enter()
{
timer = 3f;
trap.Paint(new Color(0.5f, 0.05f, 0.1f));
Debug.Log("Chomp!");
}
public void Tick()
{
// Após 3 segundos: abrir novamente
}
public void Exit()
{
}
}
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 LojaPratique por conta própria: Playground de Unity