Scenes
Сцены содержат объекты вашей игры. Они могут использоваться для создания главного меню, отдельных уровней и для других целей. Можно считать каждый файл сцены отдельным игровым уровнем. В каждой сцене можно разместить объекты окружения, заграждения, декорации, по кусочкам создавая дизайн и саму игру.
When you create a new Unity project, your scene view will show a new Scene. This is an untitled and unsaved scene. The scene will be empty except for defult objects — either an orthographic camera, or a perspective camera and a directional light, depending on whether you started the project in 2D or 3D mode.
To save the scene you’re currently working on, choose File > Save Scene from the menu, or pres Ctrl/Cmd + S.
Scenes are saved as assets, into your project’s Assets folder. Therefore they appear in the Project Window, just like any other asset.
To open a scene, in order to begin or continue working within that scene, double-click the scene asset in the Project Window.
If your current scene contains unsaved changes, you will be prompted to save or discard the changes.
Multi-Scene Editing.
It is possible to have multiple scenes open for editing at one time. For more information about this, see Multi-Scene Editing.
Переход между сценами
Приветствую! В данной статье мы разберём несколько способов перехода между сценами, а именно:
- Смена сцен по названию.
- Смена сцен по индексам.
- Смена сцен, используя параметры.
Смена сцен по названию
Данный способ самый простой, и встречается он очень часто. Он используется тогда, когда нам необходимо перейти точно на определённую сцену. Для этого создадим C# скрипт, с названием, например, Scenes. И пропишем в нём следующий код:
using UnityEngine; using UnityEngine.SceneManagement; public class Scenes : MonoBehaviour < public void OpenMenu() < SceneManager.LoadScene("Menu"); >public void OpenGame() < SceneManager.LoadScene("Game"); >>
Разбор кода
Обратите внимание, что при работе со сценами, нам необходимо обязательно подключить библиотеку:
using UnityEngine.SceneManagement;
Дальше мы создаём функцию OpenMenu(), которая будет загружать сцену с названием Menu. Вторая функция с названием OpenGame() загружаем сцену с названием Game. Убедитесь, что сцены с такими названиями существуют в Вашем проекте.
Как видите, всё очень просто. Условия, при которых Вы будете запускать данные функции, могут быть совсем разные. Например: клик на клавишу «Esc», здоровье персонажа меньше нуля, и тд. Пример:
if(HealthUser
Смена сцен по индексам
Данный способ аналогичен предыдущему, за исключением того, что мы вместо названий сцен, используем их индексы. Данный способ полезен в тех случаях, когда нам необходимо перейти на следующую или предыдущую сцену. Создадим C# скрипт, с названием, например, Scenes. И пропишем в нём следующий код:
using UnityEngine; using UnityEngine.SceneManagement; public class Scenes : MonoBehaviour < public void OpenMenu() < SceneManager.LoadScene(0); >public void OpenGame() < SceneManager.LoadScene(1); >>
Как видите, код аналогичен предыдущему, поэтому разбирать мы его не будем. Единственное что хотелось бы отметить, что благодаря функциям, у нас открываются чуть больше возможностей перехода на сцены. Например, мы можем перейти на следующую или предыдущую функцию:
using UnityEngine; using UnityEngine.SceneManagement; public class Scenes : MonoBehaviour < public void NextLevel() < var index = SceneManager.GetActiveScene().buildIndex; SceneManager.LoadScene(index + 1); >public void PreviousLevel() < var index = SceneManager.GetActiveScene().buildIndex; SceneManager.LoadScene(index - 1); >>
Разбор кода
Строчки в функции NextLevel():
var index = SceneManager.GetActiveScene().buildIndex; SceneManager.LoadScene(index + 1);
В первой строчке мы в переменную index мы заносим тот индекс сцены, в котором мы находимся в данный момент. А уже во второй строчке, мы увеличиваем индекс нашей сцены на единицу, и запускаем таким образом следующую сцену.
В функции PreviousLevel() всё аналогично, только индекс мы не увеличиваем на единицу, а уменьшаем. Тем самым запускаем предыдущую сцену.
Обратите внимание! Перед тем как работать со сценами по их индексам, нам необходимо добавить все сцены в Build Settings. Для этого жмём на вкладку File — Build Settings. Далее перетаскиваем все свои сцены в область Scenes in Build, и расставляем их по порядку. После чего просто закрываем данное окно. Теперь можно спокойно работать с индексами.
Смена сцен, используя параметры
Данный способ аналогичен предыдущему, только здесь мы переходим на определённую сцену исходя из переданного аргумента в нашу функцию.
using UnityEngine; using UnityEngine.SceneManagement; public class Scenes : MonoBehaviour < public void GoToLevel(int number) < SceneManager.LoadScene(number); >>
Разбор кода
Функция GoToLevel() принимает в качестве аргумента номер индекса, который нам необходимо открыть, и заносит его в переменную number. Этот метод защитит нас от дублирования однотипных функций, которые по идее выполняют одно и тоже.
Давайте теперь попробуем выполнить функцию GoToLevel(), передав ей аргумент «1» следующим образом:
GoToLevel(1)
Конечно же, в качестве аргумента мы можем передать не только индекс, но и название. Поэтому используя открытие сцены через аргумент функции, Вы можете работать как с индексами, так и с названиями сцен.
Если Вам понравилась сцена, буду рад Вашим лайкам.
Как переименовать сцену
Есть две сцены — одна называется Untitled а друга SampleScene . Как назвать их Menu и Level1 ? Версия 2018.4.7f1.
Лучшие ответы ( 1 )
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:
Как перезапустить сцену?
Не могу перезапустить сцену, точнее сцена перезагружается, но враги перестают спавнится и.
Как затемнить сцену?
Приветствую! Такая беда: В моей 2D игре игроки, подключённые по сети, бегают по ЗАТЕМНЁННОЙ сцене.
Как узнать текущую сцену (уровень)?
Как узнать текущую сцену и вывести её в переменную? Должно получиться что то типа этого: scen =.
Как сохранить сцену после нажатия?
У меня есть игрок который может перемещаться по сценам. Например когда он первый раз зашел на сцену.
Как мы переосмыслили работу со сценами в Unity
Unity, как движок, имеет ряд недостатков, но которые благодаря возможностям для кастомизации и инструментам для кодогенерации, можно решить.
Сейчас я вам расскажу о том, как мы написали плагин для Unity на основе пост-процессинга проектов и кодогенератора CodeDom.
Проблема
В Unity загрузка сцен происходит через строковой идентификатор. Он не стабильный, а это означает, что он легко изменяем без явных последствий. Например, при переименовании сцены всё полетит, а выяснится это только в самом конце на этапе выполнения.
Проблема обнаруживается быстро на часто используемых сценах, но может быть трудно обнаруживаемая, если речь идёт о небольших additive сценах или сценах, которые используются редко.
Решение
При добавлении сцены в проект, генерируется одноимённый класс с методом Load.
Если мы добавим сцену Menu, то в проекте сгенерируется класс Menu и в дальнейшем мы можем запустить сцену следующим образом:
Menu.Load();
Да, статический метод — это не лучшая компоновка. Но мне показалось это лаконичным и удобным дизайном. Генерация происходит автоматически, исходный код такого класса:
//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace IJunior.TypedScenes < public class Menu : TypedScene < private const string GUID = "a3ac3ba38209c7744b9e05301cbfa453"; public static void Load() < LoadScene(GUID); >> >
По-хорошему, класс должен быть статическим, так как не предполагается создание экземпляра из него. Это ошибка, которую мы исправим. Как видно уже из этого фрагмента, кода мы цепляемся не к имени, а к GUID сцены, что является более надежным. Сам базовый класс выглядит вот так:
namespace IJunior.TypedScenes < public abstract class TypedScene < protected static void LoadScene(string guid) < var path = AssetDatabase.GUIDToAssetPath(guid); SceneManager.LoadScene(path); >protected static void LoadScene(string guid, T argument) < var path = AssetDatabase.GUIDToAssetPath(guid); UnityActionhandler = null; handler = (from, to) => < if (to.name == Path.GetFileNameWithoutExtension(path)) < SceneManager.activeSceneChanged -= handler; HandleSceneLoaders(argument); >>; SceneManager.activeSceneChanged += handler; SceneManager.LoadScene(path); > private static void HandleSceneLoaders(T loadingModel) < foreach (var rootObjects in SceneManager.GetActiveScene().GetRootGameObjects()) < foreach (var handler in rootObjects.GetComponentsInChildren()) < handler.OnSceneLoaded(loadingModel); >> > > >
В этой реализации видна ещё одна фишка — передача параметров сценам.
Параллельно с решением первой проблемы — избавить код от строковых идентификаторов сцены (в том числе и от констант, которые нужно обновлять вручную), мы добавили еще и параметризацию сцен.
Теперь сцена может задекларировать список параметров, а вызывающий код должен передать для них аргументы.
Например, сцена Game хочет получить перечисление, содержащее всех игроков и при инициализации добавить для них аватаров.
В таком случае мы можем сами создать такой компонент.
using IJunior.TypedScenes; using System.Collections.Generic; using UnityEngine; public class GameLoadHandler : MonoBehaviour, ISceneLoadHandler> < public void OnSceneLoaded(IEnumerableplayers) < foreach (var player in players) < //make avatars >> >
После размещения его на сцене и последующим её сохранением, генератор добавит в класс сцены метода запуска сцены с обязательной передачей перечисления игроков.
//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // //------------------------------------------------------------------------------ namespace IJunior.TypedScenes < public class Game : TypedScene < private const string GUID = "976661b7057d74e41abb6eb799024ada"; public static void Load(System.Collections.Generic.IEnumerableargument) < LoadScene(GUID, argument); >> >
В данный момент реализована возможность перегрузки обработчиков. Т.е. если на сцене будет N обработчиков с разными параметрами, под них создастся N методов запуска. Также не запрещается наличие нескольких компонентов-обработчиков с одинаковыми параметрами.
Это не фишка, а скорее недоработка, так как такой функционал быстрее создаст путаницу, нежели будет полезен.
А почему не сделать через N?
Первую версию плагина я осветил на своём YouTube канале в этом видео.
Там задали ряд вопросов и предложили альтернативные решения. Есть интересные подходы, которые имеют право на жизнь, а есть откровенно идиотские, которые я хочу разобрать.
Чем плох статический класс с полями, через которые передаются данные для сцены?
Нередко встречаю и такое. Речь идёт о классе по типу этого:
public class GameArguments < public IEnumerablePlayers < get; set; >>
А уже внутри сцены, вероятно, будет группа компонентов, которая достаёт данные из свойств.
Основная проблема в том, что нет формализации: при загрузки сцены не совсем ясно, что нам нужно предоставить для корректной работы. Получателей в целом определить будет проще, так как мы можем воспользоваться поиском по ссылке.
Ну и опять же сцену придётся запускать по ID или имени.
Чем плох PlayerPerfs
Предлагали и такой экзотический вариант. Можно было бы начать с того, что PlayerPrefs вообще не предназначен для передачи значений внутри одного инстанса. Этим можно было бы и закончить, но продолжим критику тем, что вам также придётся работать с неформальными строковыми идентификаторами параметров.
Параллель с ASPNet
Мне хотелось получить что-то схожее с строго типизированными View из ASPNet Core. Мы считаем плохим тоном использовать ViewData и стараемся определять ViewModel. В Unity хочется что-то такого же толка с теми же преимуществами.
Отличие Unity в первую очередь в том, что сцена — это обычно более громоздкое предприятие, нежели View в ASPNet. Это решается разбивкой одной сцены на несколько подсцен с режимом загрузки Additive (наш плагин, к слову, его поддерживает), что позволяет скомпоновать сцену из сцен поменьше со своими более атомарными моделями.
Но такой подход не очень распространён, к сожалению, и на это, я думаю, есть свои причины.
Где скачать
Плагин мы сделали в паре с Владиславом Койдо в рамках Proof-of-concept. Он ещё не стабилен и не обкатан как следует, но с ним уже можно поиграться.
Если вам интересно, я попрошу Владислава в следующей статье рассказать, как он работал с Code Dom в Unity и как работать с пост-процессингом на примере того, что мы сегодня обсуждали.