Pull to refresh

GameDev и канделябр

Reading time7 min
Views38K
Канделябр — подсвечник, который используется для корректировки формы лица игрока, играющего нечестно.

Наверное, многие помнят карточную игру “Марьяж”, которая манила к ЭЛТ мониторам игроков более десятка лет назад.



В данной статье мы расскажем о том, как пытались дать этой игре вторую жизнь и что из этого вышло.



Первый призыв


Для написания игры изначально был нанят один разработчик из Белорусии, который обещал выпустить приложение в течении двух месяцев, с учётом того, что я предоставляю ему готовый дизайн. При этом, по мере возможности, ему должен был помогать коллега. Работа была оценена в $2000 + % от продаж. После получения аванса в $1000 работа закипела. Шел октябрь 2011 года.

Рекогносцировка


Изначально о портировании чего-либо не было и мысли. Было желание написать преферанс для платформы Android, который стал бы круче всех остальных. Ничего более оригинального, чем изучение специализированной литературы мы не придумали, поэтому стали читать всё, что было доступно в интернете. Среди всех книг выделялся “Русский преферанс” Дмитрия Лесного, с главой, обосновывающей математическую базу игры, которая написана академиком Леонидом Михайловичем Литвиным. К сожалению (хотя, скорее, к счастью), книгу купить было нереально, а во всех онлайн версиях нужная часть книги попросту отсутствовала. Набравшись смелости, мы написали письмо автору и, к своему удивлению, почти мгновенно получили не только недостающую часть книги, но и… исходники Windows версии игры!



Разведка боем и военный трибунал


Казалось бы, вот есть исходники, работа должна быстро продвигаться. Аж но нет, наступило глубокое затишье. Лишь изредка, как лучи солнца сквозь тучи зимой, в свн пробивались комиты, которые даже не позволяли собрать билд. Ближе к январю и они прекратились, рука потянулась за канделябром. После долгих споров, разработчик вернул $500 и мы разошлись миром. Замечу, что в этот же период был создан первый вариант дизайна, за который было заплачено $275, качество было соответствующее.

Переход на контрактную армию


Январь 2012. Потрачено 2,5 месяца и $775, не сделано ничего. По счастливой случайности, друг решивший сменить профиль с Delphi разработчика на Android, принял моё предложение о сотрудничестве и работа закипела. В дальнейшем все рассчёты с разработчиками проходили только через Odesk.

Захват плацдарма


Если вам не интересны технические проблемы, которые мы испытали при портировании игры, сразу переходите к разделу “Наступление”. Сейчас мы смахнём скупую слезу умиления и расскажем о том, с чем нам пришлось столкнуться.

Как уже писали раньше, наличие исходников не означало быстрой победы. Код был весьма запутан, UI шел вперемешку с логикой. Многие (в том числе глобальные) переменные и поля классов состояли из двух-трех букв, а названия классов и методов содержали неизвестные аббревиатуры. Масти и ранги карт, уровни ставок получались в результате магических битовых операций. Что мешало обернуть их функцией с понятным названием — загадка. Пришлось многое постигать экспериментально, пытаясь угадать предназначение той или иной операции.


(Запомните этот фрагмент кода. Ниже мы покажем его современную версию)

На создание первого рабочего прототипа на Java ушло четыре месяца кропотливой работы. Сначала была создана структура классов, которая более точно отображала взаимосвязи различных подсистем игры. На каждом этапе разработки мы имели готовый прототип, который постепенно обогащали функционалом из исходников Марьяжа. Их тоже пришлось доводить до ума, чтобы разобраться в том, как все в коде организовано, а также создать генератор эталонных игр для тестирования.

Первый прототип имел существенный недостаток — работал на смартфоне настолько медленно, что играть было попросту невозможно. Забегая вперёд, скажем, что количество итераций при вычислении оптимального хода в зависимости от уровня игрока варьируется от 25000 до нескольких миллионов, причем многие из вызовов — рекурсивны.
“Перепиши на С!” — советовали мне некоторые знакомые, мотивируя тем, что джава тормозная, а вот на С всё будет летать. Рука опять тянулась к канделябру, но на этот раз хотелось врезать уже себе, так как в этом случае еще несколько месяцев оплаченной работы пришлось бы выбросить. Такой вариант никак не радовал, а из оружия у нас был только гладкоствольный рефакторинг и мелкокалиберная оптимизация. Его мы и применили.

Закрепляемся на рубеже


Очевидно, что игра с тугодумным ИИ не интересна пользователю, поэтому первым делом было решено ускорить алгоритм для уменьшения задержек до разумных пределов. В качестве минимального устройства мы брали HTC Desire, в качестве “среднячка” — Samsung Galaxy S2. Также хотелось удостовериться, что порт алгоритма был сделан верно и оптимизация его не нарушит. Для достижения этой цели были “допилены” оригинальные исходники Марьяжа. Программа была научена проигрывать расклад всеми уровнями игроков на разных конвенциях и записывать результат в XML файл. Для этого пришлось провести долгую и кропотливую работу по отделению интерфейса от логики в Delphi. Аналогичный XML мы получали и из нашего Java кода, затем результат сравнивали. Таким образом, мы получили около миллиона игр, 70 тысяч из которых были отобраны в качестве эталонных. После каждого шага оптимизации мы прогоняли их заново.

Что же было сделано для оптимизации скорости расчетов?
  • Мы отказались от использования EnumSet, EnumMap. Казалось бы, это одни из самых быстрых коллекций в Java, но даже в них затраты на лишние проверки и вызовы дополнительных методов были слишком высокими;
  • Был написан собственный контейнер CardSet, который хранил карты в массиве из 4-х short-ов (сразу по мастям) и использовал битовую арифметику;
  • Для вычисления длины масти (и, соотвественно, всего множества карт) а так же младшей и старшей карты использовались предварительно рассчитанные массивы;
  • Одним из главных пожирателей скорости оказались итераторы. Даже постоянное преобразование из массива 4-х мастей в массив карт и проход по этому массиву выполнялся быстрее, чем вызов самого простого итератора;
  • В самых критичных местах пришлось отказаться от использования классов (включая массивы и Enum-ы) вообще и все перевести на примитивные типы и битовую арифметику. В некоторых случаях оказалось быстрее хранить данные в long и постоянно извлекать из него отдельные байты посредством битовой арифметики, чем хранить их отдельно в массивах. На виртуальной машине Android даже такие небольшие выделения памяти очень сильно ударяют по производительности, если вызываются очень часто. Разница видна и на Oracle JVM.


В итоге нам удалось достигнуть оптимизации скорости в десятки раз (от того, что одна игра считалась несколько секунд на Core i7 до того, что сейчас за секунду просчитывается в среднем 5 игр на самых сложных уровнях). И мы обошлись без переписывания даже части алгоритмов на C, что существенно упростило отладку и тестирование. Сейчас наш продукт работает достаточно быстро даже на HTC Desire, а если и задумывается, то показывается прогресс расчетов. Такого в Марьяже не было, хотя когда компьютеры еще были достаточно слабыми, ходов приходилось ждать по нескольку минут.

Вот что получилось в итоге из того кода, который был приведен в начале статьи:



И вот как он выглядит вживую:



Переходим в наступление


На момент выхода второго прототипа на маркете уже существовали реализации преферанса, поэтому хотелось не ударить в грязь лицом и сделать что-то действительно хорошее. Для начала мы просили знакомых сыграть пару партий и внимательно наблюдали за ходом игры. В итоге интерфейс был существенно изменён, а в игру был добавлен новый уровень сложности — школьник. Изначально нового уровня сложности не планировалось, но после того, как мой друг закончил пулю с более чем 200 в горе и швырнул в меня телефон, я понял что нужно что-то совсем простое. Текущий школьник не просто плохо играет, он еще и помогает игроку! Чтобы удержать пользователя в игре, мы добавили режим “Путешествие”, в котором предложили сыграть в 20 городах с постепенно возрастающей от города к городу сложностью соперников. Мы считаем, что это нам удалось. По данным гугл аналитики средняя длина сессии составляет около 10 минут и более 70% игроков играют в данном режиме. Продвижения как такового мы не делали, так как Admob не рекламирует азартные игры, а заниматься скупкой закачек, не получая тех же денег взамен, явно не стоит. Пробовали купить промо в ЖЖ, результата это не дало. И тем не менее, после публикации на Google Play и анонса на паре форумов мы попали в “Top 10” карточных игр в Украине и в “Top 20” в России в течении первого месяца, отхватив тем самым солидный кусок рынка. За три месяца нашу игру скачало более 50 000 пользователей. Отмечу так же, что статья о Преферансе на вики написана автором конкурирующего продукта и добавить свою ссылку нам не удалось.



Партизанское движение


Как и любой продукт, наша игра игра имеет группу хейтеров, переодически испускающих лучи ненависти на форумах и в коментариях на Google Play. Их объединяет одна и та же мысль: “Я N лет играл в преф и обыгрывал всех в своём дворе, а тут проигрываю? Мухлёж!” Оказывается, у нас и боты играют сообща, и картами они меняются, да и вообще карты мы специально раздаем плохие… Спасибо Google, который дал возможность отвечать на коментарии! Рейтинг, конечно, этим не исправишь, но хоть морально стало легче.

Помощь местного населения


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

Битвы, которые мы проиграли


  • Изначально хотелось получить не только аудиторию стран бывшего СССР, но и хотя бы небольшую часть тех, кто в преферанс никогда не играл. Для этого сделали дизайн в стиле казино, по умолчанию поставили рубашку “Bicycle 808” а не “Шарлеманя”. Не удалось — запад не хочет играть в преф;
  • Сделали локализацию на сербский, так как игра там популярна. После локализации аудитория не выросла, а осталась такой же малой (1%);
  • Бесплатная версия приложения. Частенько прилетают единицы без коментариев или же с обвинениями в том, что мы требуем деньги в случае проигрыша. На фоне конкурента, который принуждает ставить ему 5 звездочек, не давая продолжить игру, закрыв диалог (за полтора месяца рост составил 0.7 с 3.8 до 4.5), мы имеем солидный удар по рейтингу. Забавно наблюдать, как при практически равном количестве закачек, предложение конкурентов прорейтинговали втрое больше, при этом даже негативные коментарии имеют 5*. Куда смотрит Google? Вопросы, вопросы;
  • В определённый момент, под давлением профи, мы улучшили школьника. Он перестал помогать, и в нас полетели камни в виде единиц. Многие игроки используют школьников как источник монет, поэтому такой шаг им не понравился. Исправились мы довольно быстро.


Личный состав


После военного трибунала, первые полгода над проектом работал один программист полный рабочий день, а так же ночь и выходные. Так же был нанят дизайнер, который бросил нас, сделав 50% работы, мотивируя отказ тем, что решил завязать с фрилансом и выйти на постоянку. Следующие полгода (а зарелизили мы 31 декабря 2012 в 23-48) этот же программист работал по вечерам и выходным дням, через три месяца к нему присоедилился еще один молодой, но очень толковый напарник, который изначально взял на себя анимации, а потом выполнял всевозможные задачи.

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

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

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

Планы по захвату мира


Останавливаться на достигнутом мы не собираемся — уже ведутся работы над iOS версией, а также версией Online. Ссылки не оставляю, ищущий да обрящет :)
Tags:
Hubs:
Total votes 75: ↑62 and ↓13+49
Comments86

Articles