State Machine em jogos
- #C#
- #Unity
Resumo
Este artigo visa explorar a aplicação do State Machine (Maquina de estados) em programação de jogos eletrônicos, destacando sua eficácia em gestão de fluxo de controle. Ao implementar o State Machine em jogos, os desenvolvedores podem criar sistemas mais robustos e flexível, proporcionando uma melhore experiencia de jogo para o usuario. Este Artigo discute os fundamentos, Vantagens e exemplo de implementação
Introdução:
State Machine (Maquina de estados) é uma abstração matemática usado na ciência da computação para representar um sistema que pode estar em diferentes estados e podem mudar de um estado para outro em respostas de determinadas condições.
Estados
- Os Estado pode representar a condição ou situação especifica em que um sistema pode existir.
- Cada Estado Reflete a um conjunto especifico de propriedades, comportamentos ou características
Transições
- A transição Indicam como o sistema pode mudar de um estado par outro.
- Transições geralmente podem ser acionadas por eventos específicos
Eventos
- Eventos são os gatilhos que podem desencadear uma transição entre estado.
- Podem ser ações do usuário, mudança em variáveis, interação externa, entre outras maneira
Vantagens na Programação de jogos
Modalidade
- Flexibilidade Estrutural: Permite a divisão em estados independente, facilitando a adição, remoções e modificações.
- Reusabilidade: Estados modulares podem ser reutilizados, promovendo eficiência no desenvolvimento.
Facilidade de Manutenção
- Identificação de problemas: A identificação e correção de problemas são simplificadas, os desenvolvedores podem trabalhar na solução em parte isoladas do código.
- Adição e atualização de funcionalidades: adicionar e modificar o sistema de forma modular.
Representação Organizada de Comportamento Complexos
- Hierarquia de comportamentos: permite a representação hierárquica de comportamentos complexos, organizando interações de maneira logica.
Controle Preciso do Fluxo do jogo
- Resposta e Eventos: Garante respostas precisas a eventos específicos, o que possibilita a adaptação do jogo a ações do jogador ou mudança de cenário.
- Fluxo Determinado: Cria um controle claro e previsível do fluxo do jogo.
Exemplo Simples
using UnityEngine;
public class PlayerController: MonoBehaviour
{
// State Current Player
private PlayerState currentState;
// states
public enum PlayerState
{
Walking,
Idle
}
/*START*/
void Start()
{
// start stateMachine Idle
currentState = PlayerState.Idle;
}
void Update()
{
// Get Input W
if (Input.GetKey(KeyCode.W))
{
ChangeState(PlayerState.Walking);
}
else
{
ChangeState(PlayerState.Idle);
}
// specific perspective for each state
HandleState();
}
/*ChangeState*/
private void ChangeState(PlayerState newState)
{
if (currentState != newState)
{
Debug.Log($"Mudando de {currentState} para {newState}");
currentState = newState;
}
}
/* HandleState*/
private void HandleState()
{
switch (currentState)
{
case PlayerState.Walking:
// While you walk
MovePlayer();
break;
case PlayerState.Idle:
// While you Idle
StopPlayer();
break;
}
}
/*MovePlayer*/
private void MovePlayer()
{
transform.Translate(Vector3.forward * Time.deltaTime);
}
/*StopPlayer*/
private void StopPlayer()
{
// Nenhuma ação enquanto está parado
}
}
State Machine Com arquivos separados
crie um arquivo chamado "StateMachine", ele não pode chamar a classe MonoBehaviour. aclasse StateMachine não estende nenhuma outra classe porque ela não precisa herdar funcionalidades específicas de nenhuma classe base no contexto do Unity.
public class StateMachine
{
private State currentState;
// Name Current State Name
public string currentStateName { get; private set; }
// Update
public void Update()=> currentState?.Update();
//ChangeState
public void ChangeState(State newState)
{
currentState?.Exit();
currentState = newState;
currentStateName = newState.name;
newState.Enter();
}
}
Crie um arquivo chamado "state" , ele vai ser (abstract) pois sera chamado por outra classe futuramente.
/* --------
STATE
--------*/
public abstract class State
{
public readonly String name;
protected State(string name)=> this.name = name;
public virtual void Enter() { }
public virtual void Exit() { }
public virtual void Update() { }
}
Vamos criar a classe "PlayerController", que herdará de MonoBehaviour, pois é através dela que faremos as alterações no jogo como um todo, incluindo a gestão dos estados do nosso player. Essa classe servirá como o controlador principal, coordenando a lógica do jogo e interagindo com os diferentes estados do jogador.
public class PlayerController : MonoBehaviour
{
/*START*/
void Start()
{
// Start State
stateMachine = new StateMachine();
walkState = new Walk(this);
idleState = new Idle(this);
stateMachine.ChangeState(walkState);
}
/*UPDATE RUN AFTER START*/
void Update()
{
// Get Inputs Move
bool moveUp = Input.GetKey(KeyCode.W);
// State Player
stateMachine.ChangeState(moveUp? walkState : idleState);
// Update State Machine
stateMachine.Update();
}
}
Agora, vamos criar arquivos para os estados "Walk" e "Idle". Essas classes irão estender a classe "State", que foi previamente definida. Esses estados serão responsáveis por determinar as ações do jogador, como andar ou ficar parado, com base nas entradas do teclado ou eventos dentro do jogo. Eles desempenham um papel crucial na definição do comportamento dinâmico do jogador durante o jogo.
/* --------
STATE PLAYER WALK
--------*/
public class Walk : State
{
private PlayerController controller;
// Contructor
public Walk(PlayerController controller) : base("Walk")=>this.controller = controller;
// Enter
public override void Enter()
{
base.Enter();
Debug.log("Entrou na maquina de estado Walk");
}
// Exit
public override void Exit()
{
base.Exit();
Debug.log("Entrou na maquina de estado Walk");
}
// Update
public override void Update()=>base.Update();
}
/* --------
STATE PLAYER IDLE
--------*/
public class Idle : State
{
public PlayerController controller;
// Contructor
public Idle(PlayerController controller) : base("idle") =>this.controller = controller;
// Enter
public override void Enter()
{
base.Enter();
Debug.log("Entrou na maquina de estado Walk");
}
// Exit
public override void Exit()
{
base.Exit();
Debug.log("Entrou na maquina de estado Walk");
}
// Update
public override void Update()=>base.Update();
}
Jogos com State Machine
- The Legend of Zelda: Ocarina of Time A utilização de máquinas de estados é evidente na transição entre diferentes ações do personagem principal, Link, como andar, correr, atacar e interagir.
- Metal Gear Solid V: The Phantom Pain O jogo emprega máquinas de estados para gerenciar as diferentes situações em que o protagonista, Snake, pode se encontrar, como estado de alerta, furtividade e combate.
- Assassin's Creed Series Os jogos da série Assassin's Creed usam máquinas de estados para controlar o comportamento do personagem em diferentes situações, como escalada, exploração, combate e interações sociais.
Conclusão
Em síntese, a implementação da State Machine na programação de jogos revela-se uma abordagem eficaz para gerenciar o fluxo de controle. Ao adotar esse modelo, os desenvolvedores capacitam-se a criar sistemas mais robustos e flexíveis, aprimorando significativamente a experiência do usuário. Este artigo explorou os fundamentos da State Machine, destacando as vantagens e fornecendo exemplos práticos de implementação.