Если вы разрабатываете игры на 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);
}
В результате мы легко можем управлять действиями героя в игре прямо с подключенного геймпада:
Полезные ссылки
- Стартер-киты для игр на JS под Windows 8: Platfromer, Tower Defense
- XInput + JavaScript – пример для Windows 8
- W3C GamePad API – черновик стандарта для браузеров
- babylon.gamepads.ts – обертка над GamePad API
- Курс по разработке универсальных приложений на HTML/JS (En)
- Загрузить бесплатную или пробную Visual Studio
- Стать разработчиком универсальных приложений Windows
- Программа Windows Insider — доступ к превью Windows 10
Автор: kichik