From e92cd1de28fa8e9420124b688683be4835145dd8 Mon Sep 17 00:00:00 2001 From: bbupton Date: Mon, 7 Aug 2023 17:47:06 -0700 Subject: [PATCH] Kinematic rigid bodies --- examples/physics/src/Models.js | 106 ++++++++++++++++++++++++++++----- examples/physics/src/Views.js | 9 +-- packages/rapier/src/Rapier.js | 29 ++++++--- 3 files changed, 115 insertions(+), 29 deletions(-) diff --git a/examples/physics/src/Models.js b/examples/physics/src/Models.js index 77889e50..d46304d3 100644 --- a/examples/physics/src/Models.js +++ b/examples/physics/src/Models.js @@ -3,7 +3,7 @@ import { ModelRoot, Actor, mix, AM_Spatial, sphericalRandom, v3_scale, v3_add, v3_sub, v3_normalize} from "@croquet/worldcore"; import { RAPIER, RapierManager, AM_RapierWorld, AM_RapierRigidBody} from "@croquet/worldcore-rapier"; -import { SprayPawn, FountainPawn } from "./Views"; +// import { SprayPawn, FountainPawn } from "./Views"; function rgb(r, g, b) { return [r/255, g/255, b/255]; @@ -14,7 +14,7 @@ function rgb(r, g, b) { //------------------------------------------------------------------------------------------ class SprayActor extends mix(Actor).with(AM_Spatial, AM_RapierRigidBody) { - get pawn() {return SprayPawn} + get pawn() {return "SprayPawn"} get shape() {return this._shape || "cube"} get index() { return this._index || 0 } @@ -29,23 +29,23 @@ class SprayActor extends mix(Actor).with(AM_Spatial, AM_RapierRigidBody) { buildCollider() { let cd; - switch(this.shape) { + switch (this.shape) { case "cone": cd = RAPIER.ColliderDesc.cone(0.5, 0.5); - cd.setDensity(4) + cd.setDensity(4); break; case "ball": cd = RAPIER.ColliderDesc.ball(0.5); - cd.setDensity(2) + cd.setDensity(2); break; case "cylinder": cd = RAPIER.ColliderDesc.cylinder(0.5, 0.5); - cd.setDensity(1.5) + cd.setDensity(1.5); break; - case"cube": + case "cube": default: cd = RAPIER.ColliderDesc.cuboid(0.5, 0.5, 0.5); - cd.setDensity(1) + cd.setDensity(1); break; } @@ -56,6 +56,80 @@ class SprayActor extends mix(Actor).with(AM_Spatial, AM_RapierRigidBody) { } SprayActor.register('SprayActor'); +//------------------------------------------------------------------------------------------ +//-- BlockActor ---------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------ + +class BlockActor extends mix(Actor).with(AM_Spatial, AM_RapierRigidBody) { + + get pawn() {return "SprayPawn"} + + get shape() {return this._shape || "cube"} + get index() { return this._index || 0 } + + init(options) { + super.init(options); + + this.buildCollider(); + + this.subscribe("input", "zDown", this.goLeft); + this.subscribe("input", "xDown", this.goRight); + } + + buildCollider() { + let cd; + switch (this.shape) { + case "cone": + cd = RAPIER.ColliderDesc.cone(0.5, 0.5); + cd.setDensity(4); + break; + case "ball": + cd = RAPIER.ColliderDesc.ball(0.5); + cd.setDensity(2); + break; + case "cylinder": + cd = RAPIER.ColliderDesc.cylinder(0.5, 0.5); + cd.setDensity(1.5); + break; + case "cube": + default: + cd = RAPIER.ColliderDesc.cuboid(0.5, 0.5, 0.5); + cd.setDensity(1); + break; + } + + this.createCollider(cd); + + } + + // init(options) { + // super.init(options); + + // console.log("new block"); + + // this.subscribe("input", "zDown", this.goLeft); + // this.subscribe("input", "xDown", this.goRight); + // } + + goLeft() { + console.log("left"); + const translation = [...this.translation]; + translation[0] -= 0.1; + this.set({translation}); + } + + goRight() { + console.log("right"); + const translation = [...this.translation]; + translation[0] += 0.1; + this.set({translation}); + } + +} +BlockActor.register('BlockActor'); + + + //------------------------------------------------------------------------------------------ //-- FountainActor ------------------------------------------------------------------------ //------------------------------------------------------------------------------------------ @@ -63,7 +137,7 @@ SprayActor.register('SprayActor'); // class TestActor extends mix(Actor).with(AM_Spatial) {} class FountainActor extends mix(Actor).with(AM_Spatial, AM_RapierWorld, AM_RapierRigidBody) { - get pawn() {return FountainPawn} + get pawn() {return "FountainPawn"} init(options) { super.init(options); @@ -90,12 +164,12 @@ class FountainActor extends mix(Actor).with(AM_Spatial, AM_RapierWorld, AM_Rapie cd.translation = new RAPIER.Vector3(0,0,-24); this.createCollider(cd); - this.subscribe("ui", "shoot", this.doShoot) + this.subscribe("ui", "shoot", this.doShoot); this.future(1000).spray(); } - get max() { return this._max || 50}; + get max() { return this._max || 50} spray() { this.spawn(); @@ -103,7 +177,7 @@ class FountainActor extends mix(Actor).with(AM_Spatial, AM_RapierWorld, AM_Rapie } spawn() { - const type = this.random() + const type = this.random(); let shape = "cube"; if (type > 0.4) shape = "cylinder"; @@ -121,10 +195,10 @@ class FountainActor extends mix(Actor).with(AM_Spatial, AM_RapierWorld, AM_Rapie } doShoot(gun) { - const aim = v3_normalize(v3_sub([0,15,0], gun)) + const aim = v3_normalize(v3_sub([0,15,0], gun)); const shape = "cube"; const index = Math.floor(this.random()*20); - const translation = v3_add(gun, [0,0,0]) + const translation = v3_add(gun, [0,0,0]); const bullet = SprayActor.create({parent: this, shape, index, translation, rigidBodyType: "dynamic"}); const force = v3_scale(aim, 40); const spin = v3_scale(sphericalRandom(),Math.random() * 0.5); @@ -151,9 +225,9 @@ export class MyModelRoot extends ModelRoot { console.log("Start root model!!"); this.seedColors(); - console.log(RapierManager); + this.fountain = FountainActor.create({gravity: [0,-9.8,0], timestep:50, translation: [0,0,0], max: 200, rigidBodyType: "static"}); - this.fountain = FountainActor.create({gravity: [0,-9.8,0], timestep:15, translation: [0,0,0], max: 200, rigidBodyType: "static"}); + this.block = BlockActor.create({parent: this.fountain, translation: [0,1,5], rigidBodyType: "kinematic", index: 2}); } seedColors() { diff --git a/examples/physics/src/Views.js b/examples/physics/src/Views.js index 07fc538c..6eadd9b6 100644 --- a/examples/physics/src/Views.js +++ b/examples/physics/src/Views.js @@ -24,6 +24,7 @@ export class SprayPawn extends mix(Pawn).with(PM_Smoothed, PM_ThreeInstanced) { this.useInstance(this.actor.shape + this.actor.index); } } +SprayPawn.register("SprayPawn"); //------------------------------------------------------------------------------------------ //-- FountainPawn ------------------------------------------------------------------------- @@ -58,6 +59,7 @@ export class FountainPawn extends mix(Pawn).with(PM_Spatial, PM_ThreeVisible) { this.setRenderObject(group); } } +FountainPawn.register("FountainPawn"); //------------------------------------------------------------------------------------------ //-- GodView ------------------------------------------------------------------------------- @@ -80,13 +82,12 @@ class GodView extends ViewService { this.subscribe("input", "pointerDelta", this.doPointerDelta); } - updateCamera() { if (this.paused) return; const rm = this.service("ThreeRenderManager"); - const pitchMatrix = m4_rotation([1,0,0], pitch) - const yawMatrix = m4_rotation([0,1,0], yaw) + const pitchMatrix = m4_rotation([1,0,0], pitch); + const yawMatrix = m4_rotation([0,1,0], yaw); let cameraMatrix = m4_translation([0,0,50]); cameraMatrix = m4_multiply(cameraMatrix,pitchMatrix); @@ -122,7 +123,7 @@ class GodView extends ViewService { if (this.paused) return; if (!this.dragging) return; yaw += -0.01 * e.xy[0]; - yaw = yaw % TAU; + yaw %= TAU; pitch += -0.01 * e.xy[1]; pitch = Math.min(pitch, toRad(-15)); pitch = Math.max(pitch, toRad(-90)); diff --git a/packages/rapier/src/Rapier.js b/packages/rapier/src/Rapier.js index 4b4fd6a3..3c918dc4 100644 --- a/packages/rapier/src/Rapier.js +++ b/packages/rapier/src/Rapier.js @@ -73,8 +73,8 @@ export const AM_RapierWorld = superclass => class extends superclass { this.world.free(); } - get timeStep() {return this._timeStep || 50;} - get gravity() {return this._gravity || [0,-9.8,0];} + get timeStep() {return this._timeStep || 50} + get gravity() {return this._gravity || [0,-9.8,0]} createRigidBody(actor, rbd) { const rb = this.world.createRigidBody(rbd); @@ -131,9 +131,10 @@ export const AM_RapierRigidBody = superclass => class extends superclass { let rbd; switch (this.rigidBodyType) { + default: + case "dynamic": rbd = RAPIER.RigidBodyDesc.newDynamic(); break; case "static": rbd = RAPIER.RigidBodyDesc.newStatic(); break; - case "dynamic": - default: rbd = RAPIER.RigidBodyDesc.newDynamic(); + case "kinematic": rbd = RAPIER.RigidBodyDesc.newKinematicPositionBased(); break; } rbd.setCcdEnabled(this.ccdEnabled); rbd.translation = new RAPIER.Vector3(...this.translation); @@ -147,17 +148,27 @@ export const AM_RapierRigidBody = superclass => class extends superclass { this.worldActor.destroyRigidBody(this.rigidBodyHandle); } - get rigidBodyType() { return this._rigidBodyType || "dynamic";} - get ccdEnabled() { return this._ccdEnabled === undefined ? true : this._ccdEnabled; } - get velocity() { return this._velocity || [0,0,0];} - get acceleration() { return this._acceleration || [0,0,0];} - get hasAccelerometer() { return this._hasAccelerometer;} + get rigidBodyType() { return this._rigidBodyType || "dynamic"} + get ccdEnabled() { return this._ccdEnabled === undefined ? true : this._ccdEnabled } + get velocity() { return this._velocity || [0,0,0]} + get acceleration() { return this._acceleration || [0,0,0]} + get hasAccelerometer() { return this._hasAccelerometer} get rigidBody() { + if (!this.worldActor) return null; if (!this.$rigidBody) this.$rigidBody = this.worldActor.getRigidBody(this.rigidBodyHandle); return this.$rigidBody; } + translationSet() { + if (this.rigidBodyType !== "kinematic") return; + if (this.rigidBody) this.rigidBody.setNextKinematicTranslation(new RAPIER.Vector3(...this.translation)); + } + rotationSet() { + if (this.rigidBodyType !== "kinematic") return; + if (this.rigidBody) this.rigidBody.setNextKinematicRotation(new RAPIER.Vector3(...this.rotation)); + } + getWorldActor() { let actor = this; do {