From 4236927537d411805606bd8d540c8d5ebfd0e19c Mon Sep 17 00:00:00 2001 From: goynov Date: Tue, 4 Nov 2025 16:41:42 +0200 Subject: [PATCH] interactive objects integration --- .../InteractiveObjects/ImageObject.js | 12 +- .../InteractiveObjects/InteractiveObject.js | 79 +++++++---- .../MazeQuizGame/MazeObject.js | 41 +----- .../MazeQuizGame/MazeQuizGame.js | 29 ++-- .../MazeQuizGame/MazeQuizGame.vue | 53 ++++++- .../InteractiveObjects/TextObject.js | 2 +- src/components/SceneDesigner/GameObject.vue | 2 +- src/lib/CharacterControls.js | 3 +- src/lib/Dashboard.js | 7 + src/lib/GameEngine.js | 4 +- src/lib/Hero.js | 131 +----------------- src/lib/Physics.js | 23 +-- src/mixins/GameEnvironmentMixin.js | 35 ++--- 13 files changed, 178 insertions(+), 243 deletions(-) diff --git a/src/components/InteractiveObjects/ImageObject.js b/src/components/InteractiveObjects/ImageObject.js index 2b78760..b957e81 100644 --- a/src/components/InteractiveObjects/ImageObject.js +++ b/src/components/InteractiveObjects/ImageObject.js @@ -2,24 +2,24 @@ import { TextureLoader, MeshStandardMaterial, MeshBasicMaterial, PlaneGeometry, import { assignParams } from "@/lib/MeshUtils"; class ImageObject { - constructor(obj, context) { - var t = new TextureLoader().setPath(context.path).load(obj.value); + constructor(obj, engine, params) { + var t = new TextureLoader().setPath(params.path).load(obj.value); //t.encoding = sRGBEncoding; var mp = { map: t, alphaTest: 0.5 }; if (obj.nm) { - mp.normalMap = new TextureLoader().setPath(context.path).load(obj.nm); + mp.normalMap = new TextureLoader().setPath(params.path).load(obj.nm); } if (obj.em) { - mp.emissiveMap = new TextureLoader().setPath(context.path).load(obj.em); + mp.emissiveMap = new TextureLoader().setPath(params.path).load(obj.em); } if (obj.am) { - mp.alphaMap = new TextureLoader().setPath(context.path).load(obj.am); + mp.alphaMap = new TextureLoader().setPath(params.path).load(obj.am); } obj.material && Object.assign(mp, obj.material); - let geo = new PlaneGeometry(context.wallSize * (obj.w || 1), context.wallSize * (obj.h || 1)); + let geo = new PlaneGeometry(params.wallSize * (obj.w || 1), params.wallSize * (obj.h || 1)); if (obj.uv) { var uvAttribute = geo.attributes.uv; for (var i = 0; i < uvAttribute.count; i++) { diff --git a/src/components/InteractiveObjects/InteractiveObject.js b/src/components/InteractiveObjects/InteractiveObject.js index d15e93a..f13a6e9 100644 --- a/src/components/InteractiveObjects/InteractiveObject.js +++ b/src/components/InteractiveObjects/InteractiveObject.js @@ -8,37 +8,58 @@ import { PuzzleGame4 } from "./PuzzleGame4"; import { TextObject } from "./TextObject"; import { ImageObject } from "./ImageObject"; import { VideoPlayer } from "./VideoPlayer"; +import { MazeQuizGame } from "./MazeQuizGame/MazeQuizGame"; +import { assignMaterial, assignParams } from "@/lib/MeshUtils"; const games = {PuzzleGame1, PuzzleGame2, PuzzleGame4}; class InteractiveObject { - constructor(obj, context) { + constructor(obj, gameEngine, params) { this.name = obj.name; - this.ready = new Promise((resolve, reject) => { - let mesh; + this.ready = new Promise(async (resolve, reject) => { switch (obj.type || 'GenericObject') { case 'Group': - mesh = new Group(); - obj.group.forEach(g => { - let go = new InteractiveObject(g, context); - go.ready.then((gameMesh) => { - mesh.add(gameMesh); - }); - }); - resolve(mesh); + this.object = new Group(); + for (let g of obj.group){ + let go = new InteractiveObject(g, gameEngine); + let gameMesh = await go.ready; + this.object.add(gameMesh.object); + } break; case 'Text': - let text = new TextObject(obj, context); - resolve(text.object); + this.source = new TextObject(obj, gameEngine, params); + this.object = this.source.object; break; case 'Image': - let imo = new ImageObject(obj, context); - mesh = imo.object; - resolve(mesh); + this.source = new ImageObject(obj, gameEngine, params); + this.object = this.source.object; + break; + case 'Gltf': + let gltf = await gameEngine.load(obj.value); + let gltfObj = gltf.scene; + gltfObj.traverse(function (object) { + object.frustumCulled = false; + if (obj.name && obj.name == object.name) { + gltfObj = object; + } + // object.castShadow = true; + // object.receiveShadow = true; + }); + + assignMaterial(gltfObj, obj, params); + if (gltf.animations && gltf.animations.length) { + let mixer = new AnimationMixer(gltfObj); + gameEngine.mixers.push(mixer); + let action = mixer.clipAction(gltf.animations[0]); + action.setLoop(LoopPingPong); + action.play(); + } + this.object = gltfObj; + this.source = gltf; break; case 'GenericObject': - let promise = context.load(`/asset/default/${obj.$go.asset.name}`); - promise.then(resolve); + this.source = await gameEngine.load(`/asset/default/${obj.$go.asset.name}`); + this.object = this.source.scene; break; case 'PuzzleGame1': case 'PuzzleGame2': @@ -46,19 +67,23 @@ class InteractiveObject { case 'PuzzleGame4': case 'PuzzleGame5': case 'PuzzleGame6': - let game = new games[obj.type](context, obj.args[0], obj.args[1], obj.args[2]); - mesh = game.object; - mesh.game = game; - resolve(mesh); + let game = new games[obj.type](gameEngine, obj.args[0], obj.args[1], obj.args[2]); + this.object = game.object; + this.object.game = game; break; case 'VideoPlayer': - let vp = new VideoPlayer(context, `/asset/default/${obj.$go.asset.name}`); - vp.ready.then(resolve); + let vp = new VideoPlayer(gameEngine, `/asset/default/${obj.$go.asset.name}`); + this.source = await vp.ready; + this.object = vp.object; + break; + case 'MazeQuizGame': + this.source = new MazeQuizGame(gameEngine, obj); + await this.source.load(); + this.object = this.source.object; break; } - }); - this.ready.then((mesh) => { - this.object = mesh; + assignParams(this.object, obj); + resolve(this); }); } } diff --git a/src/components/InteractiveObjects/MazeQuizGame/MazeObject.js b/src/components/InteractiveObjects/MazeQuizGame/MazeObject.js index dfaba9e..c3d3c89 100644 --- a/src/components/InteractiveObjects/MazeQuizGame/MazeObject.js +++ b/src/components/InteractiveObjects/MazeQuizGame/MazeObject.js @@ -1,6 +1,5 @@ -import { Group, Vector3, Matrix4, Mesh, Quaternion, PlaneGeometry, MeshStandardMaterial, DoubleSide, CanvasTexture, SRGBColorSpace } from 'three'; +import { Group, Vector3, Matrix4, Mesh, Quaternion, PlaneGeometry, MeshStandardMaterial, DoubleSide} from 'three'; import { InteractiveObject } from '../InteractiveObject'; -import Utils from '@/lib/Utils'; class MazeObject { constructor(engine, def, params = {}){ @@ -39,7 +38,7 @@ class MazeObject { if (typeof size == 'number'){ size = { width: 0.1, height:1, depth:size/2 } } - let po = engine.phy.add( + let po = engine.physics.add( {position: v}, 'fixed', false, undefined, 'cuboid', { ...size, isSensor, userData } ) @@ -51,13 +50,6 @@ class MazeObject { } function addRoom(elements, def, offsetZ){ - // e = [ - // o.floor.clone(), - // o.door.clone(), - // o[def.r ? 'door' : 'wall'].clone(), - // o[def.f ? 'door' : 'wall'].clone(), - // o[def.l ? 'door' : 'wall'].clone() - // ]; let e = elements.map(e=>o[e].clone()) @@ -106,9 +98,6 @@ class MazeObject { let offsetZ = 0, e; def.len = def.len || 0; if (step == 0) { - // e = o.door.clone(); - // e.rotateY(_tf.rotation.f); - // mazeMeshes.push(e); addRoom(['floor', 'wall', 'wall', 'door', 'wall'], def, -context.wallSize) } if (def.userData?.answer !== undefined){ @@ -121,15 +110,6 @@ class MazeObject { root.add(t); } offsetZ = def.len * context.tubeSize; - //if (!def.len) offsetZ = -.275; - //room.getWorldQuaternion(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))) - addPhysics(def.matrix, [context.tubeSize / 2, 0.6, offsetZ/2], offsetZ) addPhysics(def.matrix, [-context.tubeSize / 2, 0.6, offsetZ/2], offsetZ) @@ -140,16 +120,12 @@ class MazeObject { //console.log('loadingggg', def.objects) def.objects?.forEach(async obj => { obj.room = room; - // let go = new GameObject(obj, context); - let go = new InteractiveObject(obj, context) + let go = new InteractiveObject(obj, engine, context) await go.ready; go.object.scale.multiplyScalar(context.wallSize) go.object.position.multiplyScalar(context.wallSize) go.object.applyMatrix4(def.matrix); root.add(go.object); - // go.ready.then(mesh => { - // room.add(mesh); - // }); }); def.room = room; @@ -173,17 +149,8 @@ class MazeObject { o[e] = mazeAsset.scene.getObjectByName(e); //o[e].frustumCulled = false; o[e].scale.set(scale, scale, scale) - // o[e].geometry.computeBoundingBox(); - // console.log(e, o[e].geometry.boundingBox) }); this.mazeObject(def, room); - // mazeMeshes.forEach(mesh=>{ - // //let mesh = new Mesh(mg, o.tunnel.material) - // root.add(mesh); - // //engine.phy.add(mesh, 'fixed') - // }) - - //console.log(bbox, 'bbox') const floorGeometry = new PlaneGeometry(bbox.r - bbox.l + 10*scale, bbox.f + 10*scale); const floor = new Mesh(floorGeometry,new MeshStandardMaterial({ roughness: 0, metalness:1, color: 0x00ffff, side: DoubleSide @@ -191,8 +158,6 @@ class MazeObject { floor.rotation.set(Math.PI/2, 0, 0) floor.position.set((bbox.l + bbox.r)/2, 0.3, bbox.f/2); root.add(floor); - //scene.add(new Mesh(BufferGeometryUtils.mergeGeometries(mazeGeometries, false), o.tunnel.material)); - //console.log(room); } } } diff --git a/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.js b/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.js index 7021a52..025ea93 100644 --- a/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.js +++ b/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.js @@ -3,25 +3,28 @@ import Utils from "@/lib/Utils"; const defaults = { arrows:{ - r: len => ({ type: 'image', value: '/static/textures/arrow.png', position:[-.5,.44,len+.96], rotation:[0,Math.PI, 0], scale: [0.03, 0.03, 0.03] }), - l: len => ({ type: 'image', value: '/static/textures/arrow.png', position:[.5,.44,len+.96], rotation:[0,Math.PI, Math.PI], scale: [0.03, 0.03, 0.03] }), - f: len => ({ type: 'image', value: '/static/textures/arrow.png', position:[0,.7,len+.96], rotation:[0,Math.PI, Math.PI/2], scale: [0.03, 0.03, 0.03] }) + r: len => ({ type: 'Image', value: '/static/textures/arrow.png', position:[-.5,.44,len+.96], rotation:[0,Math.PI, 0], scale: [0.03, 0.03, 0.03] }), + l: len => ({ type: 'Image', value: '/static/textures/arrow.png', position:[.5,.44,len+.96], rotation:[0,Math.PI, Math.PI], scale: [0.03, 0.03, 0.03] }), + f: len => ({ type: 'Image', value: '/static/textures/arrow.png', position:[0,.7,len+.96], rotation:[0,Math.PI, Math.PI/2], scale: [0.03, 0.03, 0.03] }) }, answers:{ - r: (len, text) => ({ type: 'text', width:0.5, text, fontSize:0.025, position:[-.5,.3,len+.9], rotation:[0,Math.PI, 0] }), - l: (len, text) => ({ type: 'text', width:0.5, text, fontSize:0.025, position:[.5,.3,len+.9], rotation:[0,Math.PI, 0] }), - f: (len, text) => ({ type: 'text', width:0.5, text, fontSize:0.025, position:[0,.55,len+.9], rotation:[0,Math.PI, 0] }) + r: (len, text) => ({ type: 'Text', width:0.5, text, fontSize:0.025, position:[-.5,.3,len+.9], rotation:[0,Math.PI, 0] }), + l: (len, text) => ({ type: 'Text', width:0.5, text, fontSize:0.025, position:[.5,.3,len+.9], rotation:[0,Math.PI, 0] }), + f: (len, text) => ({ type: 'Text', width:0.5, text, fontSize:0.025, position:[0,.55,len+.9], rotation:[0,Math.PI, 0] }) } } const tl = 4; class MazeQuizGame { - constructor(engine, context, questions) { + constructor(engine, data) { + let questions = data.shuffle ? Utils.shuffleArray(data.questions) : data.questions; let def = this.generate(questions); this.mazeObject = new MazeObject(engine, def) engine.addEventListener('collision', async e=>{ - let ud = engine.phy.world.getCollider(e.handle2)?.parent()?.userData; + let ud1 = engine.physics.world.getCollider(e.handle1)?.parent()?.userData, + ud2 = engine.physics.world.getCollider(e.handle2)?.parent()?.userData; + let ud = {...ud1, ...ud2} if (ud?.finish){ if (e.started){ engine.dashboard.updateProgress(1) @@ -53,7 +56,7 @@ class MazeQuizGame { async load(){ await this.mazeObject.load(); this.object = this.mazeObject.object; - return this.object; + return this; } generate(questions, qid = 0, len){ @@ -63,7 +66,7 @@ class MazeQuizGame { userData: { finish: true }, objects:[ { - type: 'gltf', + type: 'Gltf', position:[0,.25,len + .52], scale: [0.037, 0.037, 0.037], rotation: [0, Math.PI/4, 0], value: '/static/meshes/award.glb' } @@ -83,12 +86,12 @@ class MazeQuizGame { len, userData: { question, qid }, objects:[ { - type: 'text', text: question.q, fontSize:0.033, width:0.5, position:[0,.33,len + .96], rotation:[0,Math.PI, 0] + type: 'Text', text: question.q, fontSize:0.033, width:0.5, position:[0,.33,len + .96], rotation:[0,Math.PI, 0] } ] } - question.a.forEach((a, i)=>{ + question.a.filter(a=>!!a).forEach((a, i)=>{ let d = directions[i]; mo.objects.push( defaults.arrows[d](len), @@ -114,7 +117,7 @@ class MazeQuizGame { len: 2, objects:[ { - type: 'text', width:0.5, color:0xff0000, text: question.h, fontSize:0.033, position:[0,.44,2+.96], rotation:[0,Math.PI, 0] + type: 'Text', width:0.5, color:0xff0000, text: question.h, fontSize:0.033, position:[0,.44,2+.96], rotation:[0,Math.PI, 0] } ] } diff --git a/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.vue b/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.vue index b9c9cfb..7fd1305 100644 --- a/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.vue +++ b/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.vue @@ -1,11 +1,56 @@ \ No newline at end of file diff --git a/src/components/InteractiveObjects/TextObject.js b/src/components/InteractiveObjects/TextObject.js index 827a3fb..0457e06 100644 --- a/src/components/InteractiveObjects/TextObject.js +++ b/src/components/InteractiveObjects/TextObject.js @@ -3,7 +3,7 @@ import { Text } from "troika-three-text"; import { assignParams } from "@/lib/MeshUtils"; class TextObject { - constructor(obj, params) { + constructor(obj, engine, params) { const txt = new Text(); // Set properties to configure: txt.text = obj.text; diff --git a/src/components/SceneDesigner/GameObject.vue b/src/components/SceneDesigner/GameObject.vue index ef9793e..9b6d2ba 100644 --- a/src/components/SceneDesigner/GameObject.vue +++ b/src/components/SceneDesigner/GameObject.vue @@ -82,7 +82,7 @@ export default { if (e.type == 'InteractiveObject'){ this.modelValue.type = e.id; }else{ - this.modelValue.type = 'Object3D' + this.modelValue.type = 'GenericObject' } } } diff --git a/src/lib/CharacterControls.js b/src/lib/CharacterControls.js index b05559e..a37e9f2 100644 --- a/src/lib/CharacterControls.js +++ b/src/lib/CharacterControls.js @@ -23,9 +23,10 @@ export class CharacterControls { this.currentAction = currentAction this.animationsMap[currentAction].play() - this.characterController = engine.phy.world.createCharacterController(0.1); + this.characterController = engine.physics.world.createCharacterController(0.1); this.characterController.setUp({x:0, y:1, z:0}); po.rigidBody.setTranslation(this.model.position) + po.characterController = this.characterController; // this.characterController.enableSnapToGround(0.5); // // Don’t allow climbing slopes larger than 45 degrees. // this.characterController.setMaxSlopeClimbAngle(45 * Math.PI / 180); diff --git a/src/lib/Dashboard.js b/src/lib/Dashboard.js index 3510a03..1070b09 100644 --- a/src/lib/Dashboard.js +++ b/src/lib/Dashboard.js @@ -91,6 +91,13 @@ class DashBoard { dash.visible = false; } + this.reset = ()=>{ + this.updateProgress(0); + this.update({ + hint: '' + }); + } + this.createProgressBar(); this.update(); } diff --git a/src/lib/GameEngine.js b/src/lib/GameEngine.js index 684fa1e..65bee56 100644 --- a/src/lib/GameEngine.js +++ b/src/lib/GameEngine.js @@ -262,8 +262,8 @@ class GameEngine extends THREE.EventDispatcher{ } async initPhysics() { - this.phy = new Physics(this); - await this.phy.init(); + this.physics = new Physics(this); + await this.physics.init(); } handleXrAction(gameEngine, delta) { diff --git a/src/lib/Hero.js b/src/lib/Hero.js index 0adb58b..4f865dd 100644 --- a/src/lib/Hero.js +++ b/src/lib/Hero.js @@ -9,7 +9,6 @@ class Hero{ this.object = object; this.data = data; this.model = object.scene - //console.log(object) } init(gameEngine){ @@ -17,10 +16,6 @@ class Hero{ gameEngine.camera.position.set(0,17,-30) gameEngine.camera.lookAt(new THREE.Vector3(this.model.position.x, 5, this.model.position.z)) - // this.heroCamera = new THREE.Object3D() - // this.model.add(this.heroCamera) - // this.heroCamera.applyMatrix4(gameEngine.camera.matrix) - this.mixer = new AnimationMixer(this.model); gameEngine.mixers.push( this.mixer ); @@ -32,7 +27,7 @@ class Hero{ this.pointerControls = new PointerControls(gameEngine.camera, this.model, gameEngine.renderer.domElement); gameEngine.hero = this; - let po = gameEngine.phy.add(this.model, 'kinematicPositionBased', false, undefined, 'capsule', { radius: 0.5, halfHeight: 1}) + let po = gameEngine.physics.add(this.model, 'kinematicPositionBased', false, undefined, 'capsule', { radius: 0.5, halfHeight: 1}) po.collider.setTranslationWrtParent({ x: 0, y: 2.0, z: 0 }); //po.collider.setActiveEvents(RAPIER.ActiveEvents.COLLISION_EVENTS); @@ -59,128 +54,16 @@ class Hero{ let dlt = this.clock.getDelta(); this.delta += dlt; //if (this.delta > 0.00001){ - this.characterControls.update(this.gameEngine.phy.world, this.delta, pc) - this.gameEngine.phy.step() + this.characterControls.update(this.gameEngine.physics.world, this.delta, pc) + this.gameEngine.physics.step() this.delta = 0; //} } + } - - return; - let { inputVelocity, velocity, quat, v, targetQuaternion, clock, rotation } = this; - // let pc = this.pointerControls; - // pc.update(); - if (this.ready) { - if (this.canJump) { - //walking - this.mixer.update(this.distance / 100) - } else { - //were in the air - this.mixer.update(this.delta) - } - const p = this.characterCollider.position - p.y -= 1 - this.model.position.y = this.characterCollider.position.y - this.distance = this.model.position.distanceTo(p) - - // const rotationMatrix = new THREE.Matrix4() - // rotationMatrix.lookAt(p, this.model.position, this.model.up) - // targetQuaternion.setFromRotationMatrix(rotationMatrix) - - // if (!this.model.quaternion.equals(targetQuaternion)) { - // this.model.quaternion.rotateTowards(targetQuaternion, this.delta * 10) - // } - - if (this.canJump) { - inputVelocity.set(0, 0, 0) - - if (pc.moveForward) { - inputVelocity.z = 1 - } - if (pc.moveBackward) { - inputVelocity.z = -1 - } - - if (pc.moveLeft) { - //inputVelocity.x = -1 - rotation.y+=2*this.delta - } - if (pc.moveRight) { - //inputVelocity.x = 1 - rotation.y-=2*this.delta - } - - //let d = this.gameEngine.camera.position.distanceTo(v); - - inputVelocity.setLength(this.delta * 10) - - // apply camera rotation to inputVelocity - //euler.y = this.gameEngine.camera.rotation.y; - quat.setFromEuler(rotation) - inputVelocity.applyQuaternion(quat) - //this.gameEngine.camera.updateProjectionMatrix() - //this.gameEngine.orbitControls.update() - // if (this.gameEngine.orbitControls){ - //this.gameEngine.orbitControls.target = v//this.model.position; - // //this.gameEngine.orbitControls.update() - // } - - //this.gameEngine.camera.rotateOnAxis(v, rotation.y) - - } - - if(inputVelocity.x || inputVelocity.z){ - this.setAction(this.actionWalk, true) - }else{ - this.setAction(this.actionIdle, true) - } - - // this.gameEngine.camera.position.lerp(this.characterCollider.position, 1) - // this.gameEngine.camera.rotation.y = rotation.y; - - this.model.position.lerp(this.characterCollider.position, 1) - this.model.rotation.y = rotation.y; - - } - velocity.set(inputVelocity.x, inputVelocity.y, inputVelocity.z) - this.colliderBody.applyImpulse(velocity) - - this.delta = Math.min(clock.getDelta(), 0.1) - this.gameEngine.phy.world.step(this.delta) - - //cannonDebugRenderer.update() - - this.characterCollider.position.set(this.colliderBody.position.x, this.colliderBody.position.y, this.colliderBody.position.z) - // boxes.forEach((b, i) => { - // boxMeshes[i].position.set(b.position.x, b.position.y, b.position.z) - // boxMeshes[i].quaternion.set(b.quaternion.x, b.quaternion.y, b.quaternion.z, b.quaternion.w) - // }) - - this.characterCollider.getWorldPosition(v) - //this.gameEngine.cameraPivot.position.lerp(v, 0.1) - - // if (this.gameEngine.camera.position.distanceTo(v) > 2){ - // this.gameEngine.camera.position.set(v.x+1, 3, v.z + 3); - // } - //this.gameEngine.camera.lookAt(v.x, 3, v.z); - //this.gameEngine.camera.rotation.y = this.model.rotation.y; - - // this.gameEngine.camera.updateMatrix(); - // this.model.updateMatrix(); - let cam = this.gameEngine.camera; - let vv = new THREE.Vector3(), qq = new THREE.Quaternion; - this.heroCamera.getWorldPosition(vv) - //this.heroCamera.getWorldQuaternion(qq); - cam.position.copy(vv) - //cam.setRotationFromQuaternion(qq) - cam.lookAt(new THREE.Vector3(this.model.position.x, 2.8, this.model.position.z)) - //console.log(vv) - // cam.matrixAutoUpdate = false; - // cam.matrix.multiplyMatrices(this.model.matrix, cam.matrix) - // //cam.matrix.decompose(cam.position, cam.quaternion, cam.scale) - // //this.gameEngine.camera.updateMatrix(); - // cam.matrixAutoUpdate = true; - // this.gameEngine.orbitControls.update() + destroy(){ + delete this.gameEngine.hero; + this.gameEngine.mixers.splice(this.gameEngine.mixers.indexOf(this.mixer), 1); } } diff --git a/src/lib/Physics.js b/src/lib/Physics.js index e4e391c..2c65f1b 100644 --- a/src/lib/Physics.js +++ b/src/lib/Physics.js @@ -31,29 +31,25 @@ class Physics{ let colliderDesc switch (colliderType) { - case 'cuboid': - { + case 'cuboid':{ const { width, height, depth } = colliderSettings colliderDesc = RAPIER.ColliderDesc.cuboid(width, height, depth) } break - case 'ball': - { + case 'ball':{ const { radius } = colliderSettings colliderDesc = RAPIER.ColliderDesc.ball(radius) } break - case 'capsule': - { + case 'capsule':{ const { halfHeight, radius } = colliderSettings colliderDesc = RAPIER.ColliderDesc.capsule(halfHeight, radius) } break - default: - { + default:{ colliderDesc = RAPIER.ColliderDesc.trimesh( mesh.geometry.attributes.position.array, mesh.geometry.index?.array @@ -74,14 +70,21 @@ class Physics{ // * Responsible for collision detection const collider = this.world.createCollider(colliderDesc, rigidBody) - const physicsObject = { mesh, collider, rigidBody, fn: postPhysicsFn, autoAnimate } - this.physicsObjects.push(physicsObject) return physicsObject } + clear(){ + this.physicsObjects.forEach(po=>{ + po.characterController && this.world.removeCharacterController(po.characterController) + this.world.removeCollider(po.collider); + this.world.removeRigidBody(po.rigidBody); + }) + this.physicsObjects = []; + } + step(){ this.world.step(this.eventQueue) diff --git a/src/mixins/GameEnvironmentMixin.js b/src/mixins/GameEnvironmentMixin.js index d3e79a3..1cc294b 100644 --- a/src/mixins/GameEnvironmentMixin.js +++ b/src/mixins/GameEnvironmentMixin.js @@ -120,7 +120,10 @@ export default { */ async loadEnvironment(scene, target){ //await gameEngine.loadPanorama(`/asset/default/43.webp`); + gameEngine.hero?.destroy(); + gameEngine.dashboard?.reset(); gameEngine.activeObjects.clear(); + gameEngine.physics.clear(); await this.expandScenarioData(scene); target.objects = target.objects || {}; let l = target.objects; @@ -129,7 +132,8 @@ export default { } if (this.scene.data.$scene){ let env = await gameEngine.load(`/asset/default/${this.scene.data.$scene.asset.name}`); - this.setObjectAttributes(l, this.scene.data, env, 100); + //console.log('ENV', env) + this.setObjectAttributes(l, this.scene.data, env.scene, env, 100); gameEngine.activeObjects.add(env.scene); } for (let i of this.scene.data.items || []) { @@ -137,17 +141,16 @@ export default { await io.ready; //let gltf = await gameEngine.load(`/asset/default/${i.data.$go.asset.name}`); - let objKey = (i.data.type == 'GenericObject' || !i.data.type) ? 'scene' : 'object' - console.log(i.data, io.object) - this.setObjectAttributes(l, i.data, io.object, 1, objKey); - gameEngine.activeObjects.add(io.object[objKey]); + //console.log(i.data, io.object) + this.setObjectAttributes(l, i.data, io.object, io.source, 1); + gameEngine.activeObjects.add(io.object); if (this.env == 'GamePlaying'){ - if (i.data.$go.type == 'player3d'){ - let hero = new Hero(io.object, i.data.$go); + if (i.data.$go?.type == 'player3d'){ + let hero = new Hero(io.source, i.data.$go); hero.init(gameEngine); }else{ - if (io.object.animations?.length){ - gameEngine.playAnimation(gameEngine.scene, io.object.animations[0]); + if (io.source?.animations?.length){ + gameEngine.playAnimation(gameEngine.scene, io.source.animations[0]); } } } @@ -185,22 +188,22 @@ export default { } }, - setObjectAttributes(l, data, o, autoScaleFactor = 1, objectKey = 'scene'){ + setObjectAttributes(l, data, object, source, autoScaleFactor = 1){ if (l[data.id]){ ['position', 'scale', 'rotation'].forEach(p=>{ - o[objectKey][p].copy(l[data.id][p]) + object[p].copy(l[data.id][p]) }) }else{ - gameEngine.autoScale(o[objectKey], autoScaleFactor); + gameEngine.autoScale(object, autoScaleFactor); } l[data.id] = l[data.id] || {}; ['position', 'scale', 'rotation', 'visible'].forEach(p=>{ - l[data.id][p] = o[objectKey][p]; + l[data.id][p] = object[p]; }) - l[data.id].__o = o[objectKey]; - l[data.id].__g = o; + l[data.id].__o = object; + l[data.id].__g = source; l[data.id].__title = data.title; - o[objectKey].__pn_id = data.id; + object.__pn_id = data.id; }, async toggleAnimation(animation){