Como fazer a transição entre estados e misturar estados em uma máquina de estados finitos?

7

Não entendo como usar uma máquina de estados finitos com a entidade controlada pelo jogador.

Por exemplo, eu tenho um jogo estilo Mario (plataforma 2D). Eu posso pular, correr, andar, sofrer danos, nadar, etc. Então, meu primeiro pensamento foi usar essas ações como estados. Mas o que acontece, se você estiver correndo quando sofrer danos? Ou pular, sofrer danos e atirar ao mesmo tempo?

Eu só quero adicionar funcionalidades (ações) ao player de uma maneira limpa (sem usá-lo para todas as ações na atualização da entidade).

juakob
fonte
2
A questão é um pouco bizarra; por que ações seriam estados no FSM? Por que eles não seriam entradas para o FSM?

Respostas:

7

Eu acho que a maneira normal é ter várias máquinas de estado. Dessa forma, você pode se ater aos estados atômicos, o que geralmente facilita muito a sua vida do que ter que lidar com estados complexos.

Por exemplo:

  • Modo de Dano: Normal, Invulnerável (como em apenas um hit), invencível (como em conseguiu uma estrela)
  • Ritmo: Modo Caminhada, Modo Corrida
  • Habilidades: Normal, Super, Fogo, Voar
  • Tipo de Movimento: Caminhada, Natação, Voar

No design orientado a objetos, existe o padrão satisfatório para isso. Tudo se resume a ter uma interface por máquina de estado. E uma classe por estado possível que implementa essa interface.

Para dar um exemplo: haveria uma interface DamageMode e as subclasses NormalDamageMode, InvulnerableDamageMode e InvincibleDamageMode. Sempre que o jogador colidir com um inimigo, o método DamageMode.collision (inimigo) é chamado. É tratado pela classe responsável pelo estado atual.

Portanto, se damageMode == NormalDamageMode, o player será danificado e a variável de estado será definida como InvulnerableDamageMode. No InvulnerableDamageMode nada acontece e no InvincibleDamageMode o inimigo será danificado. É claro que é preciso haver temporizadores para voltar de InvulnerableDamageMode e InvincibleDamageMode para NormalDamageMode.

A principal vantagem do padrão de estado em comparação com if-elseif-elseif-elseif-blocks é que ele permite estruturar melhor seu código.

Hendrik Brummermann
fonte
+1 por criar muitos FSMs pequenos, em vez de um grande 'un. A granularidade é muito útil aqui.
Dezpn
Eu gosto da ideia de várias máquinas de estado. Mas como eles são integrados para trabalhar com uma entidade? Eles são atualizados em paralelo? ou eles estão aninhados dentro de uma máquina de estado de entidade?
Dani
@Dani, cada máquina de estado é referenciada como um atributo dos objetos da entidade. A maioria deles é independente, por exemplo, você pode ser invencível com Habilidades pequenas, super, disparar e voar. Alguns eventos desencadeiam várias transições de estado: por exemplo, ser atingido por um inimigo diminui a capacidade e altera o modo de dano para invulnerável. Isso deixa apenas alguns casos em que duas máquinas de estado estão realmente vinculadas. Por exemplo, forçar modo de execução enquanto invencível.
Hendrik Brummermann
7

Os estados não são ações, no seu jogo eles controlariam como o personagem é atualizado (por exemplo, cada estado pode ter sua própria função update ()).

Dê uma olhada no diagrama nesta página: http://en.wikipedia.org/wiki/State_diagram . Os estados nos dizem algo sobre o mundo (a porta está aberta ou fechada). As ações nos mostram o que leva o mundo de um estado para outro.

No seu caso, você pode ter estados como:

  • pulando
  • corrida
  • na dor
  • queda
  • morto

E a transição entre estados (os eventos / flechas entre estados) seria uma contribuição do jogador e reações ao mundo, como:

  • atingido por monstro
  • botão de salto pressionado
  • botão de disparo pressionado

Cada estado precisa verificar se algum evento relevante ocorreu. Normalmente, isso é feito com instruções if.

Mas o que acontece quando você está correndo quando sofre danos?

O hit by monsterevento seria acionado e faria a transição do jogador para o in painestado.

ou pulando sofrendo danos e atirando ao mesmo tempo?

O jogador faria a transição para o in painestado novamente, onde é possível exibir o sprite "hit" que mostra o personagem caindo para trás.

Você provavelmente não vai escapar de instruções if, mas pode evitar instruções profundamente aninhadas.

CiscoIPPhone
fonte