import { InteractiveObject } from '@/components/InteractiveObjects/InteractiveObject'; import { VideoPlayer } from '@/components/InteractiveObjects/VideoPlayer'; import { GameEngine } from '@/lib/GameEngine'; import { Hero } from '@/lib/Hero'; import { autoScale, getBoundingBox, getBoundingBoxSize } from '@/lib/MeshUtils'; import Utils from '@/lib/Utils'; let gameEngine = null; export default { async mounted(){ gameEngine = new GameEngine(); //this.gameEngine = gameEngine; await gameEngine.init(this.$refs.target, { xr: true, gizmo: this.env == 'GameDesigner', stats: this.env != 'GamePlay', designMode: this.env == 'GameDesigner', depthSense: this.env == 'GameDesigner' ? false : this.store.prefs.xr.depthSense }); //gameEngine.scene.add(new gameEngine.$.GridHelper(100,100)); if (this.env == 'GameDesigner'){ gameEngine.scene.add(gameEngine.transformControls.getHelper()); }else{ gameEngine.dashboard.enable(); } this.resize(); //gameEngine.setCamera(gameEngine.orthographicCamera) //gameEngine.setCameraOrthographic(); await this.loadScenario(); window.addEventListener('resize', this.resize); }, unmounted(){ window.removeEventListener('resize', this.resize); gameEngine.clearScene(); gameEngine.stop(); }, computed:{ scenes(){ return this.scenario?.scenes || []; }, scene(){ return this.scenesList[0]; }, currentObject(){ return this.objectsList[0]; }, sceneObjects(){ return this.object.scenes?.[this.scene?.data?.id]?.objects; }, object(){ return this.modelValue; }, objectAnimations(){ return this.currentObject?.__g?.animations?.map(a => ({ name: a.name, id: a.uuid, a })); } }, watch:{ async scene(n){ this.object.scenes = this.object.scenes || {} this.object.scenes[n.data.id] = this.object.scenes[n.data.id] || {} await this.loadEnvironment(n, this.object.scenes[n.data.id]); }, mode(n){ gameEngine.transformControls.setMode(n) }, // async 'object.scenario'(n){ // await this.loadScenario() // }, currentObject(n){ if (this.env == 'GameDesigner'){ gameEngine.transformControls.attach(n.__o); gameEngine.gizmo.target = n.__o.position; gameEngine.camera.updateProjectionMatrix() } }, renderType(v){ gameEngine.renderType = v; }, cameraType(v){ if (v == 'perspective'){ gameEngine.setCameraPerspective(); }else{ gameEngine.setCameraOrthographic(); } } }, methods:{ async loadScenario(){ if (this.object.scenario){ this.scenario = (await this.$api.scenario.load(this.object.scenario)).data; }else{ this.scenario = null; } }, async expandScenarioData(scene){ const promises = []; ['environment', 'scene', 'intro', 'audio'].filter(e=>scene.data[e]).forEach(e=>{ promises.push(this.$api.gameObject.load(scene.data[e]).then(r=>scene.data['$'+e] = r.data)) }) for (let i of scene.data.items || []) { Object.keys(i.data).filter(k=>k == 'go' || k.startsWith('go_')).forEach(k=>{ promises.push(this.$api.gameObject.load(i.data[k]).then(r=>i.data['$'+k] = r.data)); }) } await Promise.all(promises); }, /** * loads all environment objects * @param scene Scene object from the Scenario Module * @param target Target scene definition from Game Module */ async loadEnvironment(scene, target){ //await gameEngine.loadPanorama(`/asset/default/43.webp`); let intro; gameEngine.clearScene(); gameEngine.activeObjects.visible = false; await gameEngine.dashboard.ready; gameEngine.dashboard?.initScene(async ()=>{ if (this.scene.data.$audio){ await gameEngine.playAmbientSound(this.scene.data.$audio.asset.name); gameEngine.ambientSound.setVolume( 0.5 ); } intro?.play(); }); await this.expandScenarioData(scene); gameEngine.dashboard?.loading(0.05); gameEngine.orbitControls.enableRotate = this.env == 'GameDesigner' //this is needed cause when mounted canvas has different size this.resize(); target.objects = target.objects || {}; let l = target.objects; if (this.scene.data.$environment){ await gameEngine.loadPanorama(this.scene.data.$environment.asset.name); gameEngine.showBackground(false); } if (this.scene.data.$scene){ let env = await gameEngine.load(this.scene.data.$scene.asset.name); this.setObjectAttributes(l, this.scene.data, env.scene, env, null); if (this.env != 'GameDesigner'){ env.scene.traverse(o=>{ if (o.name.startsWith('land') || o.name == 'Sphere'){ console.log('Fixing ground. TODO!!!') gameEngine.physics.add(o, 'fixed', true, undefined, 'mesh', { root: env.scene}) } }) } gameEngine.activeObjects.add(env.scene); } let expectToFinish = 0, finished = 0;; if (this.scene.data.items){ let loaded = 0; for (let i of this.scene.data.items) { if (this.env != 'GameDesigner'){ if (i.data.activationTriggers?.length || i.data.activationScore){ i.data.shouldBeLocked = true; } } let io = await new InteractiveObject(gameEngine, i.data) i.__io = io; if (io.emits?.includes('finish')){ expectToFinish++; } this.setObjectAttributes(l, i.data, io.object, io.source, 1); gameEngine.activeObjects.add(io.object); if (this.env != 'GameDesigner'){ if (i.data.$go?.type == 'player3d'){ let hero = new Hero(gameEngine, io); }else{ if (io.source?.animations?.length){ gameEngine.playAnimation(gameEngine.scene, io.source.animations[0]); } if (!i.data.noPhysics){ let bb = getBoundingBox(io.object); let bbs = getBoundingBoxSize(bb); gameEngine.physics.add(io.object, 'fixed', false, undefined, 'capsule', { radius: Math.max(bbs.x, bbs.z)/2, halfHeight: bbs.y/2 }) } } io.addEventListener('finish', ()=>{ finished ++; if (!i.data.pointsGiven){ gameEngine.dashboard?.addPoints(i.data.points) } i.data.pointsGiven = true; this.scene.data.items.forEach(di=>{ if (di.data.activationTriggers?.includes(i.data.id)){ let idx = di.data.activationTriggers.indexOf(i.data.id) di.data.activationTriggers.splice(idx, 1); } if (!di.data.activationTriggers?.length && di.__io.object.__active === false && gameEngine.dashboard.points > di.data.activationScore){ di.__io.activator.activate(); } }); if (finished == expectToFinish){ //GO TO NEXT LEVEL console.log('LEVEL FINISHED') } }); io.addEventListener('sceneSwitch', (e)=>{ console.log(e); this.scenesList = [this.scenes.find(s=>s.data.id == e.scene)] }) } loaded += 1/this.scene.data.items.length gameEngine.dashboard?.loading(0.1 + 0.89*loaded); } } if (this.scene.data.$intro && this.env != 'GameDesigner'){ intro = await new VideoPlayer(gameEngine, { $go: this.scene.data.$intro, skipTransition: true, playInHud: true }); gameEngine.activeObjects.add(intro.object); intro.video.addEventListener('pause',()=>{ intro.object.removeFromParent(); gameEngine.clickable.remove(intro.object); //TODO!!!! gameEngine.activeObjects.visible = true; gameEngine.showBackground(true); }); }else{ gameEngine.activeObjects.visible = true; gameEngine.showBackground(true); } gameEngine.dashboard?.loading(1) gameEngine.physics.start(); }, targetPointerDown(){ this.pointerDownTime = performance.now(); }, targetClick(e){ if (this.env == 'GameDesigner'){ if (performance.now() - this.pointerDownTime < 200){ let intersects = gameEngine.intersect(e, this.$refs.target, gameEngine.activeObjects.children, true); //console.log(intersects) if (intersects.length){ //console.log('attaching controls to', intersects[0].object) //gameEngine.transformControls.attach(intersects[0].object); //console.log(this.sceneObjects[intersects[0].object.__pn_id]) this.objectsList[0] = this.sceneObjects[intersects[0].object.__pn_id] }else{ gameEngine.transformControls.detach(); } } }else{ gameEngine.onClick(e, this.$refs.target); } }, targetPointer(e, t){ gameEngine.onPointer(e, this.$refs.target, t); }, setObjectAttributes(l, data, object, source, autoScaleFactor = 1){ if (l[data.id]){ ['position', 'scale', 'rotation'].forEach(p=>{ object[p].copy(l[data.id][p]) }) }else if (!data.type || data.type == 'GenericObject'){ autoScale(object, autoScaleFactor); } l[data.id] = l[data.id] || {}; ['position', 'scale', 'rotation', 'visible'].forEach(p=>{ l[data.id][p] = object[p]; }) l[data.id].__o = object; l[data.id].__g = source; l[data.id].__title = data.title; object.__pn_id = data.id; }, async toggleAnimation(animation){ animation.playing = !animation.playing; gameEngine.playAnimation(gameEngine.scene, animation.a, animation.playing); }, resize(){ let r = this.$refs.target; console.log('resizing!!', r.clientWidth, r.clientHeight, r) gameEngine.resize(r.clientWidth, r.clientHeight); //this.zoom = Math.min(r.clientWidth / this.viewBox.w, r.clientHeight / this.viewBox.h); }, control(){ gameEngine.hero.lockControls(); }, async fullScreen(){ console.log(gameEngine.renderer.domElement); await gameEngine.renderer.domElement.requestFullscreen() } } }