Машина состояний
Часть раздела Архитектура игр в Unity путешествия по Unity на Coddy. Урок 37 из 64.
Метод SetState у маяка был бы одинаковым для любого объекта с состояниями: турели, противника, двери. Этот код может находиться в отдельном классе — машине состояний, которая хранит текущее состояние и меняет его. Каждый объект создает свою машину и вызывает ее вместо того, чтобы повторять код:
public class StateMachine
{
public IState Current { get; private set; }
public void ChangeState(IState next)
{
Current?.Exit();
Current = next;
Current.Enter();
}
public void Tick()
{
Current?.Tick();
}
}
public class Beacon : MonoBehaviour
{
public Renderer lamp;
private StateMachine machine = new StateMachine();
private IState blink;
private IState steady;
void Start()
{
blink = new BlinkState(lamp);
steady = new SteadyState();
machine.ChangeState(steady);
}
void Update()
{
if (Keyboard.current.spaceKey.wasPressedThisFrame) machine.ChangeState(machine.Current == steady ? blink : steady);
machine.Tick();
}
}При первом вызове ChangeState выходить из состояния не нужно: Current равен null, и ?. пропускает вызов Exit. В разделе 1 предупреждалось, что ?. не распознает фиктивный null в Unity; это относится к уничтоженным объектам Unity, а состояния — обычные объекты C#, поэтому здесь ?. безопасен. У Current есть private set, поэтому никакой скрипт не может сменить состояние, не вызвав ChangeState и его Exit и Enter.
Порядок действий внутри ChangeState важен, когда два состояния взаимодействуют с одним и тем же объектом. Exit отменяет изменения, внесенные старым состоянием, а затем Enter настраивает новое, поэтому последнее слово остается за новым состоянием. Если бы Enter состояния DarkState выключал лампу и выполнялся до Exit состояния BlinkState, этот Exit снова включил бы лампу в темном состоянии. StateMachine тоже является обычным классом: маяк, турель и противник каждый создают свою машину с помощью new и вызывают ее Tick из своего Update.
Задание
СреднеУправляйте состояниями игрока с помощью автомата.
- В
StateMachine.csнапишитеpublic class StateMachineсpublic IState Current { get; private set; }и методомTick(), который вызывает Tick текущего состояния. ChangeState(IState next)игнорирует текущее состояние; иначе вызывает Exit, задаётCurrentи вызывает Enter.Player: в Start создайтеmachine,walk,sneakи перейдите в состояние ходьбы; в Update переходите в состояние крадущегося движения, пока удерживается Space, иначе — в состояние ходьбы, а затем вызывайте Tick.
Нажмите «Играть» и удерживайте Space: Sneak: enter. Затем нажмите «Проверить».
Попробуйте сами
// StateMachine: Current, ChangeState и Tick
Все уроки раздела Архитектура игр в Unity
1Компоненты, а не иерархии
Небольшие компонентыБазовый скрипт врагаАбстрактные компонентыКомпоненты работают вместеПовторение: модульная турельПовторение: спаренная пушка4Сериализованные данные
Сериализуемые классыСписки в инспектореПеречисления в инспектореПовторение: таблица добычиПовторение: определяем добычу7Машины состояний
Состояния как классыСостояние тревогиМашина состоянийПереходыЛогика враговРыцарь атакуетПовторение: состояния двери2Интерфейсы в Unity
IDamageableИнтерфейсы и TryGetComponentGetComponentsПовторение: клавиша взаимодействияПовторение: ближайший в пределах досягаемости5ScriptableObjects
Ресурсы данныхХарактеристики оружияОбщие настройкиСохраняем ветерВолны как данныеПовторение: база предметовПовторение: покупка в магазинеПотренируйтесь самостоятельно: Песочница Unity