В этой серии постов я расскажу историю разработки нашей онлайн стратегии непрямого контроля, которая выходит на Windows, Mac, Linux, IOS, Android. Для начала поясню, что такое стратегия непрямого контроля. Это поджанр стратегий, в котором игрок обустраивает базу, создает юнитов и зарабатывает ресурсы, но при этом боевая составляющая почти никак не зависит от действий игрока.
В этой части я расскажу о создании первого прототипа и последующего перехода разработки к Unity3D.
Первый прототип
Первые задумки игры появились в 2012 году. Основу всей концепции игры составляли карты, с помощью которых игрок мог вызвать на сцену (Поле боя) сказочных персонажей или использовать заклинания для достижения главной цели — уничтожить базу другого игрока или искусственного интеллекта. От того, что все происходит на сцене и происходит название Heroes Of Scene. Все карты уникальны по своим характеристикам и способностям, чтобы игрок мог создавать свою уникальную тактику для ведения боя. Игрок может строить здания для получения того или иного ресурса или улучшения своих войск и построек. Каждую карту с героями можно прокачать ровно как и карту с заклинаниями. Задумывалось сразу сделать игровой бизнес-моделью F2P, чтобы не ограничивать игроков никакими подписками и чем-либо еще.
Но вот реализовать все, что было задумано одному человеку достаточно сложно, потому нашему гейм-дизайнеру (Основатель проекта и 3D моделлер по совместительству) пришлось сделать на основе 3D редактора Blender прототип игры, для привлечения людей в проект на долевой основе, так как финансирование отсутствует. На его создание ушло приличное количество времени, но результат стоил всех затраченных сил. Весь код и ресурсы представляли собой дикую кашу, но готовая pre-alpha работал достаточно хорошо и отражал основную суть игры хоть и без многих фишек, которые есть теперь.
Первый прототип:
Показав прототип некоторому количеству людей, стало понятно, что концепция и геймплей греют душу людям. Было принято решение собрать небольшую команду людей для создания полностью рабочей версии игры. Разработка на игровой составляющей Blender была прекращена по многим причинам: очень медленный запуск, нестабильная работа приложения и отсутствие компиляции под необходимые платформы.
Но что же выбрать из такого многообразия сред разработки?
Рассматривались многие варианты, но стоит учесть, что на тот момент не было Unreal Engine 4, CryEngine 3 не имел такую лояльную к разработчикам ценовую политику, а был тогда 1 квартал 2013 года. Большинство движков было отметено по причине отсутствия некоторых необходимых платформ, а большинство остальных по другим причинам. Выбор пал на Unity3D.
Почему же Unity3D?
Тут множество причин. В тот момент Unity3D уже имел огромное сообщество разработчиков, хорошую документацию и приличную графику. Была ровно как и есть версия Free, в которой хоть и есть ограничения, но не ограничивающие разработчиков во многих аспектах разработки (Так считалось). Самое же главное это обилие платформ, под которые могла вестись разработка проекта. Это позволяло не тратить время на перенос игры с одной платформы на другую. Оптимизация так же радовала душу, словом, все было прекрасно.
Новое ядро игры
Пришло время искать людей, и были созданы топики на достаточно известных тематических сайтах. В августе 2013 был найден разработчик клиентской части, и после небольшого разговора начал создаваться уже новый прототип на Unity3D. С этого момента началась интенсивная разработка нового клиента.
Для начала было создано простое меню на стандартном GUI движка, но не все, Scroll для карт был сделан на простых 3D объектах по причине того, что это быстро реализовывалось. И вот с интерфейсом пользователя была допущена первая ошибка. GUI Unity на тот момент ровно как и сейчас, до выхода нового редактора пользовательского интерфейса, работал очень медленно и не удовлетворял наши требования. Так как этот аспект мы все равно решили переработать в будущем, мы оставили все как есть до момента переделки интерфейса. Хранение данных о персонажах и цене карт пока было отдано на попечение клиента.
С боевой частью не было особых проблем потому что игрок лишь вызывает героев, использует заклинания и строит базу. Первая сырая версия с новым сердцем была готова, примерно за неделю мы довели игру до приличного состояния в плане багов. Но игра чувствовалась очень плохо без правильной музыки и звукового оформления.
Людей отвечающих за звук мы искали приличное количество времени, но хороших ребят мы все таки нашли. Первый пробный трек был написан достаточно быстро и радовал слух, но работа по звуковому оформлению предстояла колоссальная. Параллельно этому мы начали поиск художника по текстурам, но тут все получилось не так быстро, как мы думали. Многие люди покидали нас, ничего не сделав, а у других просто не хватало времени. Но наконец-то был найден художник по текстурам и по совместительству UI — дизайнер. С этого момента игра в художественном плане заиграла новыми красками, но полное преображение игры произошло гораздо позже. После этого мы полностью сконцентрировались на дальнейшей разработке следующего билда. Пока готовился звук мы перешли к созданию другого важного аспекта — построек.
Прототип с новым сердцем:
Постройки удалось реализовать достаточно быстро, кроме кузницы по причине достаточно большого функционала. В ней игрок может улучшать свои постройки и карты в текущем бою. И тут встал вопрос, как информировать об улучшении чего-либо, не рассылая сообщения каждому объекту (Сначала был выбран этот плебейский вариант)? Решение было найдено и заключалось оно в использовании статических переменных, которым доступ был обеспечен через свойства.
public class Forge : MonoBehaviour
{
static int levelUpgrade;
public static Level
{
get{return levelUpgrade;}
set{levelUpgrade = value;}
}
}
public class Person : MonoBehaviour
{
int levelUpgrade = 0;
void Start()
{
levelUpgrade = Forge.Level;
}
}
Этот же способ был использован для переноса данных о картах, которые выбрал игрок перед боем. Да и вообще, для всех глобальных переменных или данных, которые вы хотите перенести с одного уровня на другой лучше использовать статические переменные с доступом к ним через свойства, при переходе с уровня на уровень эти данные не уничтожаются.
Так же в определенный момент мы определили, что функция CompareTag работает в 2 раза быстрее простой сверки тэгов.
public class Empty : MonoBehaviour
{
void Start()
{
if(tag == "1")
Debug.Log("1");
if(CompareTag("1")) //Работает в 2 раза быстрее предыдущей конструкции
Debug.Log("1");
}
}
В это же время был реализован арбалет с простейшей механикой выстрела основанной на пересечении с коллайдерами. Понемногу все готовые части дорабатывались и улучшались, правились незначительные баги и оплошности в геймплее.
Мы пытались ускорить игру всеми способами потому, что игра ориентирована не только на PC, но и на мобильные платформы. Почти все объекты инициализировались во время старта уровня, чтобы снизить нагрузку в последующих моментах. Большинство карт были связаны одним общим классом и дабы для каждого не нужно было загружать отдельные объекты интерфейса или логики использовались статические переменные. Было реализовано повторное использование уже созданных объектов, что дало значительный прирост в производительности.
Меню было значительно доработано и улучшено, но тут и появилась главная проблема всего стандартного GUI. Под разные соотношения экранов автоматически ничего не подгонялось и пришлось это решать быстрым и глупым способом. Позиция и ширина вычислялась в зависимости от размеров экрана, а не его соотношения то есть:
public class Empty : MonoBehaviour
{
void OnGUI()
{
GUI.Box(new Rect(Screen.width / 10, Screen.heigth / 10, Screen.width / 15, Screen.heigth / 12),"Heroes Of Scene");
}
}
Полное отсутствие GUI элементов, как объектов в коде полностью уничтожало какое-либо внятное использование этого встроенного чуда. Мы решили, что когда будет перерабатываться интерфейс проект перейдет на достаточно известную UI систему NGUI, но о том, как мы интегрировали новый интерфейс я расскажу позже.
Наступила пора делать серверную часть и интегрировать с ней клиент, но об этом в следующей части.
Заключение:
Не используйте стандартный UI Unity, а лучше используйте сторонние системы. (Не считая абсолютного новой системы интерфейса, которая будет в новой версии этого движка). Для глобальных данных лучше использовать статические переменные с доступом через свойства. Использовать CompareTag для сравнения тегов вместо операции ==. Инициализировать как можно большее количество объектов при старте уровня, а не вовремя игры. Повторно использовать уже существующие объекты на сцене, а не создавать новые. Если у вас много объектов, объединенных примерно одной и той же логикой, создайте для них общий класс и пользуйтесь наследованием.
Автор: OnionFan