Переход между уровнями в игре на Unity

Как сделать переход между уровнями в Unity

·  9 мин чтения Unity C# SceneManager LoadLevel Build Profiles Для начинающих

Коротко. Чтобы сделать переход между уровнями в Unity, добавьте сцены в Build Profiles, подключите using UnityEngine.SceneManagement; и вызовите SceneManager.LoadScene("ИмяСцены") или SceneManager.LoadScene(индекс). Запустить переход можно с UI-кнопки, из другого скрипта или из триггера финишной зоны.

Ниже — готовый универсальный скрипт LevelLoader, переход из финишной зоны, плавное затемнение через LoadSceneAsync и разбор частых ошибок.

Первый уровень готов, играется — и почти сразу хочется большего: чтобы после финиша начинался следующий. И тут возникает логичный вопрос — а как вообще перекинуть игрока с одного уровня на другой? Спешу обрадовать: в Unity это делается буквально в пару строк. Каждый уровень здесь — это отдельная сцена (Scene), а переход между уровнями — просто её загрузка через класс SceneManager. Дальше мы пройдём весь путь по шагам: добавим уровни в сборку, напишем один универсальный скрипт LevelLoader под любую игру и повесим переход на финишную зону. Весь код готовый — копируй прямо к себе в проект.

Скажу сразу, почему на этой «мелочи» стоит задержаться. Последние годы я как lead-разработчик делал на Unity хоррор The Floor Above — он вышел в Steam, — где комната вокруг героя раз за разом повторяется. Вся эта «бесконечность» под капотом держится ровно на том, о чём эта статья: на перезагрузке сцены через SceneManager. Так что не смотри, что метод простой — на нём спокойно стоят и коммерческие проекты.

Как устроен переход между уровнями в Unity

Смотри: в Unity вообще нет отдельной штуки под названием «уровень» — вместо неё работает сцена. Меню — это сцена, первый уровень — сцена, второй — ещё одна. Поэтому «сменить уровень» на деле означает загрузить нужную сцену: старая закрывается, новая открывается. Всю работу берёт на себя метод SceneManager.LoadScene(), а обратиться к сцене можно двумя способами:

Оба варианта рабочие — и, чтобы не пришлось выбирать, ниже мы соберём скрипт, где есть сразу и тот, и другой.

Шаг 1. Добавляем уровни в сборку (Build Profiles)

Здесь есть момент, о который спотыкаются почти все новички: Unity не сможет загрузить сцену, пока ты не добавишь её в сборку. Открой File → Build Profiles (так это меню называется в Unity 6; в версиях постарше — File → Build Settings) и добавь все уровни в список Scene List в том порядке, в котором игрок будет их проходить. Рядом сразу появятся их индексы — 0, 1, 2 и дальше по списку.

Окно Build Profiles в Unity со списком сцен-уровней и их индексами
Все уровни добавлены в список сцен по порядку — от индекса 0.

Частая ошибка: если сцены нет в списке сцен сборки, при загрузке Unity просто выдаст ошибку. Если что-то не работает — первым делом загляни в Build Profiles и убедись, что уровень в списке и стоит на своём месте.

Шаг 2. Универсальный скрипт LevelLoader

Можно, конечно, прописывать загрузку сцены в каждом объекте по отдельности — но такой проект быстро превращается в кашу. Куда спокойнее живётся с одним скриптом-менеджером. Создай C#-скрипт LevelLoader и повесь его на пустой объект GameManager. Внутри — четыре готовых метода на все случаи жизни: следующий уровень, конкретный уровень по имени, перезапуск и выход в меню.

C#
using UnityEngine;
using UnityEngine.SceneManagement;

public class LevelLoader : MonoBehaviour
{
    // Следующий уровень по порядку из списка сборки
    public void LoadNext()
    {
        int next = SceneManager.GetActiveScene().buildIndex + 1;

        if (next < SceneManager.sceneCountInBuildSettings)
            SceneManager.LoadScene(next);
        else
            SceneManager.LoadScene(0); // уровни кончились — на первый
    }

    // Конкретный уровень по имени сцены
    public void LoadLevel(string sceneName)
    {
        SceneManager.LoadScene(sceneName);
    }

    // Перезапустить текущий уровень (например, после проигрыша)
    public void Reload()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
    }

    // Вернуться в меню — первую сцену в списке
    public void LoadMenu()
    {
        SceneManager.LoadScene(0);
    }
}

Как использовать LevelLoader

Вся прелесть этого скрипта в том, что дёргать его методы можно откуда угодно:

Лайфхак: метод LoadLevel(string) можно повесить прямо на кнопку и вписать имя сцены в поле параметра прямо в инспекторе. Так одна кнопка «Играть» отправит игрока в любой уровень — и всё это без единой правки в коде.

Шаг 3. Запускаем переход из финишной зоны

Скрипт у нас уже есть — осталось только чем-то его запускать. В платформерах уровень чаще всего меняется в тот момент, когда игрок добегает до флажка, двери или портала. Давайте сделаем такую невидимую финишную зону: создайте пустой объект Finish с компонентом Box Collider 2D (если у вас 2D-проект) или Box Collider (если проект 3D) и включите у него галочку Is Trigger. Такой коллайдер не отталкивает игрока и никак не мешает его движению — он просто определяет момент, когда игрок входит в эту зону.

Настройка Box Collider с галочкой Is Trigger в инспекторе Unity
Финишная зона — коллайдер с включённым Is Trigger.

Теперь вешаем на Finish совсем короткий скрипт. Как только в зону заходит игрок, он вежливо просит LevelLoader подгрузить следующий уровень:

C#
using UnityEngine;

public class FinishZone : MonoBehaviour
{
    [SerializeField] private LevelLoader loader; // Перетащите сюда объект с компонентом LevelLoader

    // Для 2D-проекта оставьте этот метод, а OnTriggerEnter() удалите.
    private void OnTriggerEnter2D(Collider2D other)
    {
        // Реагируем только на игрока
        if (!other.CompareTag("Player"))
            return;

        loader.LoadNext();
    }

    // Для 3D-проекта оставьте этот метод, а OnTriggerEnter2D() удалите.
    private void OnTriggerEnter(Collider other)
    {
        // Реагируем только на игрока
        if (!other.CompareTag("Player"))
            return;

        loader.LoadNext();
    }
}

Совет: проверьте две вещи: что персонажу присвоен тег Player (поле Tag в верхней части инспектора) и что на нём есть Rigidbody2D и Collider2D (для 2D-проекта) или Rigidbody и Collider (для 3D-проекта). Без этих компонентов событие триггера не сработает, а поиск такой мелочи легко может отнять полчаса.

Бонус: плавный переход с затемнением (LoadSceneAsync)

Когда картинка меняется рывком, это немного бьёт по глазам, а на тяжёлых уровнях игра ещё и «подвисает» на кадр. В проектах посерьёзнее переход делают через асинхронную загрузку SceneManager.LoadSceneAsync(): новая сцена тихо грузится в фоне, экран в это время плавно уходит в затемнение через CanvasGroup, а потом так же мягко проявляется. Заодно из неё можно вытащить прогресс загрузки (operation.progress) и нарисовать полосу «Loading…».

Вот тот же переход, но плавный. Понадобится полноэкранная чёрная картинка (Image) с компонентом CanvasGroup — перетащите её в поле fade:

C#
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;

public class FadeLoader : MonoBehaviour
{
    [SerializeField] private CanvasGroup fade;   // чёрный экран поверх всего UI
    [SerializeField] private float speed = 1.5f; // скорость затемнения

    // Повесьте этот метод на кнопку или на финишную зону вместо LoadNext()
    public void LoadNextSmooth()
    {
        int next = SceneManager.GetActiveScene().buildIndex + 1;
        if (next >= SceneManager.sceneCountInBuildSettings)
            next = 0;

        StartCoroutine(FadeAndLoad(next));
    }

    private IEnumerator FadeAndLoad(int sceneIndex)
    {
        // 1. Плавно затемняем экран до чёрного
        while (fade.alpha < 1f)
        {
            fade.alpha += Time.deltaTime * speed;
            yield return null;
        }

        // 2. Грузим сцену в фоне, не роняя FPS
        AsyncOperation op = SceneManager.LoadSceneAsync(sceneIndex);
        while (!op.isDone)
            yield return null;

        // 3. Плавно проявляем новую сцену
        while (fade.alpha > 0f)
        {
            fade.alpha -= Time.deltaTime * speed;
            yield return null;
        }
    }
}

Заметка: для первых проектов это точно не обязательно — обычного LoadScene хватает за глаза. Но именно так плавные переходы сделаны в The Floor Above: пока «новая» комната собирается в фоне, экран на секунду гаснет — и игрок не замечает шва. Пусть приём полежит у тебя в копилке.

Частые ошибки перехода между уровнями

Вывод

Вот и всё — теперь у тебя в руках рабочая система перехода между уровнями: один LevelLoader на всю игру плюс лёгкая финишная зона, которую можно ставить хоть на каждый уровень. А дальше её легко достроить под себя: добавить экран «Уровень пройден», звук победы, сохранение прогресса или то самое плавное затемнение. Кстати, если на уровнях много однотипных объектов, их удобно расставлять не вручную, а математическими формулами прямо в Inspector — я разбирал этот приём в отдельной статье. Если же Unity для тебя пока тёмный лес и хочется начать с самых азов — с установки, первого проекта и первого скрипта — загляни на бесплатный курс Unity Старт, а потом посмотри и полную программу обучения. Удачи с игрой!

Частые вопросы

Как загрузить сцену в Unity по имени?

Подключите пространство имён using UnityEngine.SceneManagement; и вызовите SceneManager.LoadScene("ИмяСцены"). Имя должно буква в букву совпадать с названием файла сцены, а сама сцена — быть добавлена в Build Profiles (в старых версиях — Build Settings).

Как перейти на следующий уровень по порядку?

Возьмите индекс текущей сцены и прибавьте единицу: int next = SceneManager.GetActiveScene().buildIndex + 1;, затем SceneManager.LoadScene(next). Перед загрузкой проверьте, что next меньше SceneManager.sceneCountInBuildSettings, иначе после последнего уровня будет ошибка — в скрипте LevelLoader выше эта проверка уже вшита.

Почему сцена не загружается в Unity?

Причина номер один — сцена не добавлена в список сцен сборки. Откройте File → Build Profiles (Build Settings) и убедитесь, что уровень есть в Scene List. Вторая частая причина — опечатка в имени: для Unity "level2" и "Level_2" это разные сцены.

Чем LoadScene отличается от LoadSceneAsync?

LoadScene загружает сцену синхронно — игра замирает на кадр, зато код проще. LoadSceneAsync грузит сцену в фоне и возвращает объект прогресса, поэтому подходит для тяжёлых уровней и экрана загрузки с полосой прогресса или плавным затемнением.

Как сделать плавный переход между сценами с затемнением?

Используйте SceneManager.LoadSceneAsync: пока сцена грузится в фоне, плавно затемните экран через CanvasGroup (alpha от 0 до 1), а после загрузки так же плавно проявите новую сцену. Готовый скрипт FadeLoader есть в разделе про плавный переход выше.

Хочешь научиться делать игры на Unity?

Начни бесплатно с курса Unity Старт — установка, первый проект и первый скрипт, шаг за шагом.

Начать бесплатно