Menu
CoddyTech

Состояния как классы

Часть раздела Архитектура игр в Unity путешествия по Unity на Coddy. Урок 28 из 50.

В разделе 3 оператор switch по перечислению объединяет работу всех состояний в одном Update. Такой подход перестаёт масштабироваться, когда у состояний появляются собственные данные: таймер, который использует только одно состояние, становится полем MonoBehaviour рядом с полями всех остальных состояний, и каждый case должен не забывать сбрасывать используемые им данные. Шаблон состояния в C# даёт каждому состоянию собственный класс, и каждый класс реализует один интерфейс. Этот дорожный маяк мигает или горит постоянно, а клавиша Space переключает режимы:

public interface IState
{
    void Enter();
    void Tick();
    void Exit();
}

public class BlinkState : IState
{
    private Renderer lamp;
    private float timer;

    public BlinkState(Renderer lamp)
    {
        this.lamp = lamp;
    }

    public void Enter() { timer = 0f; }

    public void Tick()
    {
        timer += Time.deltaTime;
        if (timer >= 0.5f)
        {
            timer = 0f;
            lamp.enabled = !lamp.enabled;
        }
    }

    public void Exit() { lamp.enabled = true; }
}

public class SteadyState : IState
{
    public void Enter() { }
    public void Tick() { }
    public void Exit() { }
}

public class Beacon : MonoBehaviour
{
    public Renderer lamp;
    private IState blink;
    private IState steady;
    private IState current;

    void Start()
    {
        blink = new BlinkState(lamp);
        steady = new SteadyState();
        SetState(steady);
    }

    void Update()
    {
        if (Keyboard.current.spaceKey.wasPressedThisFrame) SetState(current == steady ? blink : steady);
        current.Tick();
    }

    void SetState(IState next)
    {
        if (current != null) current.Exit();
        current = next;
        current.Enter();
    }
}

Состояния — это обычные классы C#, а не MonoBehaviours. Вы создаёте их с помощью new и передаёте им необходимые данные через конструктор — здесь это Renderer лампы, — потому что они не являются компонентами и не могут вызывать GetComponent или отображать поля в Inspector. Unity также не вызывает их методы: Beacon — это MonoBehaviour, поэтому его Update вызывает current.Tick() каждый кадр.

timer принадлежит только BlinkState, а его Enter каждый раз устанавливает его в 0, когда маяк начинает мигать. Exit приводит состояние в порядок при его завершении: нажатие Space может произойти, пока лампа выключена, и Exit включает её обратно, поэтому SteadyState никогда не начинается с погасшей лампой. SetState вызывает Exit старого состояния, затем Enter нового. Третье состояние, например медленная пульсация, — это ещё один класс, а Update в Beacon не меняется.

challenge icon

Задание

Средне

Турель-часовой охраняет двор. Стрелки управляют персонажем Player (готово). Задай турели два состояния в виде классов:

  • В IState.cs объяви public interface IState с методами void Enter(), void Tick() и void Exit().
  • В TurretStates.cs напиши два обычных класса, реализующих этот интерфейс. ScanState получает голову турели в конструкторе. Она поворачивает голову из стороны в сторону: локальный угол головы по оси y меняется со скоростью 90 градусов в секунду в диапазоне от -45 до 45, начиная с 0 и каждый раз при начале сканирования поворачиваясь вверх. В методе Enter она также окрашивает голову в Color.green.
  • AlertState получает голову и игрока. В методе Enter он окрашивает голову в Color.red и выводит в журнал Intruder!; в методе Tick поворачивает голову к игроку только по оси y, без наклона; в методе Exit выводит в журнал All clear.
  • В Turret.cs создай оба состояния в методе Start и начни сканирование. Каждый кадр переключайся в состояние тревоги, если игрок находится ближе, чем range (4), к турели, и обратно в состояние сканирования, если это не так, а затем запускай метод Tick текущего состояния. При смене состояния сначала запускается метод Exit старого состояния, а затем метод Enter нового.

Нажми Play, подойди к турели и снова отойди, затем нажми Check.

Попробуйте сами

using UnityEngine;

// ScanState и AlertState
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Архитектура игр в Unity