Игра-головоломка NeoAngle. Работа с уровнями в Unity
Всем доброго времени суток! Я бы хотел вам рассказать историю своей новой игры-головоломки NeoAngle, а также поделиться опытом импортирования, хранения и генерации уровней в Unity.
Начну с краткой предыстории, которая началась еще 5 лет назад, когда я решился заняться геймдевом, впервые познакомившись с языком программирования action script 3.0 (для разработки flash-игр) в университете.
Закончив семестр, я решил, что смог бы осилить собственную игру. Так, посидев какое-то время за блокнотом и карадашом, пришла идея головоломки с треугольниками, где игроку нужно путем переворачивания треугольного камня заполнить заданную форму и закончить уровень на финишной клетке.
Таким образом, затратив неделю на разработку в одиночку, была выпущена моя первая flash-игра SeaQuest.
И понесло меня разрабатывать дальше. Выпустив еще несколько портальных флэшек, я вернулся к идее с треугольниками, что привело к новой части, где геймплей был полностью переработан, а именно добавлены дополнительные интерактивные объекты: кнопки с препятствиями, телепорты и вращатели. Цель уровня также изменилась, теперь нужно было собрать все жемчужины и прийти к финишу.
Результат под названием Stone Quest
На этом линейка логических игр завершилась и была успешно мной позабыта.
Далее последовал обещанный обвал флэш индустрии, который перекинул меня в unity разработку для мобильных. И вот, в декабре 2016 года, совершенно случайно мне в голову вернулась мысль о треугольно-ориентированных головоломках. Особенно подтолкнуло к разработке то, что геймплей отлично подходит под тачскрин. Было решено использовать механику предыдущей игры, но с другой стилизацией.
Вот такая предыстория, которая привела к активной полуторамесячной разработке. Большая часть работы, как ни странно, ушла на геймдизайн. Из предыдущей версии почти все уровни мне показались недостаточно интересными, хотя возможности геймплея имеют гораздо больший потенциал. В следствие чего разработка началась с редактора уровней, который я написал за вечер на старом добром флэше, с возможностью тестирования написанных уровней и их экспорта/импорта в xml.
Результат работы в редакторе продемонстрирован ниже:
Прежде чем перейти к работе с Unity, мне необходимо было убедиться в том, что я смогу предоставить достаточное количество уровней для мобильной игры, которая требует разнообразный контент. Поэтому первые полторы недели я даже не открывал Unity, а работал в своем редакторе, параллельно занимаясь графикой. К слову, был выбран набирающий популярность ретро-стиль synthwave 80-ых. Он достаточно прост в исполнении, являясь при этом очень привлекательным.
Таким образом, создав допустимый набор уровней, я приступил к их портированию в Unity, продолжив тратить часть времени на доработку и создание новых.
В связи с этим, возникли следующие вопросы: каким образом импортировать, хранить и генерировать уровни в Unity из xml файла?
Найденных вариантов решения было три:
1. При старте игры вычитывать xml файл и каждый раз динамически создавать уровни на runtime.
2. В edit mode сгенерировать уровни и создать на каждый по сцене.
3. В edit mode сгенерировать уровни и создать для каждого префаб.
Очевидно, что первый вариант не самый лучший, т.к. все уровни заранее подготовлены и нету смысла их каждый раз заново создавать. Второй вариант больше подходит для более сложных и масштабных проектов, где каждый уровень имеет свою логику, интерфейс, структуру и т.п. В моем случае пришлось бы дублировать интерфейсы и ключевые объекты в каждую сцену с уровнем и при каждом изменении ui нужно было бы обновлять все сцены. Остается последний третий вариант, который как раз очень удачно подошел. О его реализации я и продолжу повествование.
Для работы с объектами в edit mode добавим кастомную панель в редакторе Unity. Для этого создаем класс наследуемый от EditorWindow в папке Assets/Editor и добавляем туда следующий метод:
[MenuItem ("Window/Level Loader")] // Level Loader - название панели в списке Window.
public static void ShowWindow () {
EditorWindow.GetWindow(typeof(LevelLoader)); // LevelLoader - имя созданного класса
}
Сразу же проверим, что панель создана в Window → Level Loader:
Далее, в методе OnGUI можно начинать добавлять кнопки и поля для нашего окна.
Базовые примеры:
void OnGUI() {
GUILayout.Label ("Custom Label", EditorStyles.boldLabel); // добавление заголовка
// создание поля для выбора GameObject
GameObject customGO = EditorGUILayout.ObjectField(customGO, typeof(GameObject), true) as GameObject;
int customInt = EditorGUILayout.IntField(customInt); // создание поля для ввода int значения
EditorGUILayout.Space(); // добавление вертикального отступа
if (GUILayout.Button("Custom Button")) // добавление кнопки с обработчиком нажатия
{
ButtonHandler();
}
}
Больше информации по компонентам можно найти в официальной документации. А я продолжу описание моего Level Loader«a, продемонстрировав принцип работы ниже:
Сперва, мы вычитываем уровни из xml файла, путем нажатия на Read Levels, после этого создается выпадающий список с возможностью выбора уровня и появляются дополнительные контролы, которые позволяют сгенерировать уровень на сцене, создать префаб выбранного уровня, пересоздать префабы всех уровней, показать/скрыть номера полей (для тестирования отрисовки и отслеживания ошибок).
Для создания объектов на сцене в edit mode используется стандартная функция Instantiate, а для удаления DestroyImmediate.
Какое-то время я создавал префабы уровней вручную, перетягивая их со сцены в папку Resources. Однако, это быстро мне надоело и я полез в интернет за информацией о том, как создавать префабы в edit mode программными средствами. Ниже конструкция, позволяющая это сделать:
private void CreateLevelPrefab() {
GameObject levelGO = GameObject.FindGameObjectWithTag("Level").gameObject;
// игровой объект Level содержит сгенерированный на сцене уровень
Object levelPrefab = EditorUtility.CreateEmptyPrefab("Assets/Resources/"+levelGO.name+".prefab");
EditorUtility.ReplacePrefab(levelGO, levelPrefab, ReplacePrefabOptions.ConnectToPrefab);
}
Далее, в режиме игры уровни добавляются на сцену следующим образом:
GameObject levelGO = Instantiate (Resources.Load ("Level"+levelNum) as GameObject);
Так, этапы добавления уровней получились следующие:
- Создание/редактирование уровня во flash-редакторе с последующим экспортом в xml
- Считывание xml уровня в unity
- Генерация уровня на сцене в edit mode
- Создание/обновление префаба уровня в папке Resources
На этом всё. Для меня это был первый опыт работы с объектами в режиме редактирования. Буду рад ознакомиться с вашими идеями по поводу реализации редактора уровней прямо в Unity, миновав Flash.
Спасибо за внимание! Оценить игру можно в Google Play по запросу NeoAngle.