Программист-рукожоп #3. О танках и разработке
Недавно обещал, что буду вести записи о том как идет разработка танков, поэтому прикладываю видео с последней записью дневника разработки. Так как видео уже не свежее, хоть и последнее - я расскажу о том как собственно я разрабатываю игру.
Выбор движка
Как вы уже знаете по предыдущему посту, мне всегда хотелось создать свой собственный движок, но дело было не в том что он "мой", а скорее в том что мне так было проще, чем разбираться в чужих API и функциях. Однако я все таки сделал для себя выбор в пользу Unity3D после того как попробовал в нем работать. Почему? Все просто - с ним быстрее.
Как выяснилось, сам unity довольно плохо оптимизирован и ИМХО, для разработки на пк подходит разве что под небольшие проекты, для крупных больше подойдет UE4 или подобные движки под игры ААА класса, так как в отличии от того же unity они разрабатывались и затачивались непосредственно "в бою". Однако unity хорошо подходит для быстрой разработки/прототипирования, особенно для мобильных платформ.
( еще один эксперимент времен выхода 2D физики в unity3d, тестировал на android )
Танки
Игра одиночная, это рамки. Если пытаться сразу сделать мультиплеер, то скорее всего уйду в дебри разработки далеко и надолго, и возможно растеряю весь энтузиазм по пути. Поэтому, даже если мультиплеер и возможен - то только после одиночной игры и полного ее релиза с несколькими обновлениями.
Механику покатушек по плоскости и простой стрельбы я освоил уже давно, все движение заключается в прибавлении координат через Rigidbody на объекте "танк", то же работает и для поворота. Почему через стандартную функцию? - так корректно работает физика, не писать же собственную для определения столкновений. Минусом простого подхода является отсутствие вертикального геймплея, но тут он нам и не нужен.
Стрельба в отличии от эксперимента rover не должна содержать в себе реально летающие снаряды - оптимизация. Вместо этого стоит использовать просто трассировку лучами или же Raycast, так же из стандартной физики unity, а при выстреле создавать в точке пересечения объектов лучом - взрыв, попутно определяя попали ли мы в объект-противник и отнимая ему здоровье.
Сцены в проект организованы просто:
1. Сцена с главным меню и набором всех окон UI которые вообще встречаются в игре, и основными скриптами-контроллерами
2. Сцена с игрой
Почему я размещаю все "окна" в одной сцене? Мне так проще. Окна из себя представляют просто области во весь экран со своим компонентом CanvasGroup, находящиеся в одном объекте Canvas, на самом объекте висит скрипт-контроллер который переключает видимость у этих объектов и их содержимого, а так же в нем описаны методы на которые ссылаются все кнопки из окон. Контроллер интерфейса является синглтоном, т.е единственным экземпляром класса и не разрушается при переходе между сценами. Вообще все основные контроллеры я пишу в виде синглтонов, так проще организовать общение между ними (как же мне не хватало знания о синглтонах в той экспериментальной онлайн игре)
До контроллера карты еще не дошел, но в планах сделать примерно так:
Сцена для игры одна, поэтому карту делаю в виде одного префаба, который будет загружаться на выбор, в зависимости от того какой уровень выбран. В этот же префаб карты можно закинуть сразу и начальные расположения врагов и точки их спавна и даже наборы скриптов.
Враги. Дабы хоть немного усложнить себе жизнь разнообразить их действия для врагов будет несколько способов спавна - заранее расставлять врагов на карте или спавнить их по таймеру в определенных координатах. Механики получается всего две: патруль и преследование. Действий при этом больше: "стоит", "поворачивает", "движется", "стреляет" и конечно "умирает"
Сейчас я уже закончил следование за целевой точкой и что то вроде патрулирования, еще нужно приписать ко всему этому поиск путей.. и выйдет неплохое преследование, так необходимое например, для организации волн надвигающихся врагов.
Оптимизация
Unity, как я выяснил набивая шишки - очень капризный движок в плане оптимизации. Чтобы все работало без тормозов есть несколько советов:
1. Объединение мешей ("батчинг") происходит только при масштабе 1 и только при одинаковых материалах. Объединение позволяет сократить число вызовов отрисовки (Drawcalls или же DC).
2. Unity редиска не объединяет меши корректно, поэтому число DC может оставаться высоким - к этому рекомендую объединять их самому на уровне моделирования в 3d редакторе.
3. Луче всего использовать "атласы" текстур (несколько текстур в одном файле) вместо единичных раскиданных по разным файлам и хорошенько сжимать их.
4. По возможности не использовать в коде поиск по строкам, это довольно медленная штука
5. Вместо воссоздания объектов (вроде пуль, для каждого выстрела) лучше использовать "пул" объектов - массив с предзагруженными объектами
6. Парсинг текста вообще штука в Unity крайне медленная, особенно на андроиде (поэтому подобные операции лучше оставлять на одноразовые события)
7. Для простых типов, например единичного вектора, лучше всего создать константу, вместо использования "Vector3.up" каждый раз когда она понадобиться
Касательно числа вызовов - совсем недавно узнал что лучшим вариантом будет держать их в пределе 30, максимум до 60 drawcalls для мобильных устройств.
Что дальше?
Кроме кода спланировал 2 обучающие и 12 основных миссий в 3 локациях. Поэтому пора начинать готовить собственно трехмерный контент - сами уровни и их наполнение, а так же звуки и эффекты.
Целевая аудитория вроде понятна, стилистику буду стараться сохранять. Нужно продолжать.
Бонус от эксперимента в GooglePlay
Если любопытно, вот ссылка на то прощупывание почвы в GooglePlay, оговорюсь что оригинальная идея была не моя и подобная игра была на PC:
GooglePlay: https://play.google.com/store/apps/details?id=com.galzuris.poord
Увидимся в следующем посте =)