【问题标题】:Event listener 'componentchanged' is only firing for 'rotation' and not 'position'事件侦听器“componentchanged”仅针对“旋转”而不是“位置”触发
【发布时间】:2018-06-30 03:05:57
【问题描述】:

当尝试使用componentchanged 事件侦听器检测相机位置的移动时,我只能在将evt.detail.name 输出到控制台时检测到旋转。

要使用键盘在场景中移动相机,我使用的是A-Frame Extras library

这是我使用的仅输出旋转的代码...

Javascript:

document.addEventListener("DOMContentLoaded", function(event)
{
        document.querySelector("a-entity[camera]").addEventListener("componentchanged", function (evt)
        {
                // The console message outputs 'rotation' and never outputs 'position'
                console.log("Event name: " + evt.detail.name); 
            if(evt.detail.name === "position")
            {
                console.log("Camera has moved from " + evt.oldData + " to " + evt.newData); 
            }
            else
            {
                 console.log("position has not changed"); 
            }
        });
});

HTML:

<a-entity id="rig" movement-controls position="0 0 0">
      <a-entity camera position="0 1.6 0" look-controls="pointerLockEnabled:false"></a-entity>
</a-entity>

【问题讨论】:

    标签: aframe


    【解决方案1】:

    使用刻度功能检查相机装置上的位置变化:

    tick: function () {
      var rigEl = this.el;
      var currentPosition = rigEl.object3D.position;
      // Compare to this.lastPosition (a vector3 you create)
      this.lastPosition.copy(rigEl.object3D.position); 
    }
    

    【讨论】:

    • 我不想使用tick函数只是因为出于我们的目的,我不想进行连续轮询。我的解决方案发布在之前的评论中。感谢您的帮助。
    • 仓位几乎总是会移动,刻度函数可以忽略不计。如果需要,您可以限制它 (AFRAME.utils.throttleTick)。我不建议对更新如此频繁的东西使用 DOM 事件。您的解决方案已关闭,因为按下键时位置会改变......不仅仅是在keydown上。对于偶然发现此线程的未来读者,请使用此解决方案。
    • 当我使用tick 选项时,如果我不移动相机,输出到控制台时,我看到 X、Y 和 Z 位置保持不变。出于我的目的,我希望在按住 键时更新位置,也可以在 keydown 上。我取消选中我的答案作为首选答案,因为我的情况将与其他偶然发现此线程的情况不同。
    • 我不同意,这不是情境性的。 tick 函数是硬 DOM keydown 事件检测位置变化的最佳实践。这就是游戏引擎的工作方式。其他东西可以修改位置而不仅仅是按键,它非常特定于 WASD 控件。
    【解决方案2】:

    必须同意 - 勾选答案不是一个很好的解决方案。而不是在事件发生时调用函数代码(在这种情况下是更改相机位置),而是连续调用刻度函数(我猜是通过 setInterval)导致很多不必要的处理。这不仅仅是 setInterval 上的 tick 函数调用,还有最终开发人员在该函数中放置的任何代码(是的,您可以通过将相机的位置存储在 tick 函数中并不断将其与新的比较位置,所以代码只在位置变化时执行——但你为什么要为这一切烦恼,当在实际位置变化时触发事件可以为你省去麻烦?)

    Keydown 有它自己的缺点(很明显,移动设备上的 AFrame 不使用 keydown - 你必须锁定 touchstart 或其他东西),但它仍然比替代方案更好。

    【讨论】:

    • 不是通过 setInterval,而是一个 requestAnimationFrame 将所有其他的 tick 调用批处理在一起。 keydown 是不好的做法。如果添加其他改变位置的控件会发生什么?如果另一个组件改变了装备的位置会发生什么?一个 keydown 监听器,你无法控制它被调用的频率,直到 DOM,它不是很好。用户几乎总是在移动,尤其是在 VR 中,无论如何它都会被调用。如果没有任何变化,则处理可以忽略不计。
    • 很高兴听到它的 requestAnimationFrame。比我想象的要好。至于当另一个组件改变位置时会发生什么——是的;你是 100% 正确的——这种方法绝对是个问题。但这也是我认为应该在库(AFrame)级别处理的更多原因。我不认为相机位置变化的通知是如此不寻常的用例,它们应该被推送到用户代码(但 YMMV)。奇怪的是,事件是为旋转更改事件设置的,那么为什么你会全力以赴,而不是位置更新呢?理想情况下,你会同时拥有(或只是一个相机移动事件)
    • 在 VR 中,摄像机位置在不断变化,这是多余的。正如我所说,游戏引擎会轮询。更不用说,您有时甚至不想检测局部位置,而是使用世界矩阵检测全局位置……旋转也是如此。鼠标事件是非常不稳定的、糟糕的实践和非通用的解决方案。
    • 我不是在谈论鼠标事件——我是在谈论在相机位置变化时有 AFrame 触发事件(它似乎没有这样做,它只对相机旋转变化这样做)。这将与控制器无关。虽然我不会在游戏引擎上不同意你的观点,但请理解这不是 AFrame 的唯一用途。
    • 它不会这样做,因为运动控制组件连接到并更改了装备的位置,而不是相机。为什么相机会在其本地变换或其组件数据发生更改时触发事件。这就是您使用刻度线的原因,因为您可能需要考虑多级变换并保证在每一帧上检查它,而不管场景结构和父组件如何。而且因为事件有开销/不可预测。这与 A-Frame 的“使用”无关。此外,A-Frame 本质上是一个游戏(或实时)引擎,这是事实(我们共同创建了 A-Frame)。
    【解决方案3】:

    我能够解决这个问题。您可以执行以下操作...

    document.addEventListener("DOMContentLoaded", function(event)
    {
        var cameraEl = document.querySelector("#camera");
        var worldPos = new THREE.Vector3();
    
        function getCameraPosition() 
        {
            worldPos.setFromMatrixPosition(cameraEl.object3D.matrixWorld);
            console.log("Position: " + worldPos.x + " " + worldPos.y + " " + worldPos.z);
        }
    
        document.addEventListener("keydown", function(evt) 
        {
            // check if keys pressed are W, A, S, D and Up, Down, Left, Right
            if (evt.keyCode == 87 || evt.keyCode == 65 || evt.keyCode == 83 || evt.keyCode == 63 || evt.keyCode == 38 || evt.keyCode == 37 || evt.keyCode == 39 || evt.keyCode == 40)
            {
                getCameraPosition();
            }
        });     
    });
    

    您还需要为您的相机添加一个 ID...

    <a-entity id="rig" movement-controls position="0 0 0">
      <a-entity id="camera" camera position="0 1.6 0" look-controls="pointerLockEnabled:false"></a-entity>
    </a-entity>
    

    【讨论】:

      猜你喜欢
      • 2020-09-06
      • 2015-12-18
      • 1970-01-01
      • 2013-05-19
      • 1970-01-01
      • 2012-01-08
      • 1970-01-01
      • 1970-01-01
      • 2021-01-14
      相关资源
      最近更新 更多