From f9a249adb7498b7e1f6ee56822e1d5db6d868a7b Mon Sep 17 00:00:00 2001 From: goynov Date: Fri, 3 Apr 2026 13:47:30 +0300 Subject: [PATCH] add collisionTypes --- .../InteractiveObjects/GenericObject.vue | 7 ++++-- .../MazeQuizGame/MazeQuizGame.js | 1 - .../InteractiveObjects/Particles.js | 1 - src/lib/GameEngine.js | 2 +- src/lib/GameManager.js | 12 +++------ src/lib/Hero.js | 25 +++++++++++-------- src/lib/Physics.js | 21 ++++++++++++++-- src/plugins/lang.js | 16 ++++++++++-- 8 files changed, 58 insertions(+), 27 deletions(-) diff --git a/src/components/InteractiveObjects/GenericObject.vue b/src/components/InteractiveObjects/GenericObject.vue index 6bda88b..bfe8ffd 100644 --- a/src/components/InteractiveObjects/GenericObject.vue +++ b/src/components/InteractiveObjects/GenericObject.vue @@ -8,7 +8,8 @@ - +
{{ modelValue.title }}
@@ -19,11 +20,13 @@ export default { data(){ return { - active: false + active: false, + collisionTypes: [] } }, mounted(){ this.active = true; + this.collisionTypes = Object.keys(this.l.collisionTypes).map(t=>({title: this.l.collisionTypes[t], value: t})) }, props:{ modelValue: Object diff --git a/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.js b/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.js index 4310f9d..ec8aac9 100644 --- a/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.js +++ b/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.js @@ -42,7 +42,6 @@ class MazeQuizGame extends EventManager { constructor(engine, data) { super(); this.data = data; - data.noPhysics = true; this.params = { ...params, mazeFile: data.style || 'quiz-s2.gltf', io: this } diff --git a/src/components/InteractiveObjects/Particles.js b/src/components/InteractiveObjects/Particles.js index 3c9939d..afc6144 100644 --- a/src/components/InteractiveObjects/Particles.js +++ b/src/components/InteractiveObjects/Particles.js @@ -10,7 +10,6 @@ import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js' class Particles { constructor(engine, data) { - data.noPhysics = true; const { x, y, count, w, h } = data; let positions = Particles.positions(count, w, h); return new Promise(async (resolve, reject) => { diff --git a/src/lib/GameEngine.js b/src/lib/GameEngine.js index 29bb9fb..8289819 100644 --- a/src/lib/GameEngine.js +++ b/src/lib/GameEngine.js @@ -258,7 +258,7 @@ class GameEngine extends EventManager{ event.preventDefault(); if (this.hero){ if (!this.pointerControls.isLocked){ - this.hero.cameraZ += event.deltaY / 100; + this.hero.cameraZ += event.deltaY * 0.005; } }else{ this.camera.zoom -= event.deltaY / (1000 / this.camera.zoom); diff --git a/src/lib/GameManager.js b/src/lib/GameManager.js index e84e3fe..ec52125 100644 --- a/src/lib/GameManager.js +++ b/src/lib/GameManager.js @@ -52,12 +52,7 @@ class GameManager{ let env = await engine.load(scene.data.$scene.asset.name); this.setObjectAttributes(sceneObjects, scene.data, env.scene, env, null); if (engine.opts.mode != 'GameDesigner'){ - env.scene.traverse(o=>{ - if (o.name.startsWith('land') || o.name == 'Sphere'){ - //this.debug('Fixing ground. TODO!!!') - engine.physics.add(o, 'fixed', true, undefined, 'mesh', { root: env.scene}) - } - }) + engine.physics.apply(env.scene) } engine.activeObjects.add(env.scene); } @@ -86,13 +81,14 @@ class GameManager{ if (io.source?.animations?.length){ engine.playAnimation(engine.scene, io.source.animations[0]); } - - if (!i.data.noPhysics){ + if (i.data.collisionType == 'basic'){ let bb = engine.meshUtils.getBoundingBox(io.object); let bbs = engine.meshUtils.getBoundingBoxSize(bb); engine.physics.add(io.object, 'fixed', false, undefined, 'capsule', { radius: Math.max(bbs.x, bbs.z)/2, halfHeight: bbs.y/2 }) + }else if (i.data.collisionType == 'objectDefinied'){ + engine.physics.apply(io.object) } } io.addEventListener('finish', ()=>{ diff --git a/src/lib/Hero.js b/src/lib/Hero.js index 343b6ee..2b3e7bd 100644 --- a/src/lib/Hero.js +++ b/src/lib/Hero.js @@ -13,29 +13,29 @@ class Hero{ } set cameraZ(v){ - this.#cameraZ = Math.min(Math.max(v, 1), 12); - if (this.#cameraZ == 1 && !this.fpv){ + this.#cameraZ = Math.min(Math.max(v, this.cameraZMin), this.cameraZMax); + if (this.#cameraZ == this.cameraZMin && !this.fpv){ if (this.engine.renderer.xr.isPresenting){ this.#cameraZ = 0; this.fpv = true; - this.cameraY = this.size.y*0.9; + this.cameraY = this.cameraYBase; this.camera.rotation.set(0,0,0); }else{ this.engine.pointerControls.lock(true).then(()=>{ this.#cameraZ = 0; this.fpv = true; - this.cameraY = this.size.y*0.9; + this.cameraY = this.cameraYBase; this.engine.pointerControls.once('unlock', ()=>{ this.fpv = false; - this.cameraY = this.size.y*1.5; + this.cameraY = this.cameraYBase * 1.5; }) }).catch(err=>{ console.log(err); }) } - }else if(this.#cameraZ > 1 && this.fpv){ + }else if(this.#cameraZ > this.cameraZMin && this.fpv){ this.fpv = false; - this.cameraY = this.size.y*1.5; + this.cameraY = this.cameraYBase * 1.5; } //this.engine.dashboard.updateText(this.#cameraZ); } @@ -67,7 +67,12 @@ class Hero{ // let center = getBoundingBoxCenterPoint(bb, this.model.userData.object.position) let bb = engine.meshUtils.getBoundingBox(io.object); this.size = engine.meshUtils.getBoundingBoxSize(bb); - console.log('Hero size is', this.size); + //console.log('Hero size is', this.size); + this.cameraYBase = this.size.y / this.engine.scale; + this.cameraZMin = 1 / this.engine.scale; + this.cameraZMax = 12 / this.engine.scale; + this.#cameraZ = this.cameraZDefault = 4 / this.engine.scale; + // let center = getBoundingBoxCenterPoint(bb, io.object.position) // console.log('hero', size, center, size.y - 2*this.characterGapOffset) @@ -97,7 +102,7 @@ class Hero{ this.orbitControl = this.engine.orbitControls //this.camera = this.engine.camera; this.camera = this.engine.cameraWorld; - this.cameraY = this.size.y * 1.5; + this.cameraY = this.cameraYBase * 1.5; this.direction = this.model.rotation.y; //this.directionVelocity = 0; @@ -150,7 +155,7 @@ class Hero{ } if (!this.fpv && !this.model.visible){ this.model.visible = true; - this.#cameraZ = 4 + this.#cameraZ = this.cameraZDefault; this.engine.camera.fov = 45; this.engine.camera.updateProjectionMatrix(); } diff --git a/src/lib/Physics.js b/src/lib/Physics.js index 58eb350..e0588f7 100644 --- a/src/lib/Physics.js +++ b/src/lib/Physics.js @@ -32,7 +32,7 @@ class Physics{ add = (mesh, rigidBodyType, autoAnimate = true, postPhysicsFn, colliderType, colliderSettings = {}) => { const rigidBodyDesc = RAPIER.RigidBodyDesc[rigidBodyType]() - let position, quaternion; + let position, quaternion, scale = new Vector3(1,1,1); // if (colliderSettings.root){ // // mesh.getWorldPosition(position = new Vector3()); // // mesh.getWorldQuaternion(quaternion = new Quaternion()); @@ -42,6 +42,15 @@ class Physics{ position = mesh.position; quaternion = mesh.quaternion; //} + + if (colliderSettings.root){ + let p = mesh; + while (p != colliderSettings.root.parent) { + scale.multiply(p.scale); + p = p.parent; + } + } + rigidBodyDesc.setTranslation(position.x, position.y, position.z) quaternion && rigidBodyDesc.setRotation(quaternion) @@ -76,7 +85,7 @@ class Physics{ const position = mesh.geometry.getAttribute( 'position' ); for ( let i = 0; i < position.count; i ++ ) { vertex.fromBufferAttribute( position, i ); - vertices.push( vertex.x, vertex.y, vertex.z ); + vertices.push( vertex.x * scale.x, vertex.y * scale.x, vertex.z * scale.x ); } // if the buffer is non-indexed, generate an index buffer @@ -111,6 +120,14 @@ class Physics{ return physicsObject } + apply(object){ + object.traverse(o=>{ + if (o.name.startsWith('land') || o.name.endsWith('-physics')){ + this.add(o, 'fixed', true, undefined, 'mesh', { root: object}) + } + }) + } + clear(){ this.physicsObjects.forEach(po=>{ po.characterController && this.world.removeCharacterController(po.characterController) diff --git a/src/plugins/lang.js b/src/plugins/lang.js index 7b15071..044da83 100644 --- a/src/plugins/lang.js +++ b/src/plugins/lang.js @@ -48,7 +48,13 @@ const lang = { minActivationScore: 'Minimum level score for activation', viewInHUD: 'Observe in head-up display', disableInteractions: 'Disable interactions', - disableCollisions: 'Disable collisions', + collisionType: 'Collision type', + collisionTypes: { + no: 'No collisions', + basic: 'Basic (sphere around object)', + objectDefinied: 'Defined in object', + advanced: 'Complex (not implemented)' + }, dimensions: 'Dimensions', elementsCount: 'Number of elements', particleWidth: 'Particle width', @@ -204,7 +210,13 @@ const lang = { minActivationScore: 'Минимален брой точки за активиране', viewInHUD: 'Показване в HUD (head-up display)', disableInteractions: 'Без взаимодействия', - disableCollisions: 'Без колизии', + collisionType: 'Тип колизии', + collisionTypes: { + no: 'Без', + basic: 'Базови (сфера около обекта)', + objectDefinied: 'От дефиницията на обекта', + advanced: 'С голяма точност (not implemented)' + }, dimensions: 'Размери', elementsCount: 'Брой елементи', particleWidth: 'Ширина на частиците',