Стан Бігу
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;
}
}
Зміни та доповнення
Змінна isStateFinished:
Це булева змінна, яка вказує, чи завершився виконання стану.
Метод FinishState:
Це новий віртуальний метод, який встановлює isStateFinished
у значення true
.
Віртуальний метод означає, що похідні класи можуть перевизначити цей метод, якщо потрібно виконати додаткові дії при завершенні стану.
Чому були внесені ці зміни
Зміни вводять змінну isStateFinished
для відстеження завершення стану та метод FinishState
для уніфікованого сигналізування про завершення стану, що дозволяє похідним класам додавати власну логіку при завершенні стану.
Стан бігу
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);
}
}
Розглянемо клас RunState
, який наслідує клас State
. Цей клас відповідає за обробку поведінки бігу нашого ворога. Зосередимося на доповненнях і змінах, внесених до цього класу.
Конструктор:
public RunState(Rigidbody2D rb, Animator animator, Transform p, float speed)
;
Цей конструктор ініціалізує RunState
необхідними компонентами: Rigidbody2D
для руху, Animator
для анімацій, Transform
для відстеження гравця та speed
для визначення швидкості руху ворога;
Метод StartState:
public override void StartState()
;
Цей метод встановлює isStateFinished
у значення false
та активує анімацію бігу, встановлюючи булевий параметр "run" в аніматорі у true
.
Метод UpdateState:
public override void UpdateState(float DeltaTime)
;
Цей метод оновлює позицію та орієнтацію ворога відповідно до позиції гравця;
Він змінює масштаб ворога для повороту у бік гравця, обчислює швидкість на основі параметра speed та застосовує цю швидкість до Rigidbody2D
.
Метод EndState:
public override void EndState()
Цей метод зупиняє анімацію бігу, встановлюючи булевий параметр "run" в аніматорі у значення false
.
Як це працює для нашого ворога
-
Рух і анімація: Використовуючи
Rigidbody2D
таAnimator
,RunState
забезпечує плавний рух ворога та відповідні анімації. Це робить поведінку візуально та фізично реалістичною; -
Відстеження позиції гравця: Трансформ
player
дозволяє ворогу завжди рухатися до гравця, що є важливим для поведінки переслідування або бігу; -
Обробка напрямку: Коригування
scale.x
залежно від позиції гравця гарантує, що ворог правильно повернутий до гравця під час бігу, що додає реалістичності; -
Динамічне оновлення стану: Метод
UpdateState
викликається кожен кадр для постійного коригування руху та напрямку ворога залежно від позиції гравця, роблячи ворога чутливим і динамічним.
Ініціалізація ворога
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);
}
Пояснення
Ініціалізація станів:
Змінні idle
та runState
ініціалізуються відповідними станами. Змінна idle
є екземпляром IdleState
з переданим аніматором, а runState
— екземпляром RunState
, який містить Rigidbody2D
, Animator
, Transform
для гравця та значення швидкості.
Ініціалізація StateManager:
stateManager = new StateManager(idle);
StateManager
ініціалізується зі станом idle
як початковим станом.
Визначення переходів:
-
FarAwayTransition:
FarAwayTransition = new Transition(() => { return (ThresholdDistance < Vector2.Distance(transform.position, player.position)); }, new StatePourcentage(runState, 50f), new StatePourcentage(dashState, 50f));
; Цей перехід перевіряє, чи гравець знаходиться далі, ніжThresholdDistance
; -
toIdleTransition:
toIdleTransition = new Transition(() => { return stateManager.GetCurrentState().isStateFinished; }, new StatePourcentage(idle, 100));
Цей перехід перевіряє, чи поточний стан завершено. Якщо так, відбувається перехід у станidle
з імовірністю 100%. -
finishRunning:
finishRunning = new Transition(() => { return (ThresholdDistance >= Vector2.Distance(transform.position, player.position)); }, new StatePourcentage(idle, 100));
Цей перехід перевіряє, чи гравець знаходиться ближче, ніжThresholdDistance
. Якщо так, відбувається перехід у станidle
з імовірністю 100%.
Додавання переходів до StateManager:
stateManager.AddStateTransition(idle, FarAwayTransition);
stateManager.AddStateTransition(dashState, toIdleTransition);
stateManager.AddStateTransition(runState, finishRunning);
Ці рядки додають визначені переходи до stateManager
.
Чому ми зробили саме так
Динамічні зміни станів:
Переходи дозволяють ворогу динамічно змінювати свою поведінку залежно від позиції гравця та статусу виконання поточного стану, що робить ворога більш чутливим та інтерактивним у ігровому середовищі.
Умовні переходи:
Використання умов (наприклад, перевірка відстані або завершення стану) гарантує, що переходи між станами відбуваються логічно та доречно, підвищуючи реалістичність ігрового процесу.
Переходи на основі ймовірності:
Використання StatePourcentage
дозволяє створювати переходи на основі ймовірності, додаючи елемент непередбачуваності та різноманіття у поведінку ворога.
Дякуємо за ваш відгук!