Получение событий кнопок и осей

В A-Frame взаимодействие с VR-контроллерами осуществляется через компоненты tracked-controls и их производные, а также через события, которые генерируются при нажатии кнопок или движении стиков. Контроллеры передают данные о кнопках, триггерах, тачпадах и аналоговых осях, что позволяет реализовать сложное взаимодействие с виртуальной средой.


Основные события контроллеров

Каждый контроллер A-Frame поддерживает стандартные события:

  • buttondown – срабатывает при нажатии кнопки. Возвращает объект события с информацией о том, какая кнопка была нажата.
  • buttonup – срабатывает при отпускании кнопки.
  • axismove – фиксирует движение стика или трекпада. Значение осей передается в виде массива [x, y] с диапазоном от -1 до 1.
  • thumbstickmoved – специализированное событие для стиков Oculus и других контроллеров.

События могут быть привязаны как к отдельным сущностям, так и к сцене через компонент a-entity.

Пример привязки события к кнопке:

<a-entity id="rightHand"
          oculus-touch-controls="hand: right"></a-entity>
const rightHand = document.querySelector('#rightHand');

rightHand.addEventListener('buttondown', (evt) => {
  console.log('Нажата кнопка:', evt.detail.id);
});

rightHand.addEventListener('axismove', (evt) => {
  const [x, y] = evt.detail.axis;
  console.log('Ось стика:', x, y);
});

В объекте события evt.detail содержится информация о:

  • id – идентификатор кнопки (trigger, grip, thumbstick, touchpad и т.д.);
  • state – текущее состояние кнопки (pressed, touched, value);
  • axis – массив с координатами осей [x, y].

Отличия между кнопками и осями

Кнопки в A-Frame делятся на:

  • Digital buttons – кнопки с бинарным состоянием (pressed: true/false).
  • Analog buttons – триггеры или сенсорные кнопки, где значение value варьируется от 0 до 1.

Оси используются для стиков и тачпадов и возвращают координаты движения. Для стика центр всегда [0, 0], при смещении значения изменяются в пределах -1 до 1.

Пример обработки триггера с плавной величиной:

rightHand.addEventListener('buttondown', (evt) => {
  if (evt.detail.id === 'trigger') {
    console.log('Значение триггера:', evt.detail.value);
  }
});

Привязка к конкретным контроллерам

A-Frame позволяет использовать платформенно-зависимые контроллеры, например:

  • oculus-touch-controls
  • vive-controls
  • windows-motion-controls

Каждый из этих компонентов автоматически генерирует стандартные события (buttondown, buttonup, axismove), но некоторые кнопки могут иметь разные идентификаторы в зависимости от устройства.

<a-entity id="leftHand" vive-controls="hand: left"></a-entity>
<a-entity id="rightHand" oculus-touch-controls="hand: right"></a-entity>
document.querySelector('#leftHand').addEventListener('buttondown', (evt) => {
  if (evt.detail.id === 'grip') {
    console.log('Зажат грип левой руки');
  }
});

Работа с осевыми событиями для навигации

Событие axismove идеально подходит для реализации перемещения персонажа или поворота камеры. В массиве [x, y]:

  • x > 0 – движение вправо
  • x < 0 – движение влево
  • y > 0 – движение вперед
  • y < 0 – движение назад

Пример движения персонажа по сцене:

const cameraRig = document.querySelector('#cameraRig');

rightHand.addEventListener('axismove', (evt) => {
  const [x, y] = evt.detail.axis;
  cameraRig.object3D.position.x += x * 0.1;
  cameraRig.object3D.position.z += y * 0.1;
});

Здесь значение оси умножается на коэффициент скорости, чтобы движение было плавным и управляемым.


Объединение событий кнопок и осей

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

  • Нажатие триггера – захват объекта
  • Стык тачпада – перемещение захваченного объекта
  • Кнопка grip – активация особых функций (телепортация, смена режима)

Пример комплексной обработки:

rightHand.addEventListener('buttondown', (evt) => {
  if (evt.detail.id === 'trigger') {
    grabObject();
  }
});

rightHand.addEventListener('axismove', (evt) => {
  const [x, y] = evt.detail.axis;
  moveObject(x, y);
});

Такой подход позволяет реализовать полноценное VR-взаимодействие без сложной логики низкоуровневого отслеживания состояний контроллера.


Полезные детали и оптимизация

  • Для многоплатформенных проектов рекомендуется использовать hand-controls, который автоматически подбирает подходящий контроллер.
  • События можно слушать на сцене (<a-scene>), чтобы обработка работала глобально для всех контроллеров.
  • Частота событий axismove высокая, поэтому важно оптимизировать обработку, чтобы не перегружать рендеринг.
AFRAME.registerComponent('axismove-logger', {
  init: function() {
    this.el.addEventListener('axismove', (evt) => {
      const [x, y] = evt.detail.axis;
      if (Math.abs(x) > 0.1 || Math.abs(y) > 0.1) {
        console.log('Активное движение:', x, y);
      }
    });
  }
});

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


Итоговый подход

Использование событий buttondown, buttonup и axismove совместно с компонентами контроллеров позволяет создавать интерактивные VR-приложения, где каждая кнопка и ось управляются напрямую через объект события. Это делает возможным как простые действия (нажатие кнопки), так и сложные механики (перемещение, вращение, захват объектов) без необходимости обращаться к низкоуровневым API WebXR.