Статьи

Введение в API геймпада HTML5

По мере того, как популярность HTML-игр постепенно растет, поставщики начинают внедрять новые захватывающие API, чтобы сделать игры немного приятнее как для нас, разработчиков, так и для наших конечных игроков. Одним из них является GamepadAPI, который позволяет подключить старый добрый консольный геймпад к компьютеру и использовать его для игр на основе браузера, в стиле «подключи и работай». Давайте погрузимся в!


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

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

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


Как я уже упоминал, API-интерфейс Gamepad еще не доступен для публичного выпуска, поэтому вам нужно сначала получить себе Nightly-сборку Firefox и убедиться, что у вас установлено дополнение Firebug (только для целей отладки).

Кроме того, вы не можете забыть геймпад! Я собираюсь использовать контроллер PlayStation 3 для этого урока, но контроллер Xbox подойдет просто отлично.

После того, как вы установили Nightly и добавили Firebug, вы готовы к работе!

(NB. Последние сборки Chromium также имеют поддержку Gamepad API, но это руководство не было проверено на них.)


Давайте начнем с базового HTML-файла (index.html) с источником «gamepad.js» (пустой файл JavaScript).

index.html

01
02
03
04
05
06
07
08
09
10
11
12
<!doctype html>
<html>
  <head>
    <meta charset=»utf-8″>
    <title>Introduction to the Gamepad API</title>
  </head>
  <body>
    <h1>Gamepad API</h1>
 
    <script src=»gamepad.js»></script>
  </body>
</html>

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

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

1
2
3
4
5
function gamepadConnected(evt)
{
  console.log(evt);
}
window.addEventListener(‘MozGamepadConnected’, gamepadConnected);

Запустите ваш index.html в Nightly и откройте консоль Firebug, здесь мы сможем увидеть запись события из нашей функции обратного вызова.

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

Зарегистрированное событие подключения геймпада

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


Не менее важно знать, был ли отключен геймпад, поэтому давайте посмотрим на событие «MozGamepadDisconnected».

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

1
2
3
4
5
function gamepadDisconnected(evt)
{
  console.log(evt);
}
window.addEventListener(‘MozGamepadDisconnected’, gamepadDisconnected);

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

Зарегистрированное событие отключения геймпада

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
var gamepadActive = false;
 
function gamepadConnected(evt)
{
  console.log(evt);
  gamepadActive = true;
}
function gamepadDisconnected(evt)
{
  console.log(evt);
  gamepadActive = false;
}
 
window.addEventListener(‘MozGamepadConnected’, gamepadConnected);
window.addEventListener(‘MozGamepadDisconnected’, gamepadDisconnected);

Нажатие кнопок, опять же, использует прослушиватель событий и функцию обратного вызова с двумя событиями, «MozGamepadButtonDown» и «MozGamepadButtonUp».

Я бы посоветовал регистрировать все событие по нажатию кнопки, чтобы посмотреть, что происходит, но ключевая информация, которую мы должны получить от этого события, — evt.button . Это числовой идентификатор кнопки, которая была нажата.

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

1
2
3
4
5
6
function buttonPressed(evt, pressed)
{
  console.log(evt.button, pressed);
}
window.addEventListener(«MozGamepadButtonDown», function(evt) { buttonPressed(evt, true); } );
window.addEventListener(«MozGamepadButtonUp», function(evt) { buttonPressed(evt, false); } );

Теперь должны выводиться идентификаторы кнопок, которые были нажаты, и были ли они нажаты или отпущены (true для кнопки вниз, false для кнопки вверх).

Зарегистрированные идентификаторы кнопок

Далее мы создадим массив со всеми кнопками PlayStation 3. Индексы массива будут сопоставлены с идентификаторами, используемыми на этом геймпаде, значениями которых будет название кнопки.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
var gamepadActive = false,
    ps3Buttons = new Array();
 
ps3Buttons[12] = ‘triangle’,
ps3Buttons[15] = ‘square’,
ps3Buttons[14] = ‘cross’,
ps3Buttons[13] = ‘circle’,
ps3Buttons[4] = ‘up’,
ps3Buttons[7] = ‘left’,
ps3Buttons[6] = ‘down’,
ps3Buttons[5] = ‘right’,
ps3Buttons[10] = ‘L1’,
ps3Buttons[8] = ‘L2’,
ps3Buttons[11] = ‘R1’,
ps3Buttons[9] = ‘R2’,
ps3Buttons[1] = ‘L3’,
ps3Buttons[2] = ‘R3’,
ps3Buttons[16] = ‘PS’,
ps3Buttons[0] = ‘select’,
ps3Buttons[3] = ‘start’;

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

Если теперь мы buttonPressed() функцию buttonPressed() , мы сможем легко определить, какая кнопка на контроллере была нажата.

1
2
3
4
function buttonPressed(evt, pressed)
{
  console.log(ps3Buttons[evt.button] + ‘ was pressed’);
}

Попробуй! Нажатие кнопок на вашем контроллере теперь должно регистрировать название нажимаемых кнопок. Это будет намного легче понять, чем «кнопка 5» (которая, в моем случае, находится на D-pad).


Обнаружение событий оси в основном отслеживает расположение левой и правой аналоговых джойстиков на геймпаде, используя событие «MozGamepadAxisMove».

Добавьте новый обработчик событий и функцию обратного вызова.

1
2
3
4
function moveAnalogSticks(evt) {
  console.log(evt.axis, evt.value);
}
window.addEventListener(«MozGamepadAxisMove», moveAnalogSticks);

Это то, что мы получаем — сбивает с толку, верно?

Зарегистрированные идентификаторы кнопок

Есть только одно событие, запущенное обеими аналоговыми палками; каждое событие дает нам одну из четырех возможных осей и значение от -1,0 до +1,0. Оси 0 и 1 принадлежат левой аналоговой ручке, а оси 2 и 3 — правой.

Зарегистрированные идентификаторы кнопок

На диаграмме выше вы увидите, что оси 0 и 2 соответствуют оси x, а 1 и 3 соответствуют оси y. Используя оси x и y для каждого отдельного аналогового джойстика, вы можете определить, в какую сторону направлен аналоговый джойстик!

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


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

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


Чтобы запустить небольшую демонстрацию, создайте элемент canvas в html-файле с идентификатором «game» и установите ширину 600 и высоту 540. Как вы, возможно, знаете, элемент canvas обычно используется для рендеринга HTML-игр. на.

Вы также захотите скопировать изображения «ship.png» и «space.jpg» из исходной загрузки в вашу рабочую папку, поскольку они будут отображаться на холсте. В качестве альтернативы, найдите свою графику, чтобы поиграть!

01
02
03
04
05
06
07
08
09
10
11
12
<!doctype html>
<html>
  <head>
    <meta charset=»utf-8″>
    <title>Introduction to the Gamepad API</title>
  </head>
  <body>
    <h1>Gamepad API</h1>
    <canvas id=»game» width=»600″ height=»540″></canvas>
    <script src=»gamepad.js»></script>
  </body>
</html>

Теперь, когда элемент canvas находится в нашей DOM, мы хотим создать игровой цикл для рендеринга нашей игры.

Я использую прокладку для «requestAnimationFrame» Пола Айриша, которая станет основой для нашего цикла. Затем мы получаем 2D-контекст canvas который мы будем использовать для рисования и создания двух новых объектов изображения, одного для фона и одного для нашего космического корабля.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
window.requestAnimFrame = (function(){
  return window.requestAnimationFrame ||
          window.webkitRequestAnimationFrame ||
          window.mozRequestAnimationFrame ||
          window.oRequestAnimationFrame ||
          window.msRequestAnimationFrame ||
          function(/* function */ callback, /* DOMElement */ element){
            window.setTimeout(callback, 1000 / 60);
          };
})();
 
var canvas = document.getElementById(‘game’),
    ctx = canvas.getContext(‘2d’),
    ship = new Image(),
    space = new Image();
 
space.src = «space.jpg»;
ship.src = «ship.png»;

Далее объект игрока. Он имеет координаты x и y, которые отслеживают, где он должен появиться на холсте; четыре направления (вверх, вниз, влево и вправо), чтобы мы могли знать, в каком направлении движется корабль; функция render() , которая сначала вызывает updatePosition() а затем рисует изображение корабля на холсте на основе координат x и y, и, наконец, сама updatePosition() , которая проверяет, какой способ установки корабля двигаться и обновляет свою позицию соответственно.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
var player = {
  x: 200,
  y: 250,
  up: false,
  down: false,
  left: false,
  right: false,
  render: function() {
    this.updatePosition();
    ctx.drawImage(ship,this.x,this.y);
  },
  updatePosition: function() {
    this.up ?
    this.down ?
    this.left ?
    this.right ?
  }
}

После этого у нас есть функция renderGame, которая сначала рисует изображение космического фона на canvas , а затем рисует наш космический корабль.

И наконец наш цикл. Эта функция вызывает себя снова и снова, каждый раз вызывая нашу функцию renderGame.

01
02
03
04
05
06
07
08
09
10
function renderGame()
{
  ctx.drawImage(space,0,0);
  player.render();
}
 
;(function animloop(){
  requestAnimFrame(animloop);
  renderGame();
})();

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


В нашем коде игрока мы назвали четыре кнопки, которыми мы хотим управлять нашим кораблем. Они соответствуют именам кнопок внутри массива ps3Buttons[] . Итак, все, что нам нужно сделать, это buttonPressed() изменить нашу buttonPressed() и мы будем двигаться.

1
2
3
4
5
6
7
8
var player = {
  …
  up: false,
  down: false,
  left: false,
  right: false,
  …
}

Теперь, когда кнопка геймпада нажата или отпущена, она устанавливает свое состояние в объекте игрока, поэтому, когда нажата кнопка «вверх», будет установлен player.up = true/false .

1
2
3
4
5
function buttonPressed(evt, pressed)
{
  console.log(evt.button, pressed);
  player[ps3Buttons[evt.button]] = pressed ?
}

Возвращайтесь к своей демонстрации, и вы сможете перемещать свой корабль!


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

Сначала давайте создадим новый массив keys[] и keyCode свойства keyCode клавиш со стрелками клавиатуры с эквивалентными кнопками на геймпаде. Это позволит нам повторно использовать buttonPressed() которую использует геймпад.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var gamepadActive = false,
    ps3Buttons = new Array(),
    keys = new Array();
 
ps3Buttons[12] = ‘triangle’,
ps3Buttons[15] = ‘square’,
ps3Buttons[14] = ‘cross’,
ps3Buttons[13] = ‘circle’,
ps3Buttons[4] = ‘up’,
ps3Buttons[7] = ‘left’,
ps3Buttons[6] = ‘down’,
ps3Buttons[5] = ‘right’,
ps3Buttons[10] = ‘L1’,
ps3Buttons[8] = ‘L2’,
ps3Buttons[11] = ‘R1’,
ps3Buttons[9] = ‘R2’,
ps3Buttons[1] = ‘L3’,
ps3Buttons[2] = ‘R3’,
ps3Buttons[16] = ‘PS’,
ps3Buttons[0] = ‘select’,
ps3Buttons[3] = ‘start’;
 
keys[38] = 4;
keys[37] = 7;
keys[40] = 6;
keys[39] = 5;

Теперь нам нужны слушатели событий onkeyup и onkeydown для клавиш со стрелками. Когда клавиша нажата или отпущена, мы убеждаемся, что геймпад не используется. Затем мы не позволяем клавише со стрелкой выполнять свою обычную задачу (в этом случае прокручиваем окно браузера вверх или вниз), а затем вызываем ту же buttonPressed() которую вызывает геймпад.

Для этого передается ложный объект события с ключом «keyCode», сопоставленным с элементом в массиве keys[] , который, в свою очередь, передает соответствующий идентификатор кнопки геймпада.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
window.onkeydown = function(evt)
  {
    if (gamepadActive == false)
    {
      evt.preventDefault();
      buttonPressed({ button: keys[evt.keyCode] }, true);
    }
  }
window.onkeyup = function(evt)
  {
    if (gamepadActive == false)
    {
      evt.preventDefault();
      buttonPressed({ button: keys[evt.keyCode] }, false);
    }
  }

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


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

Быстрое испытание для тех из вас, у кого есть контроллер, отличный от PS3 Dual Shock: отрегулируйте отображение кнопок в зависимости от того, какой контроллер подключен.

Спасибо, что нашли время, чтобы узнать об API Gamepad. Если у вас есть какие-либо вопросы, пожалуйста, оставьте их в комментариях.