Menu
CoddyTech

Переключение состояния

Часть раздела Создание настоящих игр путешествия по Unity на Coddy. Урок 15 из 60.

Каждое состояние игры выполняет свою работу в каждом кадре. Конструкция switch по полю состояния помещает эту работу в отдельный блок case для каждого состояния, и в каждом кадре выполняется ровно один блок. Состояние меняется через один метод, поэтому экран всегда соответствует состоянию. В этой битве с боссом есть вступление, бой и экран победы:

public enum Phase { Intro, Fight, Won }

public class BossFight : MonoBehaviour
{
    public GameObject introPanel;
    public GameObject fightPanel;
    public GameObject winPanel;
    public int bossHp = 10;
    private Phase phase;
    private float timer = 3f;

    void Start()
    {
        Enter(Phase.Intro);
    }

    void Update()
    {
        switch (phase)
        {
            case Phase.Intro:
                timer -= Time.deltaTime;
                if (timer <= 0f) Enter(Phase.Fight);
                break;
            case Phase.Fight:
                if (bossHp <= 0) Enter(Phase.Won);
                break;
            case Phase.Won:
                break;
        }
    }

    void Enter(Phase next)
    {
        phase = next;
        introPanel.SetActive(next == Phase.Intro);
        fightPanel.SetActive(next == Phase.Fight);
        winPanel.SetActive(next == Phase.Won);
    }
}

Каждый блок case заканчивается на break, потому что C# отказывается компилировать блок case, который продолжается следующим. Когда время вступления истекает, Enter(Phase.Fight) меняет фазу, но блок Fight выполняется только в следующем кадре, поскольку в этом кадре блок уже был выбран. Если использовать несколько отдельных блоков if один за другим, за один кадр можно начать бой и выполнить код боя.

Enter — единственное место, где изменяется phase. Выражение next == Phase.Fight равно true только для панели боя, поэтому один вызов показывает эту панель и скрывает две другие. Действия, связанные с переходом в состояние, например сброс таймера, тоже выполняются в Enter и запускаются один раз, а не в каждом кадре.

challenge icon

Задание

Легко

Сделай гонку нажатий длительностью 5 секунд.

  1. В SetState показывай только панель нового состояния. При переходе в Playing устанавливай taps = 0, timeLeft = roundTime и Taps: 0; при переходе в GameOver показывай Taps: 3 в resultText.
  2. В Update() используй switch (state): клавиша Space переводит Ready в Playing, а GameOver — в Ready; в Playing каждое нажатие Space учитывается в taps и tapsText, пока не истечёт время.

Нажми «Играть» и проведи гонку дважды. Затем нажми «Проверить».

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

using UnityEngine;
using TMPro;

public enum GameState { Ready, Playing, GameOver }

public class GameManager : MonoBehaviour
{
    public GameObject readyPanel;
    public GameObject playPanel;
    public GameObject gameOverPanel;
    public TMP_Text tapsText;
    public TMP_Text resultText;
    public float roundTime = 5f;
    public GameState state;
    private int taps;
    private float timeLeft;

    void Start()
    {
        SetState(GameState.Ready);
    }

    void Update()
    {
        // выбор действий в зависимости от state:
        // Ready: Space запускает раунд
        // Playing: Space засчитывает нажатие; когда время истекает, игра заканчивается
        // GameOver: Space возвращает игру в Ready
    }

    void SetState(GameState next)
    {
        state = next;
        // показывать только панель нового состояния
        // новый раунд начинается с 0 нажатий и длится roundTime секунд; в конце resultText показывает количество нажатий
    }
}

Все уроки раздела Создание настоящих игр

Потренируйтесь самостоятельно: Песочница Unity