Article image
Joao Silva
Joao Silva01/05/2024 19:49
Share

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

  1. 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.
  2. 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.
  3. 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.

Share
Comments (0)