Целевая аудитория: начинающие инди-разработчики игр.

Введение




В основном это список приемов и бесплатных инструментов, которые я использовал при создании мобильного endless runner’а Good Cat Gone Bad, который выйдет в Google Play 4 мая 2016 г.

Игра разрабатывалась как проект-хобби, используя Unity 5, и заняло все это дело около 4 месяцев на постоянной основе (полный рабочий день).

Дизайн


После того, как я определился с этой сумасшедшей идеей, я начал набрасывать список компонентов приложения и описывать их с помощью коротких тезисов. Например:

Компоненты:

  • game over меню
  • уровень
  • зона уровня (трасса, парк, жилой район)
  • игрок
  • коп
  • очки
  • здоровье

Game over меню:

  • показывается при смерти игрока
  • пункт Играть Заново
  • пункт Воскресить
  • пункт Выйти

Уровень:

  • может быть пройден
  • чтобы пройти, нужно набрать X очков
  • чем больше уровень, тем больше требуется очков
  • генерируется процедурно
  • вид напоминает столбец
  • состоит из бесконечного списка зон

Игрок:

  • гигантский кот
  • идет всегда вперед
  • может смещаться влево, вправо
  • уничтожает все на своем пути
  • имеет здоровье
  • имеет очки

Коп:

  • стоит на месте
  • стреляет в игрока
  • дает очки при смерти

Я использую Google Keep для хранения этих записей и прочей ерунды.

В целом, вы видели большую часть документа с начальным дизайном. Этого было достаточно для того, чтобы начать разработку. Позже я улучшил дизайн, используя такие штуки, как Core Loop, Subversion, Bartle Test.

Архитектура


Проект состоит из модулей. Модуль — это набор компонентов (логика) и asset’ов (текстуры, звуки и т.д.), относящихся к какой-то фиче или к части инфраструктуры.

Assets/Src/Catzilla
+-- AppModule
+-- CommonModule
+-- GameOverMenuModule
+-- LevelAreaModule
+-- LevelModule
+-- LevelObjectModule
+-- MainMenuModule
+-- MarketingModule
+-- PlayerModule
L-- SkillModule

Компоненты и asset’ы внутри модуля структурированы по типу.

Assets/Src/Catzilla/LevelObjectModule
+-- Animation
+-- Config
+-- Controller
+-- Materials
+-- Mesh
+-- Model
+-- Prefab
+-- Sound
+-- Texture
L-- View

У каждого модуля (кроме модулей, состоящих сугубо из asset’ов, например Marketing) есть компонент, отвечающий за инициализацию модуля (регистрация сервисов, конфигурационных значений, обработчиков событий и т.д.).

В качестве точки входа в приложение выступает специальный модуль (App). В нем регистрируются и инициализируются остальные модули.

Все это дело основано на библиотеке Zenject, которая, помимо этого, предоставляет гибкое внедрение зависимостей.

Архитектура проекта основуется на событийном подходе. В моем случае это означает, что ключевые компоненты ничего не знают друг о друге и пораждают события, которые обрабатываются посредниками, отвечающими за взаимодействие компонентов.

Графика


На протяжении уровня, в каждом кадре < 5 тыс. вершин и < 20 вызовов отрисовки (draw call).

Все эти хипстерские модели я делал в Blender. Каждая модель содержит < 200 треугольников. Большинство моделей состоят из отдельных частей (например, ноги, руки, голова, тело), чтобы их можно было разрушить.


Коп. Куча кубиков.


Начало трассы. Обычная плоскость.


Некоторые люди не верят, что это Impala 64.


А некоторые думают, что эта пальма не с Майами.

Текстурирование было сделано с помощью техники Hyden’а, и текстуры всех обьектов уровня были объединены в одну большую (256х256) текстуру, в качестве оптимизации.


Объединенная текстура всех обьектов уровня.

Для зон уровня (например, парк, трасса) я использовал материал с шейдером Mobile / Unlit (Supports Lightmap), а для обьектов уровня — шейдер Mobile / VertexLit (Only Directional Lights).

В игре только 1 направленный (directional) источник света и нет теней.

Эталонное разрешение (reference resolution) компонента Canvas Scaler = 480x800, что покрывает большую часть устройств. Кстати, кто-нибудь знает о существовании этой страницы?

Цветовая палитра игры была сгенерирована в Paletton.

Для текста я использовал шрифт Press Start 2P, который можно найти в Google Fonts.

Для плавающего текста (например, очки над обьектом) я использовал Text Mesh, вместо UI Text в режиме world space, в качестве оптимизации.

Иконки для UI (например, здоровье, умения) были позаимствованы у пакета 64 Flat Game Icons.

Анимация


Анимация была сделана в Unity (Mecanim). Всего 3 типа обьектов уровня анимированы: игрок, гражданский и бонус (например, вращающаяся штука, похожая на доллар).


Бегущий гражданский. 5 кадров.

Аудио


Звуки были сгенерированы в Sfxr, мне показалось, что у него это получается лучше, чем у Bfxr.

Компоненты Audio Source используют 2D режим (spatial blend = 0). У каждого обьекта уровня свой Audio Source, кроме игрока, у которого их 2, для большего числа одновременных звуков. Но для UI всего 1 общий Audio Source.

Звуки проигрываются через специальный компонент — аудио менеджер, который следит за тем, чтобы одновременно не проигрывалось много звуков, а также склеивает (на самом деле отбрасывает) идентичные звуки, если они проигрываются в течение очень короткого интервала времени, чтобы амплитуда не зашкаливала в выходном аудиосигнале.

Материалы для маркетинга


Иконка. Настоящий шедевр. Была сделана отдельной сценой в Unity, путем размещения одной из зон уровня и игрока, и подогнав камеру.


Вы уже догадались что это. Иконка.

Я использовал Icon Slayer для того, чтобы добавить к ней крутых эффектов (скругленные уголки) и получить нужные размеры.

Следующий кусок… всмысле шедевр — это Feature Graphic (баннер, промо, не важно), которая сделана тем же способом, как отдельная сцена.


Может, мне стоит снимать блокбастеры, вместо всего этого?

Трейлер был сделан в iMovie, используя один из его шаблонов — Блокбастер.


Уверен, Стивен Спилберг поставил бы ему палец вверх.

Веб-сайт


Frontend сайта сделан с помощью Boostrap 3. Серверной логики на backend’е нет, просто HTTP сервер Nginx. Расположено все это дело на DigitalOcean. Для развертывания я использовал Vagrant.

Разное


На проекте используется пакет Smart Localization (вы уже догадались для чего).

Для контроля версий я использовал Git. Исходный код хранится в Bitbucket.

Комментарии (24)


  1. Leopotam
    27.04.2016 17:14
    +2

    Спасибо за хорошее настроение, давно так не смеялся, до слез просто.


  1. inborn_killer
    27.04.2016 20:57
    +3

    Вспомнилось, как я в прошлом году участвовал в Ludum Dare.
    image
    Если научитесь делать свою игру за 48 часов вместо 4 месяцев, то трешачок оценят особые любители )))


  1. FrozmatGames
    27.04.2016 21:09
    +1

    На протяжении уровня, в каждом кадре < 5 тыс. вершин

    Как можно 5000 вертексов наплодить в кадре с такой графикой?
    «Коп» состоит из 6 кубиков, 6х8 = 48 вертексов максимум. Откуда там 200?)


    1. HeadZerg
      27.04.2016 22:58

      «Коп» состоит из 11 кубиков, так как из-за особенностей текстурирования для каждого цвета нужна отдельная геометрия. Из-за плоского затенения (не знаю как правильно перевести flat shading) полигоны не делят между собой вершины, поэтому в кубе 6*4 вершин. 10 полигонов мы никогда не сможем увидеть, поэтому их можно удалить. В сумме получается (11*6 — 10)*4 = 224 вершины. 10 таких человечков плюс остальные объекты плюс интерфейс вполне может к 5000 вершин подобраться.


      1. shell100500
        27.04.2016 23:08

        На самом деле у копа там не так все печально и кубиков все-таки 6, а вершин 84.

        5к это скорей порядок, чем реальное значение. В основном, в кадре до 2-3к вершин.


        1. Leopotam
          28.04.2016 00:34

          А зачем вообще было использовать текстуры, почему не задействовать цвета вершин? Тем более в блендере можно мазать их прямо кисточкой.


          1. shell100500
            28.04.2016 00:43

            Увы я не знаком с данным приемом, не могли бы вы подсказать где об этом можно почитать? Это поддерживается unity? Также мне нужна возможность менять цвета объектов (например, одна машина красная, другая розовая), как быть в этом случае?


            1. Leopotam
              28.04.2016 00:57

              В блендере VertexPaint и красить любым цветом, потом экспортировать в fbx и в юнити. В юнити не помню стандартных шейдеров, умеющих показывать цвет из вертексов, но шейдер получается довольно простой (без поддержки освещения, это уже нужно прикручивать самостоятельно):

              Shader "Custom/UnlitVertexColor" {
                  Properties {
                  }
                  SubShader {
                      Tags { "RenderType" = "Opaque" }
                      LOD 100
                      Pass {
                          Tags { "LightMode" = "ForwardBase" }
                          CGPROGRAM
                          #include "UnityCG.cginc"
                          #pragma vertex vert
                          #pragma fragment frag
                          #pragma fragmentoption ARB_precision_hint_fastest
              
                          struct v2f {
                              float4 pos : SV_POSITION;
                              fixed4 color : TEXCOORD0;
                          };
              
                          v2f vert (appdata_full v) {
                              v2f o;
                              o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                              o.color = v.color;
                              return o;
                          }
                          	
                          fixed4 frag (v2f i) : SV_Target {
                              return i.color;
                          }
                          ENDCG
                      }
                  }
                  Fallback Off
              }
              


              нужна возможность менять цвета объектов

              Сделать несколько префабов с разными мешами — они будут сбатчены в 1дк при использовании одного материала (цвета будут зашиты в вертексы).


              1. shell100500
                28.04.2016 01:21

                Сделать несколько префабов с разными мешами

                Если я правильно понял, это означает что на каждую вариацию цвета будет отдельная модель (блендер файл)? Но в таком случае это тяжелей поддерживать (например, саму геометрию модели нужно будет менять в нескольких файлах).


                1. Leopotam
                  28.04.2016 01:28

                  Это значит, что будет N-файлов машинок, из которых наделать несколько префабов и спаунить уже из списка.менять цвет через renderer.material — нельзя в принципе, как и вообще трогать renderer.material — это приводит к дублированию материала и разрыву батчинга.

                  это тяжелей поддерживать

                  Это легко поддерживать, мешей машинок думаю будет не более десятка. Погуглить как работать с инстанцированием префабов из Resources + как сделать pooling объектов. Как вариант, посмотреть здесь и здесь.


                  1. manto
                    28.04.2016 12:39

                    — Таки можно использовать Renderer.sharedMaterial вместо Renderer.material.
                    — Можно и без использования окрашивания вершин обойтись, есть Renderer.material.SetColor (хотя изменяет цвет у всех 3D моделей, которым назначен данный материал).
                    — Но само текстурирование в стиле Hyden интересно тем, что uv-развертку можно ужать до минимума, уложив, например, в 32x32 пикселя и менее, а значит можно создать атлас текстур, и используя offset и tiling уместить в текстуру 512x512, получив аж 256 вариантов раскраски, как минимум, одного персонажа. В идеале одного такого атласа с набором большого количества цветов хватит на всю игру, при должном расположении островов uv-развертки различных моделей.


                    1. Leopotam
                      28.04.2016 13:42

                      — Таки можно использовать Renderer.sharedMaterial вместо Renderer.material.
                      — Можно и без использования окрашивания вершин обойтись, есть Renderer.material.SetColor (хотя изменяет цвет у всех 3D моделей, которым назначен данный материал).

                      Левой пишу, правой зачеркиваю — противоречащие абзацы. Топикстартеру нужна кастомизация отдельных инстансов, а не всех разом. Если потрогать material хотя бы раз — он скопируется из sharedMaterial и станет новым, те выпадет из батча. Это к сожалению неуправляемо и трогать это свойство крайне не рекомендуется.

                      Но само текстурирование в стиле Hyden интересно тем, что uv-развертку можно ужать до минимума

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


        1. HeadZerg
          28.04.2016 08:39

          Скорее всего, 84 вершины — это то, что показывает blender. После экспорта их, почти всегда, будет больше. Например, для куба с жесткими гранями blender показывает 8 вершин, а unity — 24.


          1. shell100500
            28.04.2016 10:20

            Да вы правы, unity показывает 240 вершин.


      1. FrozmatGames
        27.04.2016 23:39

        Из-за плоского затенения полигоны не делят между собой вершины

        Откуда вы такое взяли?) В статье написано:
        В игре только 1 направленный (directional) источник света и нет теней.

        Это обычный свет и стандартные шейдеры. Геометрию на полигоны они не разбивают.


        1. Leopotam
          28.04.2016 00:59

          Имелось ввиду — вертексы продублированы из-за необходимости получить острые ребра между гранями (по-разному направленные нормали вертексов).


  1. Nikon_NLG
    27.04.2016 22:40

    Сразу вспомнился небезызвестный гном
    Но для первого проекта достаточно забавно. Надо будет скачать, оценить удобство управления :)


  1. BIanF
    28.04.2016 03:53

    А что насчёт реплея геймплея?


    1. shell100500
      28.04.2016 10:49

      Увы на данный момент его нет, если вы имеете в виду replayability. Один из вариантов — ввести новых персонажей с уникальным поведением.


      1. BIanF
        28.04.2016 12:40

        Я про кнопочку «повторить последние 10 секунд игры»


        1. shell100500
          28.04.2016 12:51

          Простите, я не понял о чем идет речь. Вы предлагаете добавить возможность просматривать / расшаривать последние 10 сек игры? На данный момент есть возможность расшаривать видео после прохождения уровня, также предварительно редактировать его (можно оставить только последние 10 сек).


          1. BIanF
            28.04.2016 12:52

            Ну вот я и спрашиваю, как вы это сделали =)


            1. shell100500
              28.04.2016 12:54

              Это не мой велосипед, это я интегрировал один из сервисов unity — Everyplay.


  1. Kirpa
    05.05.2016 18:52

    Только сейчас почему-то прочитал статью. Релиз уже свершился? Спасибо за интересное чтение и полезные ссылки.