Conteúdo do Curso
Jogo de Luta no Unity
Jogo de Luta no Unity
Estado de Corrida
public abstract class State
{
public bool isStateFinished;
public abstract void StartState();
public virtual void UpdateState()
{
}
public abstract void EndState();
public virtual void FinishState()
{
isStateFinished = true;
}
}
Alterações e Adições
Variável isStateFinished:
Variável booleana que indica se o estado finalizou sua execução.
Método FinishState:
Novo método virtual que define isStateFinished
como true
.
Por ser virtual, permite que classes derivadas sobrescrevam este método caso precisem executar ações adicionais ao finalizar um estado.
Por que essas alterações foram feitas
As alterações introduzem a variável isStateFinished
para rastrear a conclusão do estado e o método FinishState
para padronizar o sinal de término do estado, permitindo que classes derivadas adicionem lógica personalizada ao finalizar o estado.
Estado de Corrida
public class RunState : State
{
Rigidbody2D rb;
Animator animator;
Transform player;
float speed;
Vector2 scale;
Vector2 velocity;
public RunState(Rigidbody2D rb, Animator animator, Transform p, float speed)
{
this.animator = animator;
player = p;
this.speed = speed;
this.rb = rb;
scale = rb.transform.localScale;
velocity = new Vector2();
}
public override void StartState()
{
isStateFinished = false;
animator.SetBool("run", true);
}
public override void UpdateState(float DeltaTime)
{
scale.x = rb.position.x > player.position.x ? -1 : 1;
rb.transform.localScale = scale;
velocity.x = scale.x * speed;
rb.velocity = velocity;
}
public override void EndState()
{
animator.SetBool("run", false);
}
}
Vamos analisar a classe RunState
, que herda da classe State
. Esta classe é responsável por gerenciar o comportamento de corrida do inimigo. O foco será nas adições e alterações feitas nesta classe.
Construtor:
public RunState(Rigidbody2D rb, Animator animator, Transform p, float speed)
;
Este construtor inicializa o RunState
com os componentes necessários: um Rigidbody2D
para movimentação, um Animator
para animações, um Transform
para rastrear o jogador e uma speed
para definir a velocidade de corrida do inimigo;
Método StartState:
public override void StartState()
;
Este método define isStateFinished
como false
e ativa a animação de corrida ao definir o parâmetro booleano "run" no animator como true
.
Método UpdateState:
public override void UpdateState(float DeltaTime)
;
Este método atualiza a posição e orientação do inimigo com base na posição do jogador;
Ajusta a escala do inimigo para que ele fique voltado para o jogador, calcula a velocidade de acordo com o valor de speed e aplica essa velocidade ao Rigidbody2D
.
Método EndState:
public override void EndState()
Este método interrompe a animação de corrida ao definir o parâmetro booleano "run" no animator como false
.
Funcionamento para o Inimigo
-
Movimentação e Animação: Utilizando
Rigidbody2D
eAnimator
, oRunState
garante que o inimigo se mova suavemente e apresente animações correspondentes. Isso torna o comportamento visual e fisicamente realista; -
Rastreamento da Posição do Jogador: O transform
player
permite que o inimigo sempre se mova em direção ao jogador, o que é essencial para comportamentos de perseguição ou fuga; -
Controle de Direção: Ajustar o
scale.x
com base na posição do jogador garante que o inimigo fique voltado corretamente para o jogador enquanto corre, aumentando o realismo; -
Atualizações Dinâmicas de Estado: O método
UpdateState
é chamado a cada frame para ajustar continuamente o movimento e a direção do inimigo com base na posição do jogador, tornando o inimigo responsivo e dinâmico.
Inicialização do Inimigo
private void Start()
{
idle = new IdleState(animator);
runState = new RunState(GetComponent<Rigidbody2D>(), animator, player, speed);
stateManager = new StateManager(idle);
FarAwayTransition = new Transition(() =>
{
return (ThresholdDistance < Vector2.Distance(transform.position, player.position));
}, new StatePourcentage(runState, 50f), new StatePourcentage(dashState, 50f));
toIdleTransition = new Transition(() =>
{
return stateManager.GetCurrentState().isStateFinished;
}, new StatePourcentage(idle, 100));
finishRunning = new Transition(() =>
{
return (ThresholdDistance >= Vector2.Distance(transform.position, player.position));
}, new StatePourcentage(idle, 100));
stateManager.AddStateTransition(idle, FarAwayTransition);
stateManager.AddStateTransition(dashState, toIdleTransition);
stateManager.AddStateTransition(runState, finishRunning);
}
Explicação
Inicialização de Estado:
As variáveis idle
e runState
são inicializadas com seus respectivos estados. A variável idle
é uma instância de IdleState
com o animator passado como parâmetro, enquanto runState
é uma instância de RunState
que inclui um Rigidbody2D
, um Animator
, um Transform
para o jogador e um valor de velocidade.
Inicialização do StateManager:
stateManager = new StateManager(idle);
O StateManager
é inicializado com o estado idle
como estado inicial.
Definições de Transição:
-
FarAwayTransition:
FarAwayTransition = new Transition(() => { return (ThresholdDistance < Vector2.Distance(transform.position, player.position)); }, new StatePourcentage(runState, 50f), new StatePourcentage(dashState, 50f));
; Esta transição verifica se o jogador está mais distante queThresholdDistance
; -
toIdleTransition:
toIdleTransition = new Transition(() => { return stateManager.GetCurrentState().isStateFinished; }, new StatePourcentage(idle, 100));
Esta transição verifica se o estado atual foi finalizado. Se verdadeiro, transita para o estadoidle
com 100% de probabilidade. -
finishRunning:
finishRunning = new Transition(() => { return (ThresholdDistance >= Vector2.Distance(transform.position, player.position)); }, new StatePourcentage(idle, 100));
Esta transição verifica se o jogador está mais próximo queThresholdDistance
. Se verdadeiro, transita para o estadoidle
com 100% de probabilidade.
Adicionando Transições ao StateManager:
stateManager.AddStateTransition(idle, FarAwayTransition);
stateManager.AddStateTransition(dashState, toIdleTransition);
stateManager.AddStateTransition(runState, finishRunning);
Essas linhas adicionam as transições definidas ao stateManager
.
Por Que Fizemos Desta Forma
Mudanças Dinâmicas de Estado:
As transições permitem que o inimigo altere seu comportamento dinamicamente com base na posição do jogador e no status de conclusão do estado atual, tornando o inimigo mais responsivo e interativo dentro do ambiente do jogo.
Transições Condicionais:
O uso de condições (como verificação de distância ou conclusão de estado) garante que as transições de estado ocorram de maneira lógica e apropriada, aumentando o realismo da jogabilidade.
Transições Baseadas em Probabilidade:
O uso de StatePourcentage
permite transições baseadas em probabilidade, adicionando um elemento de imprevisibilidade e variedade ao comportamento do inimigo.
Obrigado pelo seu feedback!