воскресенье, 25 сентября 2016 г.

Evil In Trouble переехал на Unreal Engine

Коротко: 

Evil In Trouble портирован с cocos2d-x на unreal engine и почти готов для публикации на ПК.

Пожалуйста, проголосуйте за него в Steam Greenlight!



А теперь немного подробнее:

Я использую Unreal Engine с того, самого момента, как он стал доступен по недорогой подписке и всё это время, мне было интересно насколько он удобен для разработки 2d-игр. Недавно, чтобы отвлечься, я решил попробовать перенести Evil In Trouble с cocos2d-x на unreal engine.


За исключением пары моментов - результат мне более, чем понравился. Использовать Timeline вместо кокосовских Action намного удобнее и гибче. Сущности Paper2D для работы со спрайтами(PaperSprite) и спрайтовыми анимациями(PaperFlipbook) замечательно заменили классы cocos2d-x, при этом позволяя редактировать большинство параметров, которые раньше были зашиты у нас в коде через редактор свойств.

Да и вообще, в c++ осталась только основная логика: загрузка уровня,поиск пути, переключение анимации для персонажа. Всё остальное переехало в блюпринты.

Что не понравилось? Невозможность проигрывания музыки в фоне, без прерывания на загрузках анриловских карт и то, что fadein/fadeout камеры требуют, чтобы анриловский tonemapper был включен.

В общем, если я захочу сделать новую 2d-игру, то выберу Unreal Engine, пусть он и тяжеловесен для этой задачи.

вторник, 26 февраля 2013 г.

Как помочь художнику справиться с тайлсетом

Я думаю, что самым трудным при разработке графики для Evil In Trouble для художника стала работа над тайлсетом. И это, в общем-то, логично, ведь он(тайлсет) должен быть бесшовным и хорошо смотреться во всех возможных сочетаниях тайлов. Однако, главной проблемой стало то, что у художника был компьютер с MacOS X и он не имел возможности запускать игру для того, чтобы проверить свои изменения.

Как же мы могли облегчить жизнь художнику?

На тот момент cocos2dx не поддерживал macosx и мы стали думать, как бы сделать так, чтобы художник все-таки мог менять текстуру и смотреть как смотрятся уровни. Разрабатывать отдельное приложение для на каком-нибудь .net не хотелось, так как пришлось бы портировать алгоритм построения batch node(весь уровень рисуется за один draw call). Поэтому я подумал, а почему бы не использовать для этого приложение и технологии, которые есть абсолютно у каждого и не привязаны к операционной системе - к браузеру и html+css?

Те, кто знаком с html и css, знают, что при верстке тоже используются спрайты. Точно так же, как и разработчик игры, человек, занимающийся разработкой странички может упаковать в одно изображение несколько небольших. Этого вполне достаточно, чтобы воспроизвести рендер уровня, осуществляемый в игре с помощью cocos2d-x.

Как отрисовать спрайт в html?

Предположим, что я хочу, чтобы на страничке  в координатах (400,250) был отрисован спрайт c текстурными координатами (200,200) и размером (50,50).

Определим стиль tile:

<style type="text/css">
    div.tile {
        display:block;
        background:url(tiles.png);
    }
</style>

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

<div class="tile" style="position:absolute;left:400px;top:250px;background-position:-200px -200px;width:50px;height:50px;"></div>

Экспортируем уровень в html-представление!

В класс Level был добавлен метод ExportToHTML, который сохранял все спрайты CCSpriteBatchNode в виде div'ов с переопределенным атрибутом style.

void Level::_SaveToHtml(const char* filename)
{
    const char header[] = "\
<?xml version=\"1.0\"?>\n\
<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n\
<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">\n\
<head>\n\
<style type=\"text/css\">\n\
    div.tile {\n\
        display:block;\n\
        background:url(tiles.png);\n\
    }\n\
</style>\n\
</head>\n\
<body>\n\
<div style=\"position:absolute;left:40px;top:40px;\">\n\
<div style=\"display:block;background:url(background.png);position:absolute;left:0px;top:0px;width:480px;height:320px;\"></div>\n";
    
    const char footer[] = "</div>\n</body>\n</html>";

    FILE* f = fopen(filename, "w");
    fputs(header, f);


    // tiles
    CCObject* object = NULL;
    CCARRAY_FOREACH(mTilesBatchNode->getChildren(), object)
    {
        CCSprite* sprite = (CCSprite*)object;
        CC_ASSERT(sprite->getScaleX() == 1.f && sprite->getScaleY() == 1.f);
        
        CCPoint ap = sprite->getAnchorPointInPoints();
        CCPoint pos = sprite->getPosition();
        CCRect r = sprite->getTextureRect();
        fprintf(f, "<div class=\"tile\" style=\"position:absolute;left:%dpx;top:%dpx;background-position:%dpx %dpx;width:%dpx;height:%dpx;z-index:%d;\"></div>\n", 
            (int)(pos.x - ap.x), (int)(320 - (pos.y - ap.y) - r.size.height),
            (int)-r.origin.x, (int)-r.origin.y,
            (int)r.size.width, (int)r.size.height, sprite->getZOrder());
    }
    // border
    fprintf(f, "<div style=\"position:absolute;left:-2px;top:-2px;width:480px;height:320px;border-width:2px;border-style:solid\"></div>\n");
    fputs(footer, f);
    fclose(f);
}

Вот, например, один из уровней, сохраненный таким способом.


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

После этого мы объединили, для удобства html-представления нескольких уровней в один файл, отдали художнику, и он быстро исправил все недостатки тайлсета и мы двинулись дальше.

TexturePacker - добротный упаковщик спрайтов.


Привет, меня зовут +Сергей Вихирев, мы только что закончили работу над Evil In Trouble и мне захотелось рассказать о замечательной утилите TexturePacker, любезно предоставленной нам её разработчиком. Спасибо, Andreas Löw! :)

TexturePacker предназначен для запаковывания мелких спрайтов в атласы и на наш взгляд является наиболее продуманным и удобным инструментом для этого. По-крайней мере, из тех, которые мы тестировали.


Зачем вообще нужны атласы? Ну... хотя бы из-за вот таких двух преимуществ:

  • Возможность группировать спрайты при отрисовке так, чтобы избегать ненужного переключения текстур или и вовсе отрисовывать все за один раз(batching)
  • Экономия памяти устройства. Так как графические чипы работают только с текстурами размеры которых являются степенью двойки (а некоторые к этому добавляют требование, чтобы текстура была квадратной), то это может стать неявной причиной перерасхода памяти. Давайте представим, что у нас есть некий элемент интерфейса, или элемент декора уровня, шириной 280px и высотой 40px. Если загрузить данную текстуру в любой графической библиотеке, то ей придется загрузить его в текстуру размером 512x512. А если таких текстур несколько? Представляете сколько Вы можете потерять памяти, просто так?
А теперь о том, из-за чего нам понравился именно TexturePacker.

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

Экспорт

Возможен экспорт для множества различных игровых и не очень движков.
Например, cocos2d, corona, libGDX, Shiva3D, Unity3D.
Форматы текстур получаемых на выходе - png, jpg, bmp, tga, tiff, pvr, а также pvr.gz и pvr.ccz. Не хватает, наверное, только DDS.

Форматы текстур также разнообразны - это RGBA8888, RGBA4444, RGB888, RGB565. Это не полный список форматов, их там гораздо больше, просто привожу самые популярные.

Также присутствует опция создания автоматического уменьшения размеров текстур, например для iPad версии, из версии для iPad Retina.

Размещение спрайтов

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

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

Есть также возможность удалять со спрайтов избыточную 100% альфу, это помогает экономить место в атласе.

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

Командная строка

Имеется возможность паковать спрайты в атласы из командной строки. Обязательно постараемся автоматизировать часть asset pipeline с помощью этого в наших следующих проектах :) Список аргументов в консольном режиме позволяет задавать все те же настройки, что и и при использовании приложения с GUI.

Платформы

TexturePacker является кроссплатформенным приложением, который имеет одинаковый функционал на Windows, MacOS, Ubuntu linux.

Хотелось бы добавить, что TexturePacker регулярно обновляется, не только исправляя недочеты но и расширяя функционал. Я смотрел TexturePacker год назад и могу сказать, что он очень сильно вырос в плане функциональности.

четверг, 24 января 2013 г.

Почему я не люблю обновлять релизы в AppWorld

Итак, почему же я не люблю обновлять релизы в AppWorld(магазин Blackberry)?

Немножко предыстории

После регистрации в качестве blackberry-разработчика я получил два  файла client-PBDT-**********.csj и client-RDK-**********.csj. Было бы логично предположить, что они и используются для подписывания, но... Давайте я просто оставлю ссылку на страничку, где описывается, что нужно сделать, чтобы иметь возможность подписывать приложение.

Когда blackberry-keytool сгенерировал мне author.p12 файл, я его, разумеется, забэкапил. И забыл о нем на десять месяцев. До того момента, пока не обновился до windows 8.

Небольшое отступление. Если кто-нибудь захочет установить blackberry sdk на windows 8, запускайте с параметром -i GUI ;)

Ну обновился и обновился, бэкап же есть, думал я и был неприятно удивлен, когда не смог подписать очередной релиз Run In Crowd. Копание документации и форумов blackberry показало, что blackberry-keytool также генерирует файлы barsigner.csk и barsigner.db в профиле (подробнее здесь) и что без этих файлов подписать ничего нельзя, и восстановить их нельзя. Единственный выход - сгенерировать новые, которыми уже нельзя будет подписать старое приложение. Думаю, что несколько седых волосков у меня в тот момент точно прибавилось. Кто же будет бэкапить %HOMEPATH%\AppData\Local\Research In Motion?

В тот день я был очень признателен разработчикам Microsoft, потому что при обновлении старый профиль был заботливо скопирован в папку Windows.old.

Почему мне нравится подписывать приложения?

  • Компьютер должен иметь доступ к интернету, в момент подписывания
  • Если Вы подписали версию, то второй раз её подписать не получится, даже если вы её никуда не выкладывали - будьте добры, поправьте bar-descriptor.xml
  • Если я захочу подписать с другого компьютера, то придется копировать barsigner.csk и barsigner.db с того, где был сгенерирован author.p12

Почему мне не нравится закидывать .bar файлы в AppWorld?

  • Просто загрузить файл нельзя, нужно создать bundle
  • У bundle должно быть уникальное имя
  • В bundle нужно указать версию(которая уже указана в bar-descriptor.xml). Если укажете версию, отличную от того, что записано в bar-descriptor.xml - получите ошибку
  • Вы можете называть bundle v1.1.1, v1.1.2, а в один прекрасный день узнать, что точки теперь запрещены
  • Вы не можете редактировать уже созданный bundle. Даже для редактирования поддерживаемых устройств. Да, это значит, что надо обновить bar-descriptor.xml, снова подписать приложение и создать для него новый bundle.

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

четверг, 4 октября 2012 г.

Необычный Amazon Appstore


Что-то давно не писал в блог. Учитывая, что постоянных читателей у меня нет, думаю, что простительно :)

Я хочу поделиться очень интересными, с моей точки зрения, наблюдениями о таком рынке для android-приложений, как Amazon Appstore.

Amazon Appstore for Android стал интересен мне сразу после того, как Amazon выпустили свой первый Kindle Fire. Было очевидно, что у такого дешевого планшета будет своя аудитория, и не маленькая. Поэтому, после того, как Run In Crowd был доведен нами до состояния, близкого к финальному, я выделил время на изучение документации SDK от Amazon, написание обертки для InAppPurchases и выложил приложение в Amazon Appstore (первый год - бесплатно, далее 100$ в год).

Приложение сделал платным и вот почему: Amazon Appstore известен даже среди пользователей, у которых планшеты с предустановленным Google Play из-за FAD - Free Application of the Day - акции, по которой пользователи имеют возможность каждый день скачать платное приложение бесплатно.

Для участия в этой программе, необходимо подать заявку. Через  некоторое время со мной связались и озвучили несколько замечаний(пожеланий) к приложению. Самое главное из которых звучало так:

Open Feint for leaderboards/saving scores – We did want to call this out as it could potentially cause low reviews on the day of the promotion.  Recently we’ve seen a huge increase in 1 star reviews around Open Feint and permissions.   (up to 200 1 stars in one day)  Some developers have chosen to remove and some have opted to have Open Feint on the main menu as an option.

Это было интересно и одновременно непонятно для меня. Учитывая, что у нас не OpenFeint, а Scoreloop, я уточнил, существенно ли это. Ответили "да". Поэтому мы решили сделать авторизацию(с показом Terms of Service) по тапу на логотип Scoreloop или кнопку Today's Bests, т.е. по факту желания воспользоваться функциями Scoreloop.

Дальше было тестирование(судя по всему, очень пристальное, потому что благодаря ему я исправил баг на устройствах с выдвижной клавиатурой(иронично, что у меня самого Motorola Milestone с аппаратной клавиатурой), исправление недочетов и, наконец, наше приложение появилось на главной Amazon Appstore(тех.поддержка заранее предупредила, что будет большое количество скачиваний и порекомендовало увеличить серверные мощности, чтобы не было отказа в обслуживании).

Радость от большого числа скачиваний была испорчена одним обстоятельством, которое и сподвигло меня к написанию этого поста. У Amazon Appstore очень специфичная аудитория.

Смотреть за отзывами и оценкой Run In Crowd было очень неприятно. Было много единичек с комментариями вида "это приложение собирает данные о вас и отправляет их RIM".

Вот часть одного из таких комментариев:

To keep your score, you need to sign up with and enable Scoreloop (a subsidiary of Research In Motion) - which is a DATA MINING company. Here is a quote right from their Facebook page: "Drive discovery and increase sales" and "Sophisticated social data mining". Checking their EULA, you basically give them rights to share this data with their "partners".

Я не верил своим глазам, какие-то упоротые параноики(в бункере с пятилетними запасами еды?) обвиняют меня в том, что я собираю о них какие-то данные? Оказалось, что такой троллинг на Amazon'е популярен и пользователи не любят ни OpenFeint, ни Scoreloop. Кто-то даже написал "надо чтобы у вас было свое для этих целей"(а что, я сам не мог бы собирать эти данные?).

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

Итак, что не любят пользователи Amazon Appstore?

  • Не любят OpenFeint, Scoreloop и прочие социальные игровые сети
  • Не любят, если в приложении есть IAP, но в описании это не указано
  • Не любят, если у приложения есть permissions, не совпадающие с их представлениями о безопасности. Тот, факт, что Amazon проверяет приложение их не успокаивает

Стоило ли участвовать в FAD? Да, стоило, несмотря на то, что средняя оценка стала 3 из 5(на остальных платформах >= 4.7).
Применительно к нашей игре, я могу сказать, что у Amazon'а получился самый высокий процент конверсии.

Вот так выглядит график скачиваний за последние два месяца.

понедельник, 4 июня 2012 г.

upSL - кроссплатформенная обертка для Scoreloop

Давно уже хотели выложить на github, да всё как-то руки не доходили.

Про upSL

Итак, наша кроссплатформенная обертка для игр, разрабатываемых с помощью cocos2d-x и использующих Scoreloop - upSL.

Когда мы в Run In Crowd решили отказаться от OpenFeint в пользу Scoreloop, то встал вопрос о том, как организовать  работу с его функциями в приложения.

Требования были такими:

  • API должно быть кроссплатформенным
  • Контроллеры должны создаваться из игрового кода
  • Нежелательно создание лишних объектов, оборачивающих функционал сущностей Scoreloop

В итоге, пришли к такому вот решению. Покрыт не весь функционал, только то, что нам понадобилось.

Про Scoreloop

Пока разбирались, нашли несколько багов в Scoreloop, самые неприятные - в ios версии. Будем надеяться, исправят. Вообще, scoreloop достаточно капризный, например, нельзя разблокировать ачивку, если еще осуществляется синхронизация. Мелочь, но, в итоге, приходится в коде создавать дополнительные механизмы для обхода таких ограничений.

Про сложности

Больше всего кода требуется для android, в данный момент это более 1700 строк jni_scoreloop.cpp. Кроме того, что jni сам по себе трудоемкий, дополнительные проблемы создает то, что часть функций должна вызываться в ui-thread'е, поэтому их пришлось реализовывать в Scoreloop.java c предоставлением доступа нативной части обертки. При этом, callback вызванный Scoreloop'ом после выполнения запроса должен быть вызван в render-thread'е, в котором крутится игровая логика.

Будем рады, если кому-нибудь пригодится :)

четверг, 31 мая 2012 г.

Наконец-то получил Playbook!

Когда я, после прочтения топика на habrahabr, за короткое время собрал Run In Crowd для Blackberry Playbook, оттестировал на симуляторе, отправил в Blackberry Appworld и, будучи уверенным в том, что его заапрувят, стал прикидывать, когда же мне доставят обещанный Playbook 16GB, я и подумать не мог, что на это понадобится три месяца...

Как я узнал чуть позднее, (RIM очень неохотно отвечали на письма, видимо из-за очень большого количества разработчиков, которым нужно было высылать Playbook), проблема была в том, что FedEx не отправляет в Россию посылки стоимостью больше 200$. Получив номер трекинга я увидел, что планшет еще 2го марта был отправлен, перебрался через океан, в Англию и был возвращен обратно.

Т.к. на мои (да и не только мои, судя по обсуждениям на форумах) письма отвечали очень долго, то решил попробовать "зайти с другой стороны". С самых первых дней релиза Run In Crowd, со мной связался менеджер RIM по связям с разработчиками и, поскольку мы достаточно плотно с ним общались, я обратился за помощью к нему - описал ситуацию, спросил, нет ли у него выхода на людей, отвечающих за отправку планшетов. Он подтвердил, что пока нет возможности отправить планшет в Россию, спросил нет ли у меня адреса за рубежом, куда можно было бы отправить планшет и, после того как я написал, что родственников и знакомых за рубежом у меня нет, предложил подождать.
Я расстроился, посетовал в твиттере, что российские разработчики не могут получить планшеты и получил заверение, что все разработчики получат обещанные планшеты.

И, наконец-таки, получил вчера от курьера в руки долгожданный планшет, даже 32GB, а не 16GB, как было обещано :)


Весь вечер провозился, разбираясь в деталях отладки на реальном устройстве :)

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

P.S. кстати, подобную акцию RIM проводит не первый раз, прошлой весной, в преддверии выхода Playbook, они тоже давали разработчикам планшеты.