diff --git a/package-lock.json b/package-lock.json index c1bc719..f46c140 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,7 @@ "vuetify": "^3.10.5" }, "devDependencies": { - "@dimforge/rapier3d": "^0.18.2", + "@dimforge/rapier3d": "^0.19.1", "@vitejs/plugin-vue": "^5.0.5", "eslint": "^8.57.0", "eslint-config-standard": "^17.1.0", @@ -283,9 +283,9 @@ } }, "node_modules/@dimforge/rapier3d": { - "version": "0.18.2", - "resolved": "https://registry.npmjs.org/@dimforge/rapier3d/-/rapier3d-0.18.2.tgz", - "integrity": "sha512-VM6f6L/1BVhvglTM67GlHmlI6Bw9NWcXzlLGoiZ7H1dOb86c6HJ9vIa6WDHThAfgN5B0c2oLeTAQ592BDPDzgA==", + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@dimforge/rapier3d/-/rapier3d-0.19.1.tgz", + "integrity": "sha512-pvAJXeeMtEif6OlmS4f+gJ5pj3qnLHTkJaIqiVhqDnqJPanwSkXd4DU12x4BcBPXc16pABr+cA7j17Cj86x1kw==", "dev": true, "license": "Apache-2.0" }, diff --git a/package.json b/package.json index 6de653e..bc285a1 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "vuetify": "^3.10.5" }, "devDependencies": { - "@dimforge/rapier3d": "^0.18.2", + "@dimforge/rapier3d": "^0.19.1", "@vitejs/plugin-vue": "^5.0.5", "eslint": "^8.57.0", "eslint-config-standard": "^17.1.0", diff --git a/public/static/meshes/maze-reed.bin b/public/static/meshes/maze-reed.bin index 3db612f..274fa68 100644 Binary files a/public/static/meshes/maze-reed.bin and b/public/static/meshes/maze-reed.bin differ diff --git a/public/static/meshes/maze-reed.gltf b/public/static/meshes/maze-reed.gltf index 23c33d2..006f219 100644 --- a/public/static/meshes/maze-reed.gltf +++ b/public/static/meshes/maze-reed.gltf @@ -34,6 +34,11 @@ 0, 0.7071068286895752 ], + "scale":[ + 1, + 1.0834307670593262, + 1 + ], "translation":[ 0.6499999761581421, 0, @@ -46,7 +51,7 @@ "translation":[ 0, 0, - -0.44999998807907104 + -0.6619032621383667 ] }, { @@ -247,13 +252,13 @@ "count":12, "max":[ 0.5994362831115723, - 0.6900395154953003, - 0.40000441670417786 + 0.8117803931236267, + 0.6000066995620728 ], "min":[ -0.6005637049674988, - 0.010013699531555176, - -0.3999955654144287 + 0.011780375614762306, + -0.5999934077262878 ], "type":"VEC3" }, diff --git a/src/components/InteractiveObjects/MazeQuizGame/MazeObject.js b/src/components/InteractiveObjects/MazeQuizGame/MazeObject.js index bc812a9..f52084b 100644 --- a/src/components/InteractiveObjects/MazeQuizGame/MazeObject.js +++ b/src/components/InteractiveObjects/MazeQuizGame/MazeObject.js @@ -1,4 +1,4 @@ -import { Group, Vector3, Matrix4, Mesh, DoubleSide } from 'three'; +import { Group, Vector3, Matrix4, Mesh, Quaternion, BoxGeometry } from 'three'; import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js'; import { TextObject } from '../TextObject'; @@ -12,7 +12,7 @@ class MazeObject { const scale = 5; context.wallSize = params.wallSize || .65*scale; - context.tubeSize = params.tubeSize || .8*scale; + context.tubeSize = params.tubeSize || 1.2*scale; context.wallDepth = params.wallDepth || .1*scale; context.fontPath = params.fontPath || '/static/fonts/ZapfChanceryC.otf'; @@ -61,12 +61,30 @@ class MazeObject { ] }); - engine.phy.add( - {position: room.localToWorld(new Vector3(context.tubeSize / 2 - cameraNear, 0, offsetZ + cameraNear))}, - 'fixed', false, undefined, 'cuboid',{ - width:offsetZ*10, height:10, depth:10 - } - ) + let quat = new Quaternion(); + room.getWorldQuaternion(quat); + + console.log('adding!!!', room.localToWorld(new Vector3(context.tubeSize / 2, 0.6, offsetZ/2)), quat) + + // const geometry = new BoxGeometry(2, 2, offsetZ); + // const cube = new Mesh(geometry, o.tunnel.material) + // cube.position.set(context.tubeSize / 2, 0.6, offsetZ/2) + // root.add(cube); + + // console.log(offsetZ, room.localToWorld(new Vector3(context.tubeSize / 2, 0.6, offsetZ/2))) + + let left = engine.phy.add( + {position: room.localToWorld(new Vector3(context.tubeSize / 2, 0.6, offsetZ/2))}, + 'fixed', false, undefined, 'cuboid',{ width: 0.01, height:1, depth:offsetZ/2 } + ) + left.rigidBody.setRotation(quat, true) + + // let right = engine.phy.add( + // {position: room.localToWorld(new Vector3(-context.tubeSize / 2, 0.6, offsetZ/2))}, + // 'fixed', false, undefined, 'cuboid',{ width: 0.01, height:1, depth:offsetZ/2 } + // ) + // right.rigidBody.setRotation(quat, true) + if (def.type == 'area') { def.area.forEach(ar => { @@ -148,7 +166,7 @@ class MazeObject { mazeMeshes.forEach(mesh=>{ //let mesh = new Mesh(mg, o.tunnel.material) root.add(mesh); - engine.phy.add(mesh, 'dynamic') + //engine.phy.add(mesh, 'fixed') }) console.log(o.tunnel) diff --git a/src/lib/CharacterControls.js b/src/lib/CharacterControls.js index d71df03..2e5e9b7 100644 --- a/src/lib/CharacterControls.js +++ b/src/lib/CharacterControls.js @@ -17,27 +17,43 @@ export class CharacterControls { walkVelocity = 3 lerp = (x, y, a) => x * (1 - a) + y * a; - constructor(model, mixer, animationsMap, orbitControl, camera, currentAction, ray, rigidBody, pointerControls) { + constructor(model, mixer, animationsMap, engine, currentAction, po, pointerControls) { this.model = model this.mixer = mixer this.animationsMap = animationsMap this.currentAction = currentAction this.animationsMap[currentAction].play() - this.ray = ray - this.rigidBody = rigidBody + this.characterController = engine.phy.world.createCharacterController(0.1); + this.characterController.setUp({x:0, y:1, z:0}); + po.rigidBody.setTranslation(this.model.position) + // this.characterController.enableSnapToGround(0.5); + // // Don’t allow climbing slopes larger than 45 degrees. + // this.characterController.setMaxSlopeClimbAngle(45 * Math.PI / 180); + // // Automatically slide down on slopes smaller than 30 degrees. + // this.characterController.setMinSlopeSlideAngle(30 * Math.PI / 180); + // this.characterController.enableAutostep(0.5, 0.2, true); + // this.characterController.setApplyImpulsesToDynamicBodies(true); + // this.characterController.setCharacterMass(50); + this.po = po; this.pointerControls = pointerControls - this.orbitControl = orbitControl - this.camera = camera + this.orbitControl = engine.orbitControls + this.camera = engine.camera this.updateCameraTarget(new THREE.Vector3(0,1,5)) + + this._v = new THREE.Vector3(); + this.velocity = new THREE.Vector3(); + this.forceDirection = new THREE.Vector3(); + this.forceAcceleration = 1 / 32; + this.forceSpeedMax = 0.075; } switchRunToggle() { this.toggleRun = !this.toggleRun } - update(world, delta, pointerControls) { + update0(world, delta, pointerControls) { const directionPressed = pointerControls.moving() var play = ''; @@ -86,51 +102,74 @@ export class CharacterControls { velocity = this.currentAction == 'run' ? this.runVelocity : this.walkVelocity } - const translation = this.rigidBody.translation(); - if (translation.y < -1) { - // don't fall below ground - this.rigidBody.setNextKinematicTranslation( { - x: 0, - y: 10, - z: 0 - }); - } else { - const cameraPositionOffset = this.camera.position.sub(this.model.position); - // update model and camera - this.model.position.x = translation.x - this.model.position.y = translation.y - this.model.position.z = translation.z - this.updateCameraTarget(cameraPositionOffset) - - this.walkDirection.y += this.lerp(this.storedFall, -9.81 * delta, 0.10) - this.storedFall = this.walkDirection.y - this.ray.origin.x = translation.x - this.ray.origin.y = translation.y - this.ray.origin.z = translation.z - let hit = world.castRay(this.ray, 0.5, false, 0xfffffffff); - if (hit) { - const point = this.ray.pointAt(hit.timeOfImpact); - let diff = translation.y - ( point.y + CONTROLLER_BODY_RADIUS); - if (diff < 0.0) { - this.storedFall = 0 - this.walkDirection.y = this.lerp(0, -diff, 0.5) - } - } - - this.walkDirection.x = this.walkDirection.x * velocity * delta - this.walkDirection.z = this.walkDirection.z * velocity * delta + this.walkDirection.x = this.walkDirection.x * velocity * delta + this.model.position.x + this.walkDirection.z = this.walkDirection.z * velocity * delta + this.model.position.z - this.rigidBody.setNextKinematicTranslation( { - x: translation.x + this.walkDirection.x, - y: translation.y + this.walkDirection.y, - z: translation.z + this.walkDirection.z - }); - } + //const translation = this.rigidBody.translation(); + //const translation = characterController.computedMovement(); + + this.characterController.computeColliderMovement( + this.po.collider, // The collider we would like to move. + this.walkDirection, // The movement we would like to apply if there wasn’t any obstacle. + ); + + // for (let i = 0; i < this.characterController.numComputedCollisions(); i++) { + // let collision = this.characterController.computedCollision(i); + // console.log('c', collision) + // // Do something with that collision information. + // } + + let correctedMovement = this.characterController.computedMovement(); + + this.po.rigidBody.setNextKinematicTranslation(correctedMovement); + //this.po.rigidBody.setNextKinematicRotation(this.rotateQuarternion); + + // if (translation.y < -1) { + // // don't fall below ground + // this.rigidBody.setNextKinematicTranslation( { + // x: 0, + // y: 10, + // z: 0 + // }); + // } else { + const cameraPositionOffset = this.camera.position.sub(this.model.position); + + this.model.position.copy(correctedMovement) + // // update model and camera + // this.model.position.x = translation.x + // this.model.position.y = translation.y + // this.model.position.z = translation.z + this.updateCameraTarget(cameraPositionOffset, correctedMovement) + + // this.walkDirection.y += this.lerp(this.storedFall, -9.81 * delta, 0.10) + // this.storedFall = this.walkDirection.y + // this.ray.origin.x = translation.x + // this.ray.origin.y = translation.y + // this.ray.origin.z = translation.z + // let hit = world.castRay(this.ray, 0.5, false, 0xfffffffff); + // if (hit) { + // const point = this.ray.pointAt(hit.timeOfImpact); + // let diff = translation.y - ( point.y + CONTROLLER_BODY_RADIUS); + // if (diff < 0.0) { + // this.storedFall = 0 + // this.walkDirection.y = this.lerp(0, -diff, 0.5) + // } + // } + + // this.walkDirection.x = this.walkDirection.x * velocity * delta + // this.walkDirection.z = this.walkDirection.z * velocity * delta + + // this.rigidBody.setNextKinematicTranslation( { + // x: translation.x + this.walkDirection.x, + // y: translation.y + this.walkDirection.y, + // z: translation.z + this.walkDirection.z + // }); + // } } - updateCameraTarget(offset) { + updateCameraTarget(offset, cm) { // move camera - const rigidTranslation = this.rigidBody.translation(); + const rigidTranslation = cm || this.po.rigidBody.translation(); this.camera.position.x = rigidTranslation.x + offset.x this.camera.position.y = rigidTranslation.y + offset.y this.camera.position.z = rigidTranslation.z + offset.z @@ -168,4 +207,66 @@ export class CharacterControls { return directionOffset } + update (world, delta, pointerControls){ + // Calculate input buffer + // if (this.jumpBuffer > 0) { + // this.jumpBuffer -= loop.delta; // ms + + // // Automatically jump if buffer is set + // if (this.allowJump === true) { + // this.jumpBuffer = 0; + // this.jump(); + // } + // } + + // Add fake friction and fake gravity + this.velocity.x *= 0.75; + this.velocity.z *= 0.75; + this.velocity.y -= 0.005; + + // Update force direction from user input + let xDirection = 0; + let zDirection = 0; + if (pointerControls.moveForward) zDirection = -1; + if (pointerControls.moveBackward) zDirection = 1; + if (pointerControls.moveRight) xDirection = 1; + if (pointerControls.moveLeft) xDirection = -1; + + // Set the new force direction + this.forceDirection.copy({ x: xDirection, y: 0, z: zDirection }); // Ex: -1.0 to 1.0 + + // Decrease acceleration if the velocity speed equals the force speed + this._v.copy(this.velocity); + const speed = this._v.dot(this.forceDirection); + const speedNext = speed + this.forceAcceleration; + const speedClamped = Math.max(speed, Math.min(speedNext, this.forceSpeedMax)); + const acceleration = speedClamped - speed; // Ex: 0.5 (or 0 at max speed) + + // Add force to velocity using new acceleration + this.velocity.x += this.forceDirection.x * acceleration; + this.velocity.y += this.forceDirection.y * acceleration; + this.velocity.z += this.forceDirection.z * acceleration; + + // Set the next kinematic translation + if (this.po.rigidBody.numColliders() > 0) { + this.characterController.computeColliderMovement(this.po.collider, this.velocity); + this._v.copy(this.po.rigidBody.translation()); + this._v.add(this.characterController.computedMovement()); + this.po.rigidBody.setNextKinematicTranslation(this._v); + } + + // Calculate 3D object rotation from character translation + this._v.copy(this.po.rigidBody.nextTranslation()); + if (this._v.distanceTo(this.po.rigidBody.translation()) > 0.01) { + this.model.lookAt(this._v.x, this.model.position.y, this._v.z); + this.po.rigidBody.setNextKinematicRotation(this.model.quaternion); + } + + // Set vertical velocity to zero if grounded + // if (this.characterController.computedGrounded()) { + // this.allowJump = true; + // this.entity.velocity.y = 0; + // } + } + } \ No newline at end of file diff --git a/src/lib/Hero.js b/src/lib/Hero.js index 1b0a8f0..32b58c7 100644 --- a/src/lib/Hero.js +++ b/src/lib/Hero.js @@ -15,12 +15,6 @@ class Hero{ init(gameEngine){ this.gameEngine = gameEngine; - //this.gameEngine.orbitControls.object = this.model; - //this.gameEngine.orbitControls.target = this.model.position; - - //this.gameEngine.orbitControls.enabled = false; - - //this.model.add(gameEngine.camera) gameEngine.camera.position.set(0,17,-30) gameEngine.camera.lookAt(new THREE.Vector3(this.model.position.x, 5, this.model.position.z)) @@ -36,84 +30,17 @@ class Hero{ this.animationsMap[a.name] = this.mixer.clipAction(a); }) - // this.actionWalk = this.mixer.clipAction( this.object.animations.find(a=>a.name=='walk') ); - // this.actionIdle = this.mixer.clipAction( this.object.animations.find(a=>a.name=='idle') ); - // this.actionIdle.play(); - // this.activeAction = this.actionIdle; this.pointerControls = new PointerControls(gameEngine.camera, this.model, gameEngine.renderer.domElement); gameEngine.hero = this; - - // Character Collider - // const characterCollider = new THREE.Object3D() - // characterCollider.position.y = 3 - // gameEngine.activeObjects.add(characterCollider) - - // const colliderShape = new CANNON.Sphere(0.5) - // const colliderBody = new CANNON.Body({ mass: 1, material: gameEngine.phy.slipperyMaterial }) - // colliderBody.addShape(colliderShape, new CANNON.Vec3(0, 0.5, 0)) - // colliderBody.addShape(colliderShape, new CANNON.Vec3(0, -0.5, 0)) - // colliderBody.position.set( - // characterCollider.position.x, - // characterCollider.position.y, - // characterCollider.position.z - // ) - // colliderBody.linearDamping = 0.95 - // colliderBody.angularFactor.set(0, 1, 0) // prevents rotation X,Z axis - // //colliderBody.sleepSpeedLimit = 1.0; - // gameEngine.phy.world.addBody(colliderBody) - - let po = gameEngine.phy.add(this.model, 'kinematicPositionBased', false, undefined, 'ball', { radius: 0.28}) - - // let bodyDesc = RAPIER.RigidBodyDesc.kinematicPositionBased().setTranslation( - // // characterCollider.position.x, - // // characterCollider.position.y, - // // characterCollider.position.z - // -1, 3, 1 - // ) - // let rigidBody = gameEngine.phy.world.createRigidBody(bodyDesc); - // let dynamicCollider = RAPIER.ColliderDesc.ball(0.28); - // gameEngine.phy.world.createCollider(dynamicCollider, rigidBody.handle); + let po = gameEngine.phy.add(this.model, 'kinematicPositionBased', false, undefined, 'capsule', { radius: 0.5, halfHeight: 1}) + po.collider.setTranslationWrtParent({ x: 0, y: 2.0, z: 0 }); this.characterControls = new CharacterControls(this.model, this.mixer, - this.animationsMap, gameEngine.orbitControls, gameEngine.camera, 'idle', - new RAPIER.Ray( - { x: 0, y: 0, z: 0 }, - { x: 0, y: -1, z: 0} - ), po.rigidBody, this.pointerControls) - - // this.characterCollider = characterCollider; - // this.colliderBody = colliderBody; + this.animationsMap, gameEngine, 'idle', po, this.pointerControls) this.clock = new THREE.Clock() this.delta = 0 - // this.inputVelocity = new THREE.Vector3() - // this.velocity = new CANNON.Vec3() - // this.quat = new THREE.Quaternion() - // this.v = new THREE.Vector3() - // this.rotation = new THREE.Euler() - // this.targetQuaternion = new THREE.Quaternion() - // this.distance = 0 - // this.canJump = true; - - // this.contactNormal = new CANNON.Vec3() - // this.upAxis = new CANNON.Vec3(0, 1, 0) - - // colliderBody.addEventListener('collide', function (e) { - // const contact = e.contact - // if (contact.bi.id == this.colliderBody.id) { - // contact.ni.negate(this.contactNormal) - // } else { - // this.contactNormal.copy(contact.ni) - // } - // if (this.contactNormal.dot(this.upAxis) > 0.5) { - // if (!this.canJump) { - // setAction(animationActions[1], true) - // } - // this.canJump = true - // } - // }.bind(this)) - this.ready = true; } @@ -122,21 +49,6 @@ class Hero{ this.pointerControls.controls.lock(); } - // setAction(toAction, loop){ - // if (toAction != this.activeAction) { - // let lastAction = this.activeAction; - // this.activeAction = toAction - // lastAction.fadeOut(0.1) - // this.activeAction.reset() - // this.activeAction.fadeIn(0.1) - // this.activeAction.play() - // if (!loop) { - // this.activeAction.clampWhenFinished = true - // this.activeAction.loop = THREE.LoopOnce - // } - // } - // } - update(){ //return if (this.gameEngine.renderer.xr.isPresenting) return; diff --git a/src/lib/Physics.js b/src/lib/Physics.js index 95b0141..3fce5b1 100644 --- a/src/lib/Physics.js +++ b/src/lib/Physics.js @@ -20,7 +20,8 @@ class Physics{ // Create Ground. let bodyDesc = RAPIER.RigidBodyDesc.fixed(); let body = world.createRigidBody(bodyDesc); - let colliderDesc = RAPIER.ColliderDesc.cuboid(100.0, 0.1, 100.0); + let colliderDesc = RAPIER.ColliderDesc.cuboid(100, 0, 100); + //bodyDesc.setTranslation(-50,0,-50); world.createCollider(colliderDesc, body.handle); this.world = world; this.physicsObjects = [];