Microsoft — мировой лидер в области ПО и ИТ-услуг
170,08
рейтинг
9 декабря 2014 в 17:20

Разработка → Как использовать GamePad в браузере и в приложениях для Windows на HTML и JavaScript? tutorial

Если вы разрабатываете игры на HTML и JavaScript, то эта статья для вас. Мы уже много писали о том, что под Windows 8.x можно разрабатывать приложения на HTML/JS, причем, как правило, вы можете с легкостью просто взять и использовать ваш текущий движок, работающий в современных браузерах.



Просто в качестве примера: если вы делаете платформер, то вы можете воспользоваться таким движком, как Phaser (кстати, он поддерживает разработку на TypeScript!), или, нашим Platformer Game StarterKit для Windows 8. К слову, если вы хотите сделать игрушку в жанре Tower Defense, то у нас есть еще один Starter Kit. А если вы хотите создать что-то трехмерное с использованием WebGL, то наше все для вас – это Babylon.js.


GamePad


Но в этой статье я не буду рассказывать, как создать саму игру. Мы зададимся другим вопросом: как подключить к игре для Windows 8.x или в браузере геймпад? Например, игровой контроллер от Xbox 360 или Xbox One:



Будем считать, что вы уже подключили сам геймпад к своему ПК (инструкция для Xbox 360, инструкция для Xbox One). Теперь давайте разберемся, что вам нужно сделать, чтобы добавить его поддержку в своей игре.

В качестве примера я буду использовать платформер RubbaRabbit из приведенного выше стартет-кита. Мы рассмотрим два варианта: игра для Windows 8.x и игра в браузере.


Игра для Windows 8.x на HTML и JavaScript


Чтобы добавить поддержку геймпада в игру на JavaScript под Windows 8.x вам понадобится научиться работать с интерфейсами XInput. Это может звучать страшновато, потому что для этого нужно погрузиться в код на C++, но мы уже сделали практически все, что вам нужно, чтобы не пересекаться с ними напрямую.

Для работы вам нужно скачать пример XInput and JavaScript controller sketch. Внутри него вы легко найдете папочку с кодом на C++, в которой находится проект библиотеки-обвязки над XInput, с которой вы в свою очередь сможете работать в своей игре на JavaScript.



Этот проект вам нужно добавить в свой солюшн с игрой и добавить ссылку на него внутри проекта для Windows 8.x:



При желании вы можете залезть внутрь файлов на C++ и выяснить, что они фактически выставляют наружу очень простой интерфейс доступа к контроллеру: конструктор для получения ссылки на геймпад и функцию getState для получения его текущего состояния с проекцией на кнопки геймпада Xbox.

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

Игровой цикл


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

В моем случае игровой цикл задается внутри функции update:

/**
 * game simulation loop step - called every frame during play
 */
this.update = function () {
...
}


Где-то внутри этой функции есть обработка нажатий на кнопки, которая выглядит примерно так:

if (touchleft || jaws.pressed("left") || jaws.pressed("a")) { 
    player.vx = -move_speed; player.flipped = 1; 
}
else if (touchright || jaws.pressed("right") || jaws.pressed("d")) { 
    player.vx = +move_speed; player.flipped = 0; 
}

if (!player.attacking && (touchjump || jaws.pressed("up") || jaws.pressed("w") || jaws.pressed("space"))) { 
    if (!player.jumping && player.can_jump) { 
        sfxjump(); 
        player.vy = jump_strength; 
        player.jumping = true; 
        player.can_jump = false; 
    } 
}
else { 
    player.can_jump = true; 
}


Как вы можете заметить, разработчики движка уже позаботились о том, что пользователь может передавать команды не только с разных кнопок с клавиатуры, но и, например, с виртуальных кнопок на сенсорном устройстве (переменные touchleft, touchright и т.п.).

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

Поддержка геймпада


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

Для инициализации контроллера мы создаем объект Controller через конструктор, доступный нам из подключенной ранее библиотеки на C++:

//Add Xbox Contoller support    
function initXboxpad() {
    var controller = new GameController.Controller(0);

    if (controller != null) {
        updateState();
    }

    ...
}


Далее нам нужно с определенной периодичностью обновлять состояние контроллера, для этого опишем функцию updateState, которая будет запрашивать вызов себя на каждый кадр анимации:


//Add Xbox Contoller support    
function initXboxpad() {
    var controller = new GameController.Controller(0);

    // render loop
    if (controller != null) {
        updateState();
    }

    function updateState() {
        var state = controller.getState();

        if (state.connected) {
            var x = state.leftThumbX / 32767;

            touchleft = (x < -0.9);
            touchright = (x > 0.9);

            touchjump = state.a;
            touchattack = state.x;
            touchpause = state.start;
        }
        window.requestAnimationFrame(updateState);
    }     
}


Это весь(!) код, который необходимо добавить в игрушку, чтобы она научилась взаимодействовать с геймпадом от Xbox 360. Не забудьте только при старте вызвать саму функцию initXboxpad.



Обратите внимание, что в данном случае мы «эксплуатируем» уже существующие переменные, аккумулирующие в себе команды от возможного сенсорного интерфейса, и обновляем их в зависимости от того, каково текущее состояние элементов управления на геймпаде. Например, если игрок нажал кнопку «A», то соответствующее состояние state.a будет равно true и мы его проецируем на «прыжок» в игре.

Кстати, через функцию setState геймпада вы можете заставить его вибрировать.

Игра в браузере


Теперь давайте посмотрим, что мы можем сделать в браузере. Для браузеров в W3C разрабатывается специальный стандарт Gamepad API, который позволит единообразно работать с разными типами игровых геймпадов.

Стандарт предполагает, что есть некоторая «общая модель», к которой можно свести разные игровые контроллеры:


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

В сам стандарт в этой статье погружаться не буду, благо в интернете уже есть достаточное количество обзорных статьей. Например, вот документация от Mozilla. Единственное, что хочу тут отметить – это то, что она устарела относительно предположения, что Gamepad API не поддерживает в Internet Explorer. На самом деле, в свежих сборках Internet Explorer 11 Gamepad API уже поддерживается.

В контексте данной статьи про стандарт нужно знать только одно: он предоставляет доступ к сырым данным, разбитым по осям и нумерованным кнопкам. Чтобы понять реальное соответствие, вам нужно будет проделать определенные умственные операции в своем коде.

Игровой цикл и код игры




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



Все остальное пока остается неизменными, и верны те же самые предположения про игровой цикл, которые мы делали для проекта под Windows 8.

Поддержка геймпада


Чтобы упростить себе работу с геймпадом, я воспользуюсь готовым кодом из библиотеки Babylon.js – babylon.gamepads.ts (GitHub). Вы можете просто скопировать библиотеку себе или сделать ее форк.

Библиотека делает несколько важных вещей:
  • умеет поверх Gamepad API симулировать событийную модель (если вам вдруг нужно);
  • упрощает доступ к отдельными элементами контроллера (например, объединяет оси джойстика в один объект);
  • различает контроллер Xbox, делая необходимое мне отображение обобщенных кнопок на конкретные.

Обратите внимание, что библиотека написана на TypeScript. Рядом вы также можете найти скомпилированную версию для JavaScript. В моем случае я просто добавляю библиотеку внутрь проекта, Visual Studio включает поддержку TypeScript и автоматически генерирует js-файлы при сохранении.

Не забудьте подключить библиотеку на страницу с игрой:
<script src="js/babylon.gamepads.js"></script>


Далее схема подключения геймпада очень похожа на то, что мы делали в случае с Windows 8.x:

   //Add Xbox Contoller support 
    function initGamePad() {
        var xboxpad;
        function updateState() {
            if (xboxpad != null && xboxpad.browserGamepad.connected) {
                xboxpad.update();
                touchleft = (xboxpad.leftStick.x < -0.9);
                touchright = (xboxpad.leftStick.x > 0.9);
                touchjump = (xboxpad.buttonA == 1);
                touchattack = (xboxpad.buttonX == 1);
                touchpause = (xboxpad.buttonStart == 1);
            }
            window.requestAnimationFrame(updateState);
        }
        var gamepadConnected = function (gamepad) {
            if (gamepad instanceof BABYLON.Xbox360Pad) {
                xboxpad = gamepad;
                updateState();
            }
        };
        var gamepads = new BABYLON.Gamepads(gamepadConnected);
    }


Внутрь функции BABYLON.Gamepads передается обработчик события подключения геймпада у компьютеру. Как видите, добавление в проект поддежки геймпада – это примерно 20 строчек кода!

Вариант кода с событийной моделью:
    //Add Xbox Contoller support 
    function initGamePad() {
        var xboxpad;
        var gamepadConnected = function (gamepad) {
            if (gamepad instanceof BABYLON.Xbox360Pad) {
                xboxpad = gamepad;
                xboxpad.onleftstickchanged(function (values) {
                    var x = values.x;
                    touchleft = (x < -0.9);
                    touchright = (x > 0.9);
                });
                xboxpad.onbuttondown(function (button) {
                    switch (button) {
                        case BABYLON.Xbox360Button.A: 
                            touchjump = true;
                            break;
                        case BABYLON.Xbox360Button.X: 
                            touchattack = true;
                            break;
                        case BABYLON.Xbox360Button.Start: 
                            touchpause = true;
                            break;
                    }
                });

                xboxpad.onbuttonup(function (button) {
                    switch (button) {
                        case BABYLON.Xbox360Button.A: 
                            touchjump = false;
                            break;
                        case BABYLON.Xbox360Button.X: 
                            touchattack = false;
                            break;
                        case BABYLON.Xbox360Button.Start: 
                            touchpause = false;
                            break;
                    }
                });
            }
        };
        var gamepads = new BABYLON.Gamepads(gamepadConnected);
    }


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


Полезные ссылки


Автор: @kichik
Microsoft
рейтинг 170,08
Microsoft — мировой лидер в области ПО и ИТ-услуг

Комментарии (3)

  • +1
    А есть какие-нибудь демки онлайн? Чтобы открыть браузер и проверить, работает ли геймпад.
  • 0
    Только недавно писал интерфейс для геймпада) В бейонд привязка к вендору, отдельные кнопки не обработаешь, нагрузка на обработку состояния синхронно с рендером, немного излишний опрос состояний. О том как и почему всё в статье =)

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

Самое читаемое Разработка