Facebook Instant Games config

Теперь наличие файла fbapp-config.json стало обязательным. Это обычный JSON, в котором описаны желаемые параметры игры. Подробности доступны по адресу
https://developers.facebook.com/docs/games/instant-games/sdk/bundle-config

Android NDK native APIs

Постоянно забываю какой API level какому Android относится.
Сводня табличка по стабильным версиям API NDK.
И что бы два раза не вставать – заметки по SDK platform, а заодно и ассеты Android.
Долгое время я использовал API 16, что соответствует Android 4.1 и Android 4.1.1. Сегодня решил в одной игре перейти на API 21. Перед публикацией посмотрю статистику количества отвалившихся пользователей этой игры из-за переходя на новую версию API.

Книга «Шаблоны игрового программирования»

Шаблоны игрового программирования Перевод книги Game Programming Patterns by Robert Nystrom. Книга была создана для удобного чтения на русском языке в формате электронной книги.

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

Краткий список шаблонов, которые рассмотрены в книге: Command, Flyweight, Observer, Prototype, Singleton, State, Component, Event Queue и прочее.

На сайте автора http://gameprogrammingpatterns.com/ можно заказать печатную или электронную версию книги на английском языке.

Ultimate Question 42

Вчера закончился прием заявок на международный конкурс Ludum Dare. Разработчикам нужно за 72 часа (jam) или за 48 часов (compo) создать игру с нуля на заданную тему.

Наша команда из 4 человек создала игру Ultimate Question 42 за 72 часа.
Я был в роли программиста и технического специалиста (ну а как иначе :)), Шевадзуцкий Александр за геймдизайнера, а Ходас Артем и Доджо у нас художники.

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

Игру решили писать на моем движке сразу для Web, т.к. позволяет оценить игру сразу, без установки на десктоп или мобильное устройство. На сайте проекта доступна нативная версия для Linux, у меня на смартфоне работает версия для iOS. В будущем планируется выпуск публичных версих для iOS, Android, Apple TV (tvOS), Android TV, а так же для платформы Facebook Instant Games.

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

Ссылка на официальную страницу игры на Ludum Dare – Ultimate Question 42

Загрузка и кодирование в base64 на JavaScript

Для шаринга и инвайта в Facebook / Instant Games нужно в качестве параметра image передать картинку, закодированную в base64. Можно сделать это в offline, но это увеличит размер дистрибутива и увеличит время загрузки игры. Значит это не наш метод.

Я делаю это в рантайме с помощью XMLHttpRequest и FileReader:

function toDataURL(url, callback) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
        var reader = new FileReader();
        reader.onloadend = function() {
            callback(reader.result);
        }
        reader.readAsDataURL(xhr.response);
    };
    xhr.open('GET', url);
    xhr.responseType = 'blob';
    xhr.send();
}

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

Emscripten initialization

Мой обновленный способ инициализации. В целом он почти не отличается от использованного мною все эти годы. И является практически дефольтным, согласно документации. Но, на одном параметре стоит заострить внимание.

По-умолчанию этот параметр установлен в TRUE. И сегодня я получил слайд-шоу, установив его в значение по-умолчанию.

EmscriptenWebGLContextAttributes attr;
emscripten_webgl_init_context_attributes(&attr);

attr.alpha = EM_FALSE;
attr.depth = EM_FALSE;
attr.stencil = EM_FALSE;
attr.antialias = EM_FALSE; // <-- this should be set to FALSE!
attr.preserveDrawingBuffer = EM_FALSE;
attr.preferLowPowerToHighPerformance = EM_FALSE;
attr.failIfMajorPerformanceCaveat = EM_FALSE;
attr.enableExtensionsByDefault = EM_TRUE;
attr.premultipliedAlpha = EM_TRUE;
attr.majorVersion = 1;
attr.minorVersion = 0;

EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(nullptr, &attr);
emscripten_webgl_make_context_current(ctx);

Emscripten HiDPI

На HiDPI мониторах downscaled текстуры выглядят мягко говоря не очень красиво. Искал способ решить эту проблему. В итоге мои исследования привели к такому не самому легковесному решению.

  1. Получить device pixel ratio для настройки размров canvas.
  2. Получить размер canvas и разрешение css.
  3. На их основе вычислить отношение.
  4. Использовать это отношение для расчета координат мыши и тача.

После этого все будет выглядеть красиво на HiDPI мониторах. Но есть одна “особенность” – увеличенный (в зависимости от отношения размеров css и canvas) в несколько раз фреймбуфер. При отношении равном 2, получаем размер фреймбуфера в четыре раза больший, со всеми вытекающими.

Немного кода

CSS

canvas {
    width: 100vw;
    height: 100vh;
    display: block;
}

JavaScript

window.addEventListener('resize', resizeCanvas, false);

function resizeCanvas() {
    var realToCSSPixels = window.devicePixelRatio;

    var displayWidth  = Math.floor(canvas.clientWidth  * realToCSSPixels);
    var displayHeight = Math.floor(canvas.clientHeight * realToCSSPixels);

    if (canvas.width !== displayWidth || canvas.height !== displayHeight) {
        canvas.width  = displayWidth;
        canvas.height = displayHeight;
    }
}

resizeCanvas();

C++

int width, height;
emscripten_get_canvas_element_size(nullptr, &width, &height);

double cssWidth, cssHeight;
emscripten_get_element_css_size(nullptr, &cssWidth, &cssHeight);

const auto ratiox = (float)(width / cssWidth);
const auto ration = (float)(height / cssHeight);

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

История поиска одного бага

Debugging Довольно много времени потратил на поиск “плавающего” бага. За это время успел отрефакторить кучу кода, до которого руки не доходили ранее. Но баг не ловился. И в его поимке не смогли помочь ни Xcode Instruments, ни Xcode Analyzer (фронтэнд к статическому анализатору llvm).

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

Падения игры под отладчиком и backtrace давали BAD EXC, что как бы намекало на испорченную где-то ранее память. Но где именно? Статический анализатор, по идее, должен на раз находить access out of bounds. Но анализатор молчал, типа вообще все пучком.

От безысходности и обиды на самого себя, решил синхронизировать линуксовую версию с main branch, т.к. в процессе поиска бага был сделан серьезный рефакторинг кода. Ну и очевидно, что погонять движок под valgrind никогда лишним не будет.
И valgrind сразу же нашел memory corruption (тот самый “плавающий” баг, на поиски которого я убил много времени. И мелкий ничего не значащий memory leak.

Linux и valgrind рулят!

Emscripten: события клавиатуры в iframe

Столкнулся с проблемой на itch.io, когда приложение запущенной внутри iframe не получает события клавиатуры. Придумал вот такой workaround:

postRun: (function() {
                window.addEventListener('mousedown', function(evt) {
                    window.focus();
                    // evt.preventDefault();
                    evt.stopPropagation();
                    evt.target.style.cursor = 'default';
                }, false);
            })(),

К событию postRun добавляем установку листенера на событие mousedown. Теперь при клике мышью на канавасе с игрой события от клавиатуры будут передаваться в наше приложение.

Way of Tanks

Way of Tanks Way of Tanks – это танковый ранер с бесконечным геймплеем и разнообразной трассой. Игрок свайпами (или кнопками клавиатуры, или жестами на пульте Apple TV) управляет танком. Задача игрока преодолеть как можно большую дистанцию не столкнувшись с препятствиями и не погибнув в бою с боссами. Так может перемещаться с дорожки на дорожку, стрелять и перепрыгивать рвы (да, вот такой современный танк). В игре есть различные поверапы, которые временно улучшают характеристики танка – маневренность, супер-снаряд, удвоение собранных денег, способность пробивать препятствия. Так же игрок может приобрести, за собранные во время гонки деньги, новый улучшенный танк. Всего в игре четыре танка, которые отличаются по характеристикам и возможностям.
» Read more

1 2