首页 > 解决方案 > 使用 Ammo 驱动程序时,如何使用 A-Frame 物理系统移动动态物体?

问题描述

这个先前的问题和答案解释了如何在 A-Frame 物理系统中移动动态物体,方法是在更改位置后使用 syncToPhysics() 方法调用。 如何翻译 A-Frame 动态体

我一直在使用这种技术,并且在使用 CANNON.js 驱动程序时对我来说效果很好。

参见例如https://unmarred-ambiguous-shad.glitch.me/

但是,我想使用 Ammo 驱动程序,如此处所述。 https://github.com/n5ro/aframe-physics-system/blob/master/AmmoDriver.md

(想要使用 Ammo 驱动程序的一个关键原因是,目前 CANNON.js 不适用于 A-Frame 1.2+ https://github.com/n5ro/aframe-physics-system/issues/187)。

我希望我可以在 ammo-body 组件上使用 syncToPhysics() 做同样的事情:

this.el.components["ammo-body"].syncToPhysics();

但我试图在这个故障中这样做,但它不起作用 - 身体只是卡在一个地方。 https://roasted-snow-replace.glitch.me/

有什么方法可以让这个功能与 Ammo 一起工作,或者在使用 Ammo 驱动程序时无法直接操纵动态物体的位置?

标签: aframeammo.js

解决方案


这并不优雅,但我发现“传送”对象的唯一解决方案是:

  • 将身体碰撞标志设置为 KINEMATIC (2) - 否则子弹只是忽略运动状态更新
  • 应用新位置(通过syncToPhysics()使用框架物理时)
  • 重置身体速度,因此物体不会在传送后立即反弹
  • 恢复原始标志(通过updateCollisionFlags()使用框架物理时)

像这里的东西:

<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script src="https://mixedreality.mozilla.org/ammo.js/builds/ammo.wasm.js"></script>
<script src="https://cdn.jsdelivr.net/gh/n5ro/aframe-physics-system@v4.0.1/dist/aframe-physics-system.js"></script>

<script>
  AFRAME.registerComponent("moving-dynamic-body", {
    init: function() {
        // wait until the physics engine is ready
        this.el.addEventListener("body-loaded", e => {
          // cache the ammo-body component
          this.ammoComponent = this.el.components["ammo-body"];
          // use this vector to zero the velocity
          // keep in mind this needs to be deleted manually from the memory with Ammo.destroy(this.zeroSpeed)
          this.zeroSpeed = new Ammo.btVector3(0, 0, 0);
        });
      }

      ,
    tick: function() {
      // wait for the physics 
      if (!this.ammoComponent) return;
      
      // restore stuff if the "teleport magic" has been done in the last renderloop.
      // this should probably be done in steps instead of tick
      if (this.collisionFlag === 2) {
        // this just tells us that we reverted to normal
        this.collisionFlag = 0;
        // restore the original collision flags
        this.ammoComponent.updateCollisionFlags();
        // reset the speed, or the body will bounce away
        this.ammoComponent.body.setLinearVelocity(this.zeroSpeed);
      }
   
      // if the body is below 1m
      if (this.el.object3D.position.y < 1) {
        // set the THREEJS position.y
        this.el.object3D.position.y = 2;
        // change the collision flag to the KINEMATIC_BODY
        this.collisionFlag = 2;
        // apply the flag
        this.ammoComponent.body.setCollisionFlags(this.collisionFlag);
        // sync the physisc transforms to the THREEJS transform
        this.ammoComponent.syncToPhysics();
      }
    }
  });
</script>

<a-scene physics="driver: ammo; debug: true; debugDrawMode: 1;" renderer="colorManagement:true">
  <a-box id="test1" ammo-body="type: dynamic" ammo-shape="type: box" material="color:#dd1111" height="0.1" width="0.1" depth="0.1" position="0 2 -1" moving-dynamic-body>
  </a-box>
</a-scene>


推荐阅读