Dawnkeeper: разработка, продвижение, итоги

в 14:22, , рубрики: Без рубрики

Dawnkeeper: разработка, продвижение, итоги

Совсем недавно мы опубликовали Dawnkeeper: Last Survivors — игру для мобильных платформ iOS/Android. За несколько месяцев разработки накопился некоторый технический опыт игростроя, которым хотелось бы поделиться.

Графика

Пока мы только смотрим в сторону 3D разработки. На данный момент создание качественных 3d-моделей дело не легкое и не дешевое. К тому же, трехмерная графика создает определенные трудности с производительностью. Поэтому решили использовать старый добрый 2d жанр.
В нашей игре мы использовали скелетную анимацию. Попробовали несколько продуктов и остановились на Spine. На хабре уже есть пост знакомства с данным инструментом. Использовали Pro версию, так как только там доступны такие вкусности как:

  • Meshes – позволяют указать области внутри изображения, что улучшает fill rate, благодаря тому, что не прорисовывается прозрачная область вне указанных областях.
    Dawnkeeper: разработка, продвижение, итоги
  • Skinning – позволяет переключаться между разными наборами изображений, прикрепленных к определенным bones в анимации. Мы использовали скины для разного внешнего состояния врагов (здоровый, раненый, почти убитый…) а также для различной экипировки. То есть, у нас один проект, одна анимация ходьбы, например, а «обвесы» переключаются с помощью скинов. Именно этот пункт мотивировал нас приобрести pro лицензию.
    Dawnkeeper: разработка, продвижение, итоги
  • Free-Form Deformation – позволяет с помощью mesh деформировать изображения. Причем деформацию можно использовать в анимации, что позволяет сделать игру более живой, а также снимает с художника кучу работы по анимированию какой-нибудь одежды на персонаже. Это также положительно сказывается на общем весе графического материала. Кстати, к моменту выпуска игры не было реализации FFD в run-time библиотеке для Cocos2-dx. Мы тогда связались с авторами spine, хотели узнать примерные сроки реализации. Но все складывалось печально, так как там небольшое количество разрабов пытаются поддержать интеграцию spine c несколькими игровыми движками. Зато, они поделились ссылкой на кастомную реализацию FFD для cocos2d. Эта реализация где-то на 80% подходит для cocos2d-x, остальную часть пришлось за пару дней переписывать на плюсы. Благо у нас есть одаренный плюсовик, который не страшится решать технические сложности. Ниже представлены анимации, которые помогут по достоинству оценить данную фичу.
    Dawnkeeper: разработка, продвижение, итогиDawnkeeper: разработка, продвижение, итоги

В общем, сложилось приятное впечатление после работы со Spine, авторы которого постоянно добавляют новые фишки. Единственные претензии только к скорости обновлений, так как они анонсируют очень «вкусную» фичу, но не особо спешат с ее реализацией.

Платформа iOS

В процессе разработки мы использовали CocosBuilder, но так как он уже давно не поддерживается и практически отсутствуют новые комиты, то постоянно всплывали различные старые баги и приходилось много чего исправлять, что являлось довольно существенной помехой. Стоит еще обратить внимание на SpriteBuilder, на который идет редирект с сайта cocosbuilder-a. Возможно данный форк cocosbuildera будет лучше поддерживаться и обрастать функционалом, кстати, у него отсекли возможность работы с js. Также, разработчики заявляют, что, по сравнению со своим прародителем, у spritebuilder-а улучшена работа с ресурсами, добавлен редактор для локализаций, также прокачено общее юзабилити. К сожалению, опыта работы с ним у нас еще не нет, но будет чертовски круто, если кто-то поделится своими впечатлениями в коментах. В нашем следующем проекте мы практически наверняка откажемся от cocosbuilder-a и будем смотреть в сторону альтернатив, например CocoStudio, хотя ее еще нет для Mac :(
Также стоит отметить работу с PVR графикой — для ios этот формат позволил сэкономить немного занимаемой памяти. Визуально потери качества не заметно. Для наглядности, можно взглянуть на таблицу сравнения занимаемой текстурой памяти в КБ:

Формат 1024х1024 2048х2048
PVRTC4 512 2048
PVRTC2 256 1048
RGBA 32 bit 4096 16384
RGBA 16 bit 2048 8192

Для большинства наших текстур качество в PVRTC4 выходило лучше, чем в RGBA4444, немного хуже чем в RGBA8888, но сравнимо. Не все текстуры достаточно хорошо выглядят в PVR формате. Android устройства поддерживают следующие форматы сжатия ETC1, PVRTC, ATITC, S3TC — но как обычно, одни девайсы поддерживают один формат, другие — другой. Кстати, может и для android придумали кое-какие костыли, надо будет пробежаться по поиску.
Для для девайсов с различными экранами нужно предусмотреть определенный механизм позиционирования игровой сцены.
В cocos'e при разработке используются свои единицы измерения, задаваемые разработчиком — designResolutionSize. В нашем случае мы выставили размер по умолчанию 1024х768 (под ipad), и определили что ширина может варьироваться в зависимости от соотношения сторон девайсов (FIXED_HEIGHT). Таким образом, на «длинных» девайсах мы могли получить размер 1400х768. Также при дизайне интерфейсов в CocosBuilder'е есть возможность позиционировать элементы относительно различных углов (отступ от правого края 100, сверху 50). Подробнее можно почитать здесь.

Платформа Android

Здесь у нас были трудности с сохранение данных. Проблема оказалась в том, что если производилась попытка сохранять данные в несуществующем дереве директорий, эти самые директории не создавались автоматически, поэтому пришлось добавить соответствующую проверку. На просторах stackoverflow было найдено замечательное обсуждение, решавшее нашу проблему.
Далее нам нужно было решить проблему с размером apk файла. Google настоятельно рекомендует использовать файлы дополнений obb. К сожалению, у нас возникли трудности с чтением zip-данных c cocos2d-x, а поэтому решили пойти путем multiple apk. То есть обычное разделение графики в зависимости от устройства. В этом случае используем три набора графики medium, large и xlarge. А в манифесте прописываем определенные <compatible-screens> параметры:

AndroidManifest.xml
<!-- medium -->
    <!--
    <compatible-screens>
        <screen android:screenSize="small" android:screenDensity="ldpi" />
        <screen android:screenSize="small" android:screenDensity="mdpi" />
        <screen android:screenSize="small" android:screenDensity="hdpi" />
        <screen android:screenSize="small" android:screenDensity="xhdpi" />
        <screen android:screenSize="small" android:screenDensity="213" />
        <screen android:screenSize="normal" android:screenDensity="ldpi" />
        <screen android:screenSize="normal" android:screenDensity="mdpi" />
        <screen android:screenSize="normal" android:screenDensity="hdpi" />
    </compatible-screens>
    -->

<!-- large -->
    <compatible-screens>
        <screen android:screenSize="normal" android:screenDensity="xhdpi" />
        <screen android:screenSize="normal" android:screenDensity="213" />
        <screen android:screenSize="large" android:screenDensity="ldpi" />
        <screen android:screenSize="large" android:screenDensity="mdpi" />
        <screen android:screenSize="large" android:screenDensity="hdpi" />
        <screen android:screenSize="large" android:screenDensity="213" />
        <screen android:screenSize="xlarge" android:screenDensity="ldpi" />
        <screen android:screenSize="xlarge" android:screenDensity="mdpi" />
        <screen android:screenSize="xlarge" android:screenDensity="213" />
    </compatible-screens>

<!-- xlarge -->
    <!--
    <compatible-screens>
        <screen android:screenSize="small" android:screenDensity="480" />
        <screen android:screenSize="normal" android:screenDensity="480" />
        <screen android:screenSize="large" android:screenDensity="480" />
        <screen android:screenSize="xlarge" android:screenDensity="480" />
        <screen android:screenSize="large" android:screenDensity="xhdpi" />
        <screen android:screenSize="xlarge" android:screenDensity="hdpi" />
        <screen android:screenSize="xlarge" android:screenDensity="xhdpi" />
    </compatible-screens>

 <!--<meta-data android:name="resources_screen_size" android:value="xlarge"/>-->
        <meta-data android:name="resources_screen_size" android:value="large"/>
        <!--<meta-data android:name="resources_screen_size" android:value="medium"/>-->
    -->

При таком подходе размер apk составил порядка 25, 30 и 40 мегабайт. Немного добавилось мороки с сопровождением нескольких apk, так как нужно следить за versionCode в манифесте. Кстати, в самом начале мы забыли указать такое расширение как tvlarge (код в манифесте 213), например, это nexus 7 первого поколения с разрешением 1280х800. В связи с этим, отсеклось определенное количество планшетов : Google настоятельно рекомендует использовать <supports-screens> вместо <compatible-screens>, но при этом мы имеем менее обширные параметры сортировки устройств.

Продвижение, аналитика

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

Есть несколько вариантов продвижения приложения/игры в App Store или Google Play. Если игра довольно виральная — читай крайне необычная, к примеру, какой-нибудь пиксельарт про крота, который путешествует в космосе и собирает желуди, то продвигать такой проект намного легче — сразу становятся доступны различные ресурсы со смешными картинками/видео и огромными аудиториями, для которых что-то необычное это вполне естественно. Также различные крупные издания могут куда охотней и абсолютно бесплатно написать про ваш продукт, т.к. он явно будет выделяться среди остальных игр, представленных в сторах. Если виральность у игры низкая — остаются два способа. Это продвижение при помощи кросс-промоушена внутри своих приложений + различные статьи на тематических ресурсах и обзоры на популярных порталах или же, если позволяет бюджет — закупка траффика, т.е. установок. В зависимости от категории, в которой нужно продвинуть игру требуется различно количество инсталлов, для категории Образование это одно число — а для Экшен будет уже абсолютно другое.
Поскольку желудей в нашей игре нет — мы выбрали вариант первый вариант. Активное продвижение начали примерно неделю назад, когда игра появилась в обоих сторах. Мы заказали платный обзор на 4pda, который принес примерно 1000 инсталов на android и 200 на iOS. Также заказали еще обзоры на macdigger и appleinsider. Пробовали рекламные посты в группах Vk, которые особого результата не принесли. Попутно использовали кросс-промоушен нашей игры в других приложениях пользуясь House Ads от Admob-а.
Также добавлю, что подходы к продвижению для двух маркетов разнятся. Если для app store нужно организовывать буст скачек в краткосрочный период, в течение приблизительно двух-трех дней, то Google Play требует долгосрочного продвижения, где, помимо количества скачек и оставленных отзывов, немаловажное значение играет еще и retention, то есть удержание пользователей. Результаты продвижения наблюдаем по AppAnnie. Напрягает, что данные с play google приходят с небольшим запозданием.

Об игре

Ну что же, настало время для рекламного булшита краткого обзора игры. Dawnkeeper — это классический Action Defence, в стиле Last Stand. Главный герой, Рейнор Торн, единственный кто уцелел после безжалостного уничтожения своего Ордена Гипериона. Ему предстоит заручившись поддержкой безумного однорукого гнома-подрывника и колдуньи-отступницы, пробиваясь через орды монстров, добраться до предателей, чтобы отомстить и вернуть мир в Империю!
Каждый из трех героев обладает своим уникальным набором умений и манерой игры. Рейнор, к примеру, хорошо владеет арбалетами и различными дисковыми пушками, может внезапно обрушить на противников град стрел или уничтожать их прицельным выстрелом. Гном Торвальд — специалист по осадному искусству, прекрасно бросает тяжелые метательные топоры, которые легко раскалывают ороговевшие панцири монстров. Также он может усыпать все поле сражения множеством смертоносных замедляющих кольев и мин. А для совсем крепких противников у него всегда есть в запасе одна-другая бочка со взрывоопасным порохом. Колдунья Линн предпочитает уничтожать противников группами, насылая на них штормы из молний и обрушивая метеориты.

В процессе прохождения игры будут открываться новые области карты Стирийской Империи и появляться более смертоносные виды врагов (время для Coub-а), но и вместе с тем, закономерно можно будет найти более лучшее оружие и экипировку.
Dawnkeeper: разработка, продвижение, итоги

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

В игре есть и режим «Выживание», где можно попробовать свои силы против бесконечных волн монстров, попробовав набрать как можно больше очков, зайти как можно дальше и подняться на верхние позиции в таблице лидеров.

Dawnkeeper: разработка, продвижение, итогиDawnkeeper: разработка, продвижение, итоги Dawnkeeper: разработка, продвижение, итоги

Также мы на время сделали бесплатным Pro-версию для ios, а на Pro-версию для android поставили минимальную цену (так как сбросить ее в ноль нельзя :) + Загадки ДаВинчи Pro: Ренессанс тоже стали бесплатными на сегодня :). По секрету скажу, что скоро будет продолжение серии «Загадки ДаВични» в новом формате! Кстати, на play google нашу игру встретили более лояльно, нежели на app store. Сейчас игра находится на видимых позициях в категории «Ролевые» топ новых платныхбесплатных. На app store был небольшой скачок скачиваний, когда игра находилась в New. Недавно мы выпустили апдейт, доступный уже для всех стран и очень интересно наблюдать в Google Analytics как в реальном времени играют, например, в ЮАР или Аргентине.

Автор: zoo

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js