A-FRAME扩展组件

时间:2018-02-19 14:09:48

标签: aframe

考虑一下:

<a-entity id="player">
    <a-entity id="camera" camera look-controls></a-entity>
    <a-entity id="leftHand" oculus-touch-controls="hand: left"></a-entity>
    <a-entity id="rightHand" oculus-touch-controls="hand: right"></a-entity>
</a-entity>

如果我想将我的播放器移动到场景中,我会将wasd-controls添加到#player。这样做,忽略头部的方向(camera):W始终移动&#34;北&#34;,无论你在哪里看。如果我将wasd-controls添加到#camera,则磁头移动正确,但控制器会被遗忘。

所以我考虑创建一个自定义wasd-controls,但我无法扩展该组件。我成功地复制并粘贴了所有代码,但这非常令人讨厌。

这不起作用:AFrame extend component and override

有什么想法吗?

MY-WASD-controls.js

var KEYCODE_TO_CODE = require('aframe/src/constants').keyboardevent.KEYCODE_TO_CODE;
var AFRAME = require('aframe');
var THREE = require('aframe/src/lib/three');
var utils = require('aframe/src/utils');

var bind = utils.bind;
var shouldCaptureKeyEvent = utils.shouldCaptureKeyEvent;

var CLAMP_VELOCITY = 0.00001;
var MAX_DELTA = 0.2;
var KEYS = [
    'KeyW', 'KeyA', 'KeyS', 'KeyD',
    'ArrowUp', 'ArrowLeft', 'ArrowRight', 'ArrowDown'
];

/**
 * WASD component to control entities using WASD keys.
 */
module.exports.Component = AFRAME.registerComponent('my-wasd-controls', {
    schema: {
        acceleration: {default: 65},
        adAxis: {default: 'x', oneOf: ['x', 'y', 'z']},
        adEnabled: {default: true},
        adInverted: {default: false},
        easing: {default: 20},
        enabled: {default: true},
        fly: {default: false},
        head: {type: 'selector'},
        wsAxis: {default: 'z', oneOf: ['x', 'y', 'z']},
        wsEnabled: {default: true},
        wsInverted: {default: false}
    },

    init: function () {
        // To keep track of the pressed keys.
        this.keys = {};

        this.position = {};
        this.velocity = new THREE.Vector3();

        // Bind methods and add event listeners.
        this.onBlur = bind(this.onBlur, this);
        this.onFocus = bind(this.onFocus, this);
        this.onKeyDown = bind(this.onKeyDown, this);
        this.onKeyUp = bind(this.onKeyUp, this);
        this.onVisibilityChange = bind(this.onVisibilityChange, this);
        this.attachVisibilityEventListeners();
    },

    tick: function (time, delta) {
        var currentPosition;
        var data = this.data;
        var el = this.el;
        var movementVector;
        var position = this.position;
        var velocity = this.velocity;

        if (!velocity[data.adAxis] && !velocity[data.wsAxis] &&
            isEmptyObject(this.keys)) { return; }

        // Update velocity.
        delta = delta / 1000;
        this.updateVelocity(delta);

        if (!velocity[data.adAxis] && !velocity[data.wsAxis]) { return; }

        // Get movement vector and translate position.
        currentPosition = el.getAttribute('position');
        movementVector = this.getMovementVector(delta);
        position.x = currentPosition.x + movementVector.x;
        position.y = currentPosition.y + movementVector.y;
        position.z = currentPosition.z + movementVector.z;
        el.setAttribute('position', position);
    },

    remove: function () {
        this.removeKeyEventListeners();
        this.removeVisibilityEventListeners();
    },

    play: function () {
        this.attachKeyEventListeners();
    },

    pause: function () {
        this.keys = {};
        this.removeKeyEventListeners();
    },

    updateVelocity: function (delta) {
        var acceleration;
        var adAxis;
        var adSign;
        var data = this.data;
        var keys = this.keys;
        var velocity = this.velocity;
        var wsAxis;
        var wsSign;

        adAxis = data.adAxis;
        wsAxis = data.wsAxis;

        // If FPS too low, reset velocity.
        if (delta > MAX_DELTA) {
            velocity[adAxis] = 0;
            velocity[wsAxis] = 0;
            return;
        }

        // Decay velocity.
        if (velocity[adAxis] !== 0) {
            velocity[adAxis] -= velocity[adAxis] * data.easing * delta;
        }
        if (velocity[wsAxis] !== 0) {
            velocity[wsAxis] -= velocity[wsAxis] * data.easing * delta;
        }

        // Clamp velocity easing.
        if (Math.abs(velocity[adAxis]) < CLAMP_VELOCITY) { velocity[adAxis] = 0; }
        if (Math.abs(velocity[wsAxis]) < CLAMP_VELOCITY) { velocity[wsAxis] = 0; }

        if (!data.enabled) { return; }

        // Update velocity using keys pressed.
        acceleration = data.acceleration;
        if (data.adEnabled) {
            adSign = data.adInverted ? -1 : 1;
            if (keys.KeyA || keys.ArrowLeft) { velocity[adAxis] -= adSign * acceleration * delta; }
            if (keys.KeyD || keys.ArrowRight) { velocity[adAxis] += adSign * acceleration * delta; }
        }
        if (data.wsEnabled) {
            wsSign = data.wsInverted ? -1 : 1;
            if (keys.KeyW || keys.ArrowUp) { velocity[wsAxis] -= wsSign * acceleration * delta; }
            if (keys.KeyS || keys.ArrowDown) { velocity[wsAxis] += wsSign * acceleration * delta; }
        }
    },

    getMovementVector: (function () {
        var directionVector = new THREE.Vector3(0, 0, 0);
        var rotationEuler = new THREE.Euler(0, 0, 0, 'YXZ');

        return function (delta) {
            var rotation = (this.data.head || this.el).getAttribute('rotation');
            var velocity = this.velocity;
            var xRotation;

            directionVector.copy(velocity);
            directionVector.multiplyScalar(delta);

            // Absolute.
            if (!rotation) { return directionVector; }

            xRotation = this.data.fly ? rotation.x : 0;

            // Transform direction relative to heading.
            rotationEuler.set(THREE.Math.degToRad(xRotation), THREE.Math.degToRad(rotation.y), 0);
            directionVector.applyEuler(rotationEuler);
            return directionVector;
        };
    })(),

    attachVisibilityEventListeners: function () {
        window.addEventListener('blur', this.onBlur);
        window.addEventListener('focus', this.onFocus);
        document.addEventListener('visibilitychange', this.onVisibilityChange);
    },

    removeVisibilityEventListeners: function () {
        window.removeEventListener('blur', this.onBlur);
        window.removeEventListener('focus', this.onFocus);
        document.removeEventListener('visibilitychange', this.onVisibilityChange);
    },

    attachKeyEventListeners: function () {
        window.addEventListener('keydown', this.onKeyDown);
        window.addEventListener('keyup', this.onKeyUp);
    },

    removeKeyEventListeners: function () {
        window.removeEventListener('keydown', this.onKeyDown);
        window.removeEventListener('keyup', this.onKeyUp);
    },

    onBlur: function () {
        this.pause();
    },

    onFocus: function () {
        this.play();
    },

    onVisibilityChange: function () {
        if (document.hidden) {
            this.onBlur();
        } else {
            this.onFocus();
        }
    },

    onKeyDown: function (event) {
        var code;
        if (!shouldCaptureKeyEvent(event)) { return; }
        code = event.code || KEYCODE_TO_CODE[event.keyCode];
        if (KEYS.indexOf(code) !== -1) { this.keys[code] = true; }
    },

    onKeyUp: function (event) {
        var code;
        code = event.code || KEYCODE_TO_CODE[event.keyCode];
        delete this.keys[code];
    }
});

function isEmptyObject (keys) {
    var key;
    for (key in keys) { return false; }
    return true;
}

1 个答案:

答案 0 :(得分:2)

我仍然建议复制并粘贴它。如果您以后升级过A-Frame,并且更改了控件,那么您的扩展可能会中断。

更改原型应该有效(例如/login)。原型方法是可写的。

另一种方法是覆盖组件实例上的方法。 AFRAME.components['wasd-controls'].Component.prototype.foo = () => {}