Привет, меня зовут Всеволод Шмыров. В Яндексе я занимаюсь разработкой интерфейсов. Но этот пост посвящен тому, как я just for fun попробовал выйти на рынок игр под Windows Phone. Я разработал небольшую игру-арканоид. Примерно год назад я подготовил небольшой доклад об этом и представил его своим коллегам. Доклад охватывает все четыре стадии, которые мне пришлось пройти: подготовка, разработка, публикация и после публикации. Сегодня я хочу поделиться этим рассказом с вами. Сразу оговорюсь, что это не история успеха. Популярной моя игра так и не стала, так что идею заработать на ней я забросил и сделал игру бесплатной.
Для начала представлю свою игру. Она называется Pixelnoid. Геймплей абсолютно классический для арканоида: игрок управляет платформой, отбивает мячики, мячики сбивают блоки. Цель каждого уровня – уничтожить все доступные блоки. Игра обладает очень необычной графикой, вместо мячика пиксель, вместо блока пиксель побольше, все пиксели разноцветные, и поэтому получается составлять вот такие простые писксельные изображения, как на заглавной картинке. На самом деле там используется всего лишь 400 пикселей. Игра доступна для платформы Windows Phone, начиная с версии 7.5. Изначально она стоила около 1$, хотя был триал и бесплатная лайт-версия, но об этом я чуть позже расскажу на этапе «после публикации». Игра разрабатывалась с апреля по июнь 2013 года, в августе я производил всякие обновления, чинил баги и пытался хоть как-то распространить игру.
Под катом вы найдете рассказ по мотивам доклада, его видеозапись и слайды.
Подготовка
Стоит рассказать, почему я вообще начал это делать. В марте я купил телефон на базе Windows Phone и сразу заметил, что в маркете игр почти нет, особенно арканоидов, а это мой любимый жанр. И как программист я сразу решил исправить это. Некоторые арканоиды были, но по большей части они были портированы с Windows Mobile, и это было ужасно. У меня есть опыт разработки игр, это мое хобби с давних про, но публикации до этого еще не было. Я постоянно сам себе клепал мелкие игрушки и в них играл. Плюс у меня есть некоторый опыт, скажем так, промышленной разработки игр: в предыдущей фирме я два года разрабатывал игры для социальных сетей. Также мне еще была знакома среда разработки (Visual Studio), платформа .NET, язык C# и технология XNA.
XNA — это набор инструментов, который упрощает процесс разработки игр. Не готовый игровой движок, а именно удобный интерфейс для того, чтобы взаимодействовать с двухмерными спрайтами, трехмерными моделями, звуками и прочими элементами, которые могут понадобиться в играх. XNA последние несколько лет очень активно используется для разработки в основном для инди-игр в основном для платформ Windows и Xbox. Туда входит framework, который работает в связке с .NET и специальная версию редактора XNA Game Studio edition.
На XNA было создано множество игр. Например, Torchlight (обе части), Bastion, FEZ. Но так как это Microsoft, я очень быстро столкнулся с реальностью. Я узнал, что технологию XNA могут через некоторое время закрыть. Там была довольно мутная история. Официально XNA рекомендовался разрабатывать под платформу Windows Phone 7, а под платформу Windows Phone 8 появилось какое-то странное сообщение о том, что Microsoft не рекомендует использовать эту технологию, и что она будет работать в режиме совместимости для приложений под Windows Phone 7. Там похожая проблема была с технологией Silverlight, в какой-то момент ее отменили. Но, тем не менее, это мнение никак не помешало, потому что я очень быстро нашел проект нашел проект Mono Game. Это свободная реализация XNA, интерфейсно все выглядит точно так же, по сути я просто отключил от проекта библиотеки XNA и подключил проект Mono Game. Все сразу же заработало, никакой разницы нет. И Mono Game, в отличие от XNA, поддерживается большим количеством платформ (Windows, Linux, OS X, Android, iOS, QUYA, PlayStation). Эта технология потенциально позволяет мне без особых усилий выйти на другие мобильные рынки.
Разрабатывал я все в Visual Studio по сути под Windows Phone 7 в эмуляторе. Для разработки под Windows Phone 8 потребуется Windows 8 с Visual Studio 2012. В начале я пытался все это запустить в эмуляторе, но у меня это не заработало, потому что требовалась поддержка виртуализации. В некоторых случаях я шел по наиболее быстрому пути. И тут наиболее быстрым путем мне показалось поставить 90-дневную Windows 8 на ноутбук и дебажить приложение на моем телефоне. Так я и сделал, хотя потом все же купил полноценную Windows 8 Professional.
Теперь немного про сам магазин. Этап подготовки достаточно длительный. Прежде чем приступить непосредственно к разработке, я примерно 3 недели собирал данные по поводу того, что можно и нельзя сделать, и что в конечном итоге мне это может принести. Магазин Windows Phone так же как и App Store проверяет приложения перед публикацией, в отличие от Google Play. Приложений там было достаточно много, но большинство из них — просто треш, поделки на коленке. Годовая подписка разработчика на тогда стоила 99$ а сейчас стала 19$ в год. Проверяют обычно от 4 до 7 рабочих дней. В принципе, это не так много, особенно по сравнению с магазином приложений Apple. Мне не хотелось платить 99$ поэтому я стал искать лазейки как это можно совершить.
И я очень быстро нашел программу DreamSpark — это такой небольшой лайфхак. Программа от Microsoft, которая предоставляет студентам возможность публиковать приложения в различные магазины Microsoft. Эта программа действует год, как и сама подписка. Была одна тонкость в том, что я не студент, на тот момент я уже полтора года как получил диплом. Я снова начал искать лазейки и снова нашел.
Я все провернул через сайт Интуит — этот сайт каким-то образом получил возможность раздавать ключи. Чтобы получить ключ, достаточно было пройти несколько тестов, которые утвердили в Microsoft. Я там сдал основы HTML 5, пару тестов по C# и по базовому JavaScript. Я на этом сайте давно зарегистрирован, поэтому мне нужно было пройти всего лишь 3 теста, новому пользователю нужно пройти 6 или 8 тестов, и это до сих пор работает, они так же продолжают раздавать ключи.
Плюшки Dreamspark:
- возможность публиковать приложения (я этим воспользовался);
- бесплатное или со скидками ПО (мне это не пригодилось, т.к. я все разрабатывал в экспресс-версиях);
- и последнее, наверное, самое главное — возможность обновить Windows 8 до версии Pro за 2000 рублей вместо 9900.
На процессе регистрации в магазине в качестве разработчика я подробно останавливаться не буду, ничего интересного там нет. Нужно было заполнить несколько анкет: информация о себе, своем банке и т.д.
Следующий этап — это разблокировка телефона. Это последнее препятствие перед самой разработкой. Делается это очень просто. После разблокировки телефона появляется возможность устанавливать .xap-файлы не из магазина приложений, а с SD-карточки. Этим пользуются пираты. На моей модели телефона HTC 8X не было слота для SD-карточки, поэтому я все проворачивал, подключая кабель к ноутбуку, и каждый раз собирал проект. Мне это не мешало.
Разработка
Наконец, мы подходим к самому веселому этапу — разработке. Делал я все с апреля по июнь, в основном в свободное время, в праздники, выходные и во время отпуска.
Так как я все делал сам, мне нужно было как-то планировать свое рабочее время. Я использовал систему ролей. Приходил с работы и решал, что сегодня я геймдизайнер. Я садился, создавал новый уровень, и вдруг видел какой-нибудь баг. Тогда я писал о нем в таске программисту, который, возможно, мог бы прийти завтра-послезавтра. Конечно, если баг был серьезный, то я трансформировался в программиста и сразу же правил его, а потом возвращался обратно.
ToDo-списков я составлял очень много: на клочках бумаги, в вебе и в мобильных приложениях. В начале я пытался заниматься планированием, но в конечном итоге я пришел к другому способу управления тасками. Я стал просто для каждой роли вести общий список. Как только я заканчивал работу, я выписывал то, что за сегодня сделал. Получается некоторая система поощрения. Когда запланировано больше, чем сделано, появляется нежелательное чувство вины. А когда ты записываешь хотя бы один пункт из сделанного, появляется какое-то ощущение гордости за себя, что ты чего-то достиг, дело медленно, но двигается.
Геймплей арканоида понятен: летает мячик, разбивает блоки, при уничтожении блок может влиять на соседние блоки. У меня это и взрывающиеся блоки, и bomber-блоки, которые уничтожают все блоки по горизонтали и вертикали. Есть блоки ледяные, которые делают все соседние блоки очень хрупкими. Это все значительно разбавляет геймплей. В моей версии игры есть одна особенность: мячик от платформы отскакивает не по отраженному углу, а так как будто бы платформа слегка скругленная. Чем ближе к центру происходит удар мячика, тем прямее угол отскока. Когда я это делал, вообще не задумывался. Но спустя примерно три месяца после того, как я разработал эту механику, я узнал, что бывают и другие. Например, кто-то использовал падение с небольшим углом рандомно. Но тогда получается, что игрок совершенно не управляет игрой, т.е. он не может направить мяч в ту сторону, в которую ему нужно.
Как видно по скринам, в игре есть очки. Уничтожив один блок, получаешь одно очко. Если удается уничтожить число блоков кратное пяти, не касаясь платформы, дополнительно получаешь столько же очков. Очки были добавлены в игру просто как классический элемент арканоида, они не влияют на последующие уровни. Там нет всяких популярных нынче звездочек и достижений, хотя, возможно, и следовало это сделать. Это помогло бы прибавить интереса к игре.
Архитектура игры
Игра в плане программного кода не очень большая. Я не использовал паттерн MVC. Вообще это самый популярный паттерн в играх, например, есть тысяча юнитов, которые выглядят по-разному, но ведут себя одинаково. У меня есть некая сущность, которая похожа на представление. Она описывает цвет элемента. Все элементы в игре обладают каким-то определенным цветом и простой геометрической формой. В общем-то, контроллер от модели у меня редко отличался в том плане, что у мячика есть определенный квадрат, который используется и для детектинга коллизий, и для отрисовки этого мячика на экране. Архитектурно XNA-игры выглядят примерно одинаково. Я говорю XNA, а не MonoGame, т.к. интерфейс и основные принципы были изначально заданы именно в ней. XNA сама предоставляет технологию «тика»: два метода Update и Draw в базовом классе. Первый метод отвечает за обновление данных по «тику», а второй — за отрисовку. XNA не предоставляет сущность «игровой элемент», а только инструменты для работы с графикой, звуком и текстом. У меня есть базовый элемент уровня, базовый элемент интерфейса, не все сделано хорошо, но, тем не менее, это работает. Не могу сказать, что во время разработки у меня возникали проблемы с негативными результатами из-за изначально неправильной архитектуры.
Есть один момент, который я хотел бы выделить. При разработке игр почему-то очень часто многие допускают такую простую ошибку: на каждый «тик» сдвигают игровые элементы на определенное расстояние. Например, Марио бежит к топору, чтобы разрубить мост и сбросить Боузера в лаву. В играх необходимо всегда не на какую-то константу сдвигать персонажей каждый «тик», а всегда задавать какую-то скорость умноженную на дельту между текущим и предыдущим тиком. Это нужно на случай, если вдруг на каких-либо устройствах ваша игра будет тормозить. В производительных играх это очень важно. Если у кого-то было 10 FPS, а у кого-то — 30, игроки увидят разный результат. Например, Марио не добежит до топора и не спасет принцессу.
Чтобы этого избежать, я храню позицию и направление. Этим очень удобно манипулировать в том плане, что мне периодически нужно создавать шейпы, которые движутся под некоторым углом от направления мячика, и нужно было создавать бонусы клонирования мячика. Т.е. мячик в воздухе как бы раздваивается. Я переводил направления в радианы, добавлял некоторый угол и потом переводил обратно для новых мячей.
Position.X += Direction.X * Speed;
Position.Y += Direction.Y * Speed;
…
double ballDirection = Math.Atan2(ball.Direction.Y, ball.Direction.X);
newBall.Direction.X = Math.Cos(ballDirection + Math.PI / 8);
newBall.Direction.Y = Math.Sin(ballDirection + Math.PI / 8);
newBall.Position.X = ball.Position.X;
newBall.Position.Y = ball.Position.Y;
Вернемся к внешнему виду игры. Как я уже говорил, блоки бывают разной прочности, у меня они обозначены различными цветами. Блоки из бело-серой группы обладают прочностью 1 (т.е. для их уничтожения достаточно одного удара), у зеленых прочность равна 2, у синих — 3 и т.д.
Блоки голубого цвета в центре — это как раз ледяные, которые делают все соседние блоки очень хрупкими, т.е. белыми. Это классический элемент геймплея арканоида, у меня он просто выполнен в виде пикселей. При создании уровней я старался одновременно сделать уровень визуально красивым, но не слишком простым или сложным. При разработке я себя не ограничивал, нагло брал образы из других игр и использовал интернет-мемы.
Уровни я просто рисовал в редакторе, получались картинки 20 на 20 пикселей. Их я подключал к проекту и при первом создании уровня парсил изображение. Каждый цвет пикселя соответствует определенному типу блока, нужно было обработать всего лишь 400 пикселей. Это очень быстрая операция. Нельзя сказать, что в каком-то месте в плане производительности игра проседала в каком-то месте при обработке данных.
Еще в описание уровня включается XML-файл, который описывает всякие данные, которые не очень удобно обозначать графически: положение мячей на платформе от 0 до 1 и расположение бонусов в уровне. Бонусы бывают статические (всегда жестко привязаны к позиции в сетке) и динамические (случайно раскидываются по плиткам без бонусов при запуске уровня).
Цвета пикселей
На картинке ниже отображен целый уровень, состоящий только из условно белых пикселей. Все пиксели с определенной прочностью имеют примерно одинаковый цвет. Вроде как это белый, хотя видно, что некоторые блоки совсем не белые.
Я это делал программно, в игре не использовалось спрайтов. Если быть точным, есть один спрайт размером 1 на 1 пиксель, который я программно растягивал до определенного размера и подкрашивал нужным мне цветом. Цвет получал при помощи достаточно простой функции. В примере ниже как раз проставлены значения именно для получения белого блока: от белого до серого.
r1 = g1 = b1 = 170;
r2 = g2 = b2 = 255;
…
public static Color GetColor(byte r1, byte r2, byte g1, byte g2, byte b1, byte b2)
{
if (rand == null)
rand = new Random((int)DateTime.Now.Ticks);
float fRand = (float)rand.NextDouble();
Color result = new Color();
result.R = (byte)(r1 + ((r2 - r1) * fRand));
result.G = (byte)(g1 + ((g2 - g1) * fRand));
result.B = (byte)(b1 + ((b2 - b1) * fRand));
return result;
}
Поэтому каждый раз, если приглядеться, картинка всегда получается немного разной. Ниже приведено видео с примером интересного уровня, где есть блоки-ключи и блок-ворота. При ударе по блоку-ключу блок-ворота на пять секунд разблокируются и становятся доступны для разрушения. Разблокировка ворот запускает визуальное обновление блока, поэтому если бить по ключу многократно, получается что-то типа белого шума.
При разработке мне нужно было поддерживать все разрешения экрана, которые на тот момент встречались на платформе Windows Phone:
- 800x480 (wvga);
- 1280x720 (720p);
- 1280x768 (wxga).
Очевидно, что с таким набором разрешений мне также нужно было поддерживать два соотношения сторон. Все подходят к этой проблеме по-разному. Лично я скейлил картинку всю по ширине экрана. На картинке ниже видно, как снизу обрезалось изображение. У меня под платформой было достаточно большое пространство под палец, чтобы игрок, управляя платформой пальцем не перекрывал себе картинку. Я этим пространством немного пожертвовал, для того чтобы картинка хорошо выглядела и с шириной 720, и с шириной 768. Красной линией как раз показано то, что на левом экране платформа чуть ниже находится, чем на экране с другим соотношением сторон.
Пара слов о музыке и звуках. Музыки у меня в игре нет, потому что у меня руки не дошли ее сделать. Звуки в игре есть, они использовались с моей любимой приставки — SNES. Я нашел 256 семплов и их использовал.
Публикация
В определенный момент я понял, что если я не опубликую приложение в ближайшее время, у меня останется только два пути. Либо я буду пилить приложение бесконечно, получив годам к семидесяти неимоверно крутой движок на все случаи жизни (но к тому времени он мне уже будет не нужен), либо я просто потеряю интерес и заброшу разработку.
Форма аплоуда приложения состоит из четырех этапов. На первом нужно заполнить самые основные данные: категория, подкатегория, название в Dev Center и цена (я поставил 34 рубля). Тогда у меня еще не было триал-версии, так что я загружал только платную игру.
На втором этапе происходит непосредственно загрузка XAP-файла. У их было сразу два, так как я одновременно загружал версию на чистом XNA и для WP7. В этой форме также указывается, какие версии платформы и разрешения экрана поддерживает приложение. Большая часть информации, в том числе и язык приложения, берется из настроек проекта. Нужно было также ввести описание, ключевые слова, загрузить иконку (300x300), фон (1000x800) и скриншоты под все поддерживаемые разрешения экрана.
Третий этап — возрастные рейтинги. Я проставил себе только два CSRR (Тайвань) и PEGI. В первом было достаточно выбрать нужный пункт из выпадающего списка, поэтому я его и заполнил. А PEGI мне был необходим, так как этот рейтинг используется во многих европейских странах, в России и США, а именно на эти рынки я и был нацелен. Это также было несложно. На сайте PEGI нужно было заполнить буквально одну форму (наличие насилия, эротики, наркотиков, алкоголя и тому подобного).
В итоге мне дали скачать специальный PDF-файл, который нужно было загрузить в магазин приложений для подтверждения рейтинга. Мне еще был интересен рынок Бразилии, но для получения рейтинга для этой страны нужно было отправить заполненный бланк на реальный адрес, и связываться с этим я не стал.
Последний пункт — это получение ключа к сервисам карт от Nokia. Мне он не понадобился.
После публикации
Я отправил приложение и стал ждать аппрува. Восьмого августа мне пришло письмо с подтверждением. Выяснилось, что при заполнении формы я забыл снять галочку с пункта «публиковать, как только это станет доступно», так что моя игра уже висела в магазине приложений.
Сразу после публикации дела шли не очень хорошо, игру никто не покупал. Я начал искать варианты для продвижения игры. Первым делом я сделал группу на facebook. Залайкали ее только мои друзья. Я также залил ролики на YouTube, это тоже не принесло особого успеха. Далее я написал об игре на пару тематических сайтов (http://wpcentral.com, http://4pda.ru), где отнеслись с большим одобрением к тому, что автор сам пришел порекламировать свою игру. Просмотров там было, много, а вот с покупками как-то не срослось. Весь август я правил баги и вносил исправления в игру. Кроме того, я сделал триал-версию с 2, а затем и с 5 бесплатными уровнями. Для название с Pixelnoid на Pixel Arkanoid (Pixelnoid). Также я заменил казавшуюся мне красивой иконку на чуть менее приятную, но более понятную. Это принесло мне на 3–4 установки в день больше, люди стали понимать, что это арканоид.
Чуть позже я еще сделал бесплатную лайт-версию: ту же игру, но с другим набором уровней (их там всего 15). Там я сделал специальную кнопочку “more levels”, которая открывает магазин приложений с предложением купить полную версию. Естественно, эта игра стала гораздо популярнее оригинальной версии.
Windows Phone Store для каждого региона свой, ниже приведены результаты по запросу [arkanoid] в России, США и Британии. Как видно, выборка получается немного разная, хотя Pixelnoid Lite встречается везде.
Через какое-то время моя игра появилась на паре пиратских сайтах, что я считаю в некотором роде показателем успеха.
Еще чуть позже мне пришло письмо с сообщением о том, что Pixelnoid будет висеть в рекомендованных играх (первый экран при переходе в раздел игр в магазине приложений) в Китае. Позже такое же письмо пришло про Великобританию и Австралию. На графике ниже видны всплески, связанные с моими действиями. Игра начала медленно расти когда появилась сначала триальная, а затем и лайт-версия, ну а крупные всплески в конце — это как раз результат появления в рекомендованных.
Но скачивания и покупки — разные вещи. Купили игру за месяц всего 6 раз, т.е. не окупилась даже покупка Windows 8 со скидкой.
Спустя пару месяцев после того, как я выступил с этим докладом, я решил сделать игру полностью бесплатной. Ситуация с покупками в лучшую сторону не менялась, несмотря на то, что я еще пару раз попадал в раздел рекомендованных игр. Безусловно, в провале игры виноват я сам. Сейчас, смотря на проект, я вижу множество ошибок в самой игре, которых не замечал во время разработки.
Подытожить это все, наверное, надо прописными истинами, которые понятны всем и без меня. Если хочешь добиться какой-то реальной отдачи, нужно уходить в дело с головой, а не заниматься им вполсилы. Да и это не гарантирует результата, особенно если делаешь это в одиночку и без особенных финансовых вливаний. Я не относился к разработке серьезно, и результат теперь кажется очевидным.
Лично я считаю, что экосистема WinPhone все еще остается «сыроватой». Хотя с прошлого года ситуация заметно улучшилась. В магазине появилось множество приложений и игр как от крупных издателей, так и от инди-разработчиков. Входной порог, кажется, все еще остается ниже, чем на Android или iOS.
Автор: vsesh