Newer
Older
reroad-test / 2020-ryusei / aframe-master / src / components / generic-tracked-controller-controls.js
@ryusei ryusei on 22 Oct 2020 5 KB パノラマ表示
var registerComponent = require('../core/component').registerComponent;
var bind = require('../utils/bind');

var trackedControlsUtils = require('../utils/tracked-controls');
var checkControllerPresentAndSetup = trackedControlsUtils.checkControllerPresentAndSetup;
var emitIfAxesChanged = trackedControlsUtils.emitIfAxesChanged;
var onButtonEvent = trackedControlsUtils.onButtonEvent;

var GAMEPAD_ID_PREFIX = 'generic';

/**
 * Button indices:
 * 0 - trigger
 * 1 - squeeze
 * 2 - touchpad
 * 3 - thumbstick
 *
 * Axis:
 * 0 - touchpad
 * 1 - thumbstick
 *
 */
var INPUT_MAPPING = {
  axes: {
    touchpad: [0, 1],
    thumbstick: [2, 3]
  },
  buttons: ['trigger', 'squeeze', 'touchpad', 'thumbstick']
};

/**
 * Oculus Go controls.
 * Interface with Oculus Go controller and map Gamepad events to
 * controller buttons: trackpad, trigger
 * Load a controller model and highlight the pressed buttons.
 */
module.exports.Component = registerComponent('generic-tracked-controller-controls', {
  schema: {
    hand: {default: ''},  // This informs the degenerate arm model.
    defaultModel: {default: true},
    defaultModelColor: {default: 'gray'},
    orientationOffset: {type: 'vec3'}
  },

  /**
   * Button IDs:
   * 0 - trackpad
   * 1 - trigger
   */
  mapping: INPUT_MAPPING,

  bindMethods: function () {
    this.onControllersUpdate = bind(this.onControllersUpdate, this);
    this.checkIfControllerPresent = bind(this.checkIfControllerPresent, this);
    this.removeControllersUpdateListener = bind(this.removeControllersUpdateListener, this);
    this.onAxisMoved = bind(this.onAxisMoved, this);
  },

  init: function () {
    var self = this;
    this.onButtonChanged = bind(this.onButtonChanged, this);
    this.onButtonDown = function (evt) { onButtonEvent(evt.detail.id, 'down', self); };
    this.onButtonUp = function (evt) { onButtonEvent(evt.detail.id, 'up', self); };
    this.onButtonTouchStart = function (evt) { onButtonEvent(evt.detail.id, 'touchstart', self); };
    this.onButtonTouchEnd = function (evt) { onButtonEvent(evt.detail.id, 'touchend', self); };
    this.controllerPresent = false;
    this.lastControllerCheck = 0;
    this.rendererSystem = this.el.sceneEl.systems.renderer;
    this.bindMethods();
  },

  addEventListeners: function () {
    var el = this.el;
    el.addEventListener('buttonchanged', this.onButtonChanged);
    el.addEventListener('buttondown', this.onButtonDown);
    el.addEventListener('buttonup', this.onButtonUp);
    el.addEventListener('touchstart', this.onButtonTouchStart);
    el.addEventListener('touchend', this.onButtonTouchEnd);
    el.addEventListener('axismove', this.onAxisMoved);
    this.controllerEventsActive = true;
  },

  removeEventListeners: function () {
    var el = this.el;
    el.removeEventListener('buttonchanged', this.onButtonChanged);
    el.removeEventListener('buttondown', this.onButtonDown);
    el.removeEventListener('buttonup', this.onButtonUp);
    el.removeEventListener('touchstart', this.onButtonTouchStart);
    el.removeEventListener('touchend', this.onButtonTouchEnd);
    el.removeEventListener('axismove', this.onAxisMoved);
    this.controllerEventsActive = false;
  },

  checkIfControllerPresent: function () {
    var data = this.data;
    var hand = data.hand ? data.hand : undefined;
    checkControllerPresentAndSetup(
      this, GAMEPAD_ID_PREFIX,
      {hand: hand, iterateControllerProfiles: true});
  },

  play: function () {
    this.checkIfControllerPresent();
    this.addControllersUpdateListener();
  },

  pause: function () {
    this.removeEventListeners();
    this.removeControllersUpdateListener();
  },

  injectTrackedControls: function () {
    var el = this.el;
    var data = this.data;
    // Do nothing if tracked-controls already set.
    // Generic controls have the lowest precedence.
    if (this.el.components['tracked-controls']) { return; }
    el.setAttribute('tracked-controls', {
      hand: data.hand,
      idPrefix: GAMEPAD_ID_PREFIX,
      orientationOffset: data.orientationOffset,
      iterateControllerProfiles: true
    });
    if (!this.data.defaultModel) { return; }
    this.initDefaultModel();
  },

  addControllersUpdateListener: function () {
    this.el.sceneEl.addEventListener('controllersupdated', this.onControllersUpdate, false);
  },

  removeControllersUpdateListener: function () {
    this.el.sceneEl.removeEventListener('controllersupdated', this.onControllersUpdate, false);
  },

  onControllersUpdate: function () {
    this.checkIfControllerPresent();
  },

  onButtonChanged: function (evt) {
    var button = this.mapping.buttons[evt.detail.id];
    if (!button) return;
    // Pass along changed event with button state, using button mapping for convenience.
    this.el.emit(button + 'changed', evt.detail.state);
  },

  onAxisMoved: function (evt) {
    emitIfAxesChanged(this, this.mapping.axes, evt);
  },

  initDefaultModel: function () {
    var modelEl = this.modelEl = document.createElement('a-entity');
    modelEl.setAttribute('geometry', {
      primitive: 'sphere',
      radius: 0.03
    });
    modelEl.setAttribute('material', {color: this.data.color});
    this.el.appendChild(modelEl);
  }
});