Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Aprende Estado de Carrera | Comportamiento del Enemigo
Juego de Lucha en Unity

bookEstado de Carrera

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;
    }
}

Cambios y Adiciones

Variable isStateFinished:

Variable booleana que indica si el estado ha finalizado su ejecución.

Método FinishState:

Nuevo método virtual que establece isStateFinished en true. Al ser virtual, las clases derivadas pueden sobrescribir este método si necesitan realizar acciones adicionales cuando un estado finaliza.

Razones de estos cambios

Los cambios introducen la variable isStateFinished para rastrear la finalización del estado y el método FinishState para estandarizar la señalización de finalización del estado, permitiendo que las clases derivadas agreguen lógica personalizada al completar el estado.

Estado de carrera

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);
    }
}

Analicemos la clase RunState, que hereda de la clase State. Esta clase se encarga de gestionar el comportamiento de carrera de nuestro enemigo. Nos centraremos en las adiciones y cambios realizados en esta clase.

Constructor:

public RunState(Rigidbody2D rb, Animator animator, Transform p, float speed);

Este constructor inicializa el RunState con los componentes necesarios: un Rigidbody2D para el movimiento, un Animator para las animaciones, un Transform para rastrear al jugador y una speed que determina la velocidad a la que corre el enemigo;

Método StartState:

public override void StartState(); Este método establece isStateFinished en false y activa la animación de correr configurando el parámetro booleano "run" en el animator a true.

Método UpdateState:

public override void UpdateState(float DeltaTime); Este método actualiza la posición y orientación del enemigo en función de la posición del jugador; Ajusta la escala del enemigo para que mire hacia el jugador, calcula la velocidad según la velocidad establecida y aplica esta velocidad al Rigidbody2D.

Método EndState:

public override void EndState() Este método detiene la animación de correr estableciendo el parámetro booleano "run" en el animador a false.

Funcionamiento para Nuestro Enemigo

  • Movimiento y Animación: Mediante el uso de Rigidbody2D y Animator, el RunState garantiza que el enemigo pueda moverse de manera fluida y tenga animaciones correspondientes. Esto hace que el comportamiento sea visual y físicamente realista;

  • Seguimiento de la Posición del Jugador: El transform del player permite que el enemigo siempre se desplace hacia el jugador, lo cual es esencial para comportamientos de persecución o huida;

  • Manejo de Dirección: Ajustar el scale.x en función de la posición del jugador asegura que el enemigo mire correctamente hacia el jugador mientras corre, aumentando el realismo;

  • Actualizaciones Dinámicas de Estado: El método UpdateState se llama en cada frame para ajustar continuamente el movimiento y la dirección del enemigo según la posición del jugador, haciendo que el enemigo sea receptivo y dinámico.

Inicialización del Enemigo

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);
}

Explicación

Inicialización del Estado:

Las variables idle y runState se inicializan con sus respectivos estados. La variable idle es una instancia de IdleState con el animador pasado como parámetro, mientras que runState es una instancia de RunState que incluye un Rigidbody2D, un Animator, un Transform para el jugador y un valor de velocidad.

Inicialización de StateManager:

stateManager = new StateManager(idle); El StateManager se inicializa con el estado idle como estado inicial.

Definiciones de Transiciones:

  • FarAwayTransition: FarAwayTransition = new Transition(() => { return (ThresholdDistance < Vector2.Distance(transform.position, player.position)); }, new StatePourcentage(runState, 50f), new StatePourcentage(dashState, 50f));; Esta transición verifica si el jugador está más lejos que ThresholdDistance;

  • toIdleTransition: toIdleTransition = new Transition(() => { return stateManager.GetCurrentState().isStateFinished; }, new StatePourcentage(idle, 100)); Esta transición verifica si el estado actual ha finalizado. Si es verdadero, transiciona al estado idle con un 100% de probabilidad.

  • finishRunning: finishRunning = new Transition(() => { return (ThresholdDistance >= Vector2.Distance(transform.position, player.position)); }, new StatePourcentage(idle, 100)); Esta transición verifica si el jugador está más cerca que ThresholdDistance. Si es verdadero, transiciona al estado idle con un 100% de probabilidad.

Añadiendo transiciones al StateManager:

stateManager.AddStateTransition(idle, FarAwayTransition);
stateManager.AddStateTransition(dashState, toIdleTransition);
stateManager.AddStateTransition(runState, finishRunning);

Estas líneas agregan las transiciones definidas al stateManager.

Razón de esta implementación

Cambios de estado dinámicos:

Las transiciones permiten que el enemigo cambie su comportamiento de manera dinámica según la posición del jugador y el estado de finalización del estado actual, haciendo que el enemigo sea más receptivo e interactivo dentro del entorno del juego.

Transiciones condicionales:

El uso de condiciones (como verificar la distancia o la finalización del estado) garantiza que las transiciones de estado ocurran de manera lógica y adecuada, mejorando el realismo de la jugabilidad.

Transiciones basadas en probabilidad:

El uso de StatePourcentage permite transiciones basadas en probabilidad, agregando un elemento de imprevisibilidad y variedad al comportamiento del enemigo.

question mark

¿Qué sucede con el animator cuando se llama al método StartState en la clase RunState?

Select the correct answer

¿Todo estuvo claro?

¿Cómo podemos mejorarlo?

¡Gracias por tus comentarios!

Sección 3. Capítulo 5

Pregunte a AI

expand

Pregunte a AI

ChatGPT

Pregunte lo que quiera o pruebe una de las preguntas sugeridas para comenzar nuestra charla

bookEstado de Carrera

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;
    }
}

Cambios y Adiciones

Variable isStateFinished:

Variable booleana que indica si el estado ha finalizado su ejecución.

Método FinishState:

Nuevo método virtual que establece isStateFinished en true. Al ser virtual, las clases derivadas pueden sobrescribir este método si necesitan realizar acciones adicionales cuando un estado finaliza.

Razones de estos cambios

Los cambios introducen la variable isStateFinished para rastrear la finalización del estado y el método FinishState para estandarizar la señalización de finalización del estado, permitiendo que las clases derivadas agreguen lógica personalizada al completar el estado.

Estado de carrera

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);
    }
}

Analicemos la clase RunState, que hereda de la clase State. Esta clase se encarga de gestionar el comportamiento de carrera de nuestro enemigo. Nos centraremos en las adiciones y cambios realizados en esta clase.

Constructor:

public RunState(Rigidbody2D rb, Animator animator, Transform p, float speed);

Este constructor inicializa el RunState con los componentes necesarios: un Rigidbody2D para el movimiento, un Animator para las animaciones, un Transform para rastrear al jugador y una speed que determina la velocidad a la que corre el enemigo;

Método StartState:

public override void StartState(); Este método establece isStateFinished en false y activa la animación de correr configurando el parámetro booleano "run" en el animator a true.

Método UpdateState:

public override void UpdateState(float DeltaTime); Este método actualiza la posición y orientación del enemigo en función de la posición del jugador; Ajusta la escala del enemigo para que mire hacia el jugador, calcula la velocidad según la velocidad establecida y aplica esta velocidad al Rigidbody2D.

Método EndState:

public override void EndState() Este método detiene la animación de correr estableciendo el parámetro booleano "run" en el animador a false.

Funcionamiento para Nuestro Enemigo

  • Movimiento y Animación: Mediante el uso de Rigidbody2D y Animator, el RunState garantiza que el enemigo pueda moverse de manera fluida y tenga animaciones correspondientes. Esto hace que el comportamiento sea visual y físicamente realista;

  • Seguimiento de la Posición del Jugador: El transform del player permite que el enemigo siempre se desplace hacia el jugador, lo cual es esencial para comportamientos de persecución o huida;

  • Manejo de Dirección: Ajustar el scale.x en función de la posición del jugador asegura que el enemigo mire correctamente hacia el jugador mientras corre, aumentando el realismo;

  • Actualizaciones Dinámicas de Estado: El método UpdateState se llama en cada frame para ajustar continuamente el movimiento y la dirección del enemigo según la posición del jugador, haciendo que el enemigo sea receptivo y dinámico.

Inicialización del Enemigo

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);
}

Explicación

Inicialización del Estado:

Las variables idle y runState se inicializan con sus respectivos estados. La variable idle es una instancia de IdleState con el animador pasado como parámetro, mientras que runState es una instancia de RunState que incluye un Rigidbody2D, un Animator, un Transform para el jugador y un valor de velocidad.

Inicialización de StateManager:

stateManager = new StateManager(idle); El StateManager se inicializa con el estado idle como estado inicial.

Definiciones de Transiciones:

  • FarAwayTransition: FarAwayTransition = new Transition(() => { return (ThresholdDistance < Vector2.Distance(transform.position, player.position)); }, new StatePourcentage(runState, 50f), new StatePourcentage(dashState, 50f));; Esta transición verifica si el jugador está más lejos que ThresholdDistance;

  • toIdleTransition: toIdleTransition = new Transition(() => { return stateManager.GetCurrentState().isStateFinished; }, new StatePourcentage(idle, 100)); Esta transición verifica si el estado actual ha finalizado. Si es verdadero, transiciona al estado idle con un 100% de probabilidad.

  • finishRunning: finishRunning = new Transition(() => { return (ThresholdDistance >= Vector2.Distance(transform.position, player.position)); }, new StatePourcentage(idle, 100)); Esta transición verifica si el jugador está más cerca que ThresholdDistance. Si es verdadero, transiciona al estado idle con un 100% de probabilidad.

Añadiendo transiciones al StateManager:

stateManager.AddStateTransition(idle, FarAwayTransition);
stateManager.AddStateTransition(dashState, toIdleTransition);
stateManager.AddStateTransition(runState, finishRunning);

Estas líneas agregan las transiciones definidas al stateManager.

Razón de esta implementación

Cambios de estado dinámicos:

Las transiciones permiten que el enemigo cambie su comportamiento de manera dinámica según la posición del jugador y el estado de finalización del estado actual, haciendo que el enemigo sea más receptivo e interactivo dentro del entorno del juego.

Transiciones condicionales:

El uso de condiciones (como verificar la distancia o la finalización del estado) garantiza que las transiciones de estado ocurran de manera lógica y adecuada, mejorando el realismo de la jugabilidad.

Transiciones basadas en probabilidad:

El uso de StatePourcentage permite transiciones basadas en probabilidad, agregando un elemento de imprevisibilidad y variedad al comportamiento del enemigo.

question mark

¿Qué sucede con el animator cuando se llama al método StartState en la clase RunState?

Select the correct answer

¿Todo estuvo claro?

¿Cómo podemos mejorarlo?

¡Gracias por tus comentarios!

Sección 3. Capítulo 5
some-alt