@croquet/microverse-library
Version:
An npm package version of Microverse
155 lines (132 loc) • 5.61 kB
JavaScript
// Copyright 2022 by Croquet Corporation, Inc. All Rights Reserved.
// https://croquet.io
// info@croquet.io
/*
This is a wrapper to call Rapier Physics Engine features. It is expected to be used
a user-defined behavior module that creates a rigid body and a
collider description. (see behaviors/default/cascade.js for an
example.)
*/
// the following import statement is solely for the type checking and
// autocompletion features in IDE. A Behavior cannot inherit from
// another behavior or a base class but can use the methods and
// properties of the card to which it is installed.
// The prototype classes ActorBehavior and PawnBehavior provide
// the features defined at the card object.
import {ActorBehavior} from "../PrototypeBehavior";
class PhysicsActor extends ActorBehavior {
teardown() {
this.removeImpulseJoint();
this.removeCollider();
this.removeRigidBody();
delete this._myPhysicsWorld;
// _myPhysicsWorld is there so that a destroyed card, which lost its parent
// property when this teardown is executed, still removes itself from the physics world.
}
getRigidBody() {
/*
A "dollar-property" is a special model-side property naming
convention which excludes the data to be stored in the
snapshot. In this case, rigidBody is a cache to hold onto
the rigidBody object.
When a user joins an existing session, the snapshot will not
contain this.$rigidBody. So it is lazily initialized when it
is accessed.
The implementation of PhysicsManager is in src/physics2.js.
*/
if (!this.$rigidBody) {
if (this.rigidBodyHandle === undefined) return undefined;
const physicsWorld = this.physicsWorld;
if (!physicsWorld || !physicsWorld.world) {return undefined;}
this.$rigidBody = physicsWorld.world.getRigidBody(this.rigidBodyHandle);
}
return this.$rigidBody;
}
createRigidBody(rbd) {
this.removeRigidBody();
rbd.translation = new Microverse.Physics.Vector3(...this.translation);
rbd.rotation = new Microverse.Physics.Quaternion(...this.rotation);
this._myPhysicsWorld = this.physicsWorld;
this.$rigidBody = this._myPhysicsWorld.world.createRigidBody(rbd);
this.rigidBodyHandle = this.$rigidBody.handle;
this._myPhysicsWorld.rigidBodies.set(this.rigidBodyHandle, this._target);
/*
Those events are handled so that when a position-based object
was moved from the user program, the object's position and
rotatino in the simulation are updated.
*/
if (this.getRigidBody().bodyType() === Microverse.Physics.RigidBodyType.KinematicPositionBased) {
this.listen("translationSet", "Physics$PhysicsActor.setKinematicTranslation");
this.listen("rotationSet", "Physics$PhysicsActor.setKinematicRotation");
}
}
setKinematicTranslation(data) {
this.getRigidBody().setNextKinematicTranslation(new Microverse.Physics.Vector3(...data.v));
}
setKinematicRotation(data) {
this.getRigidBody().setNextKinematicRotation(new Microverse.Physics.Quaternion(...data.v));
}
removeRigidBody() {
let r = this.getRigidBody();
if (!r) return;
const physicsWorld = this._myPhysicsWorld;
if (!physicsWorld) {return;}
physicsWorld.world.removeRigidBody(r);
physicsWorld.rigidBodies.delete(this.rigidBodyHandle)
delete this.rigidBodyHandle;
delete this.$rigidBody;
}
createCollider(cd) {
this.removeCollider();
const physicsWorld = this.physicsWorld;
this._myPhysicsWorld = physicsWorld;
let collider = physicsWorld.world.createCollider(cd, this.getRigidBody());
this.colliderHandle = collider.handle;
return this.colliderHandle;
}
removeCollider() {
if (this.colliderHandle === undefined) return;
const physicsWorld = this._myPhysicsWorld;
if (!physicsWorld) {return;}
let world = physicsWorld.world;
let collider = world.getCollider(this.colliderHandle);
if (collider) {
world.removeCollider(collider);
}
delete this.colliderHandle;
}
createImpulseJoint(type, body1, body2, ...params) {
this.removeImpulseJoint();
const physicsWorld = this.physicsWorld;
if (!physicsWorld) {return;}
this._myPhysicsWorld = physicsWorld;
// compatibility with Rapier 0.7.3 based spec
if (type === "ball") {type = "spherical";}
let func = Microverse.Physics.JointData[type];
if (!func) {throw new Error("unkown joint types");}
let jointParams = func.call(Microverse.Physics.JointData, ...params);
let joint = physicsWorld.world.createImpulseJoint(jointParams, body1.rigidBody, body2.rigidBody);
this.jointHandle = joint.handle;
return this.jointHandle;
}
removeImpulseJoint() {
if (this.jointHandle === undefined) return;
const physicsWorld = this._myPhysicsWorld;
if (!physicsWorld) {return;}
let world = physicsWorld.world;
let joint = world.getImpulseJoint(this.jointHandle);
if (joint) {
world.removeJoint(joint);
}
delete this.jointHandle;
}
}
export default {
modules: [
{
name: "Physics",
actorBehaviors: [PhysicsActor]
}
]
}
/* globals Microverse */