Reputation: 826
This previous question & answer explain how to move a dynamic body in A-Frame physics system, by using the syncToPhysics() method call after making changes to position. How to translate A-Frame dynamic body
I've been using this technique, and it works well for me when using the CANNON.js driver.
See e.g. https://unmarred-ambiguous-shad.glitch.me/
However, I would like to use the Ammo driver, as described here. https://github.com/n5ro/aframe-physics-system/blob/master/AmmoDriver.md
(one key reason for wanting to use the Ammo driver is that at this time, CANNON.js does not work with A-Frame 1.2+ https://github.com/n5ro/aframe-physics-system/issues/187 ).
My hope was that I could do the same thing with syncToPhysics() on the ammo-body component:
this.el.components["ammo-body"].syncToPhysics();
But I tried to do so in this glitch, and it's not working - the body is just stuck in one place. https://roasted-snow-replace.glitch.me/
Is there any way to get this function working with Ammo, or is it impossible to directly manipulate the position of dynamic bodies when using the Ammo driver?
Upvotes: 1
Views: 2560
Reputation: 616
I created a fork of the aframe-physics-system
package to make it at least partially compatible with A-Frame 1.2.
Here is the updated file:
https://github.com/gearcoded/aframe-physics-system/blob/master/dist/aframe-physics-system.js
I didn't test everything, but the scene editor, gravity, and collision work.
Upvotes: 1
Reputation: 14655
This isn't elegant, but the only solution I found to "teleport" an object is to:
syncToPhysics()
when using aframe physics)updateCollisionFlags()
when using aframe physics)Something like here:
<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/[email protected]/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>
Upvotes: 3
Reputation: 826
One possible solution is to directly set a Linear Velocity in Ammo. This eliminates the need to update the physics engine with the new position data.
Due to friction the block will slow down, so you need to keep setting it for a constant velocity (also probably possible to configure materials to eliminate friction).
Also the tick function starts firing before Ammo WASM is fully initialized, and if you try to create a new Ammo.btVector3 too soon, this hits an error.
After some experimentation, it looks like checking for the existence of Ammo.asm.$ is a good way of determining when the WASM stuff is ready. But there may be a better solution here.
tick: function(time, timeDelta) {
// Ammo WASM takes a moment to initialize.
// Don't try to do anything that involves creating Ammo objects until
// Ammo.asm.$ exists.
if (Ammo.asm.$) {
const velocity = new Ammo.btVector3(1, 0, 0);
this.el.body.setLinearVelocity(velocity);
Ammo.destroy(velocity);
}
}
New glitch including this solution...
https://pinto-big-pecorino.glitch.me/
A couple of references I used to help with this answer: BulletPhysics (ammo.js) - How would you go about applying force to an object?
https://github.com/n5ro/aframe-physics-system/blob/master/AmmoDriver.md#using-the-ammojs-api
Upvotes: 2