From 8f817eee147629250abfacaa3fb94a19b0f01902 Mon Sep 17 00:00:00 2001 From: goynov Date: Tue, 21 Oct 2025 18:50:52 +0300 Subject: [PATCH] amaze --- src/components/GamePlaying/GamePlaying.vue | 35 +++--- .../MazeQuizGame/MazeObject.js | 97 +++++++++-------- .../MazeQuizGame/MazeQuizGame.js | 100 ++++++++++++------ .../InteractiveObjects/TextObject.js | 4 +- .../InteractiveObjects/VideoPlayer.vue | 2 +- src/components/SceneDesigner/GameObject.vue | 2 +- src/components/SceneDesigner/Scene.vue | 2 +- .../SceneDesigner/SceneDesigner.vue | 2 +- src/components/SceneDesigner/SvgRectangle.vue | 2 +- src/components/SceneDesigner/Task.vue | 2 +- src/lib/CharacterControls.js | 2 +- src/lib/{gameEngine.js => GameEngine.js} | 2 +- src/lib/{utils.js => Utils.js} | 5 + 13 files changed, 157 insertions(+), 100 deletions(-) rename src/lib/{gameEngine.js => GameEngine.js} (97%) rename src/lib/{utils.js => Utils.js} (86%) diff --git a/src/components/GamePlaying/GamePlaying.vue b/src/components/GamePlaying/GamePlaying.vue index 2618bf1..d40e055 100644 --- a/src/components/GamePlaying/GamePlaying.vue +++ b/src/components/GamePlaying/GamePlaying.vue @@ -158,7 +158,8 @@ export default { } }, async loadEnvironment(scene, target){ - await gameEngine.loadPanorama(`/asset/default/55/panorama-vaya.webp`); + //await gameEngine.loadPanorama(`/asset/default/55/panorama-vaya.webp`); + await gameEngine.loadPanorama(`/asset/default/36.jpg`); await this.expandScenarioData(scene); //gameEngine.activeObjects.scale.set(0.033, 0.033, 0.033) gameEngine.activeObjects.clear(); @@ -224,30 +225,30 @@ export default { // vp.object.rotation.y += -Math.PI/2; let maze = new MazeQuizGame(gameEngine, {}, [ - {s: 'Кое е най-голямото езеро в България', h: 'Wrong answer', a: true}, - {s: '1 + 1 = 2', h: 'Wrong answer', a: true}, - {s: '1 + 1 = 2', h: 'Wrong answer', a: true}, - {s: '1 + 1 = 2', h: 'Wrong answer', a: true}, + {q: 'Атанасовското езеро е дълго около 10км.', a:['Вярно', 'Невярно'], h: 'Грешен отговор. Атанасовското езеро е дълго около 10км.'}, + {q: 'Колко дълбоко е Атанасовското езеро?', a:['Около 35см', 'Около 3.5м', 'Метър и половина'], h: 'Атанасовското езеро е дълбоко средно около 35см.'}, + {q: 'Колко вида птици се наблюдават в Атанасовското езеро?', a: ['Повече от 330 вида', 'Над 10 вида', 'Над 450 вида'], h: 'В Атанасовското езеро са наблюдавани над 330 вида птици'}, + {q: 'Какво е Via Pontica?', a: ['Миграционният път на птиците, минаващ покрай Бургаските езера', 'Рядък вид птица', 'Местност в гр. Бургас'], h: 'Via Pontica наричаме миграционния път на птиците'}, ]) maze.load().then(o=>{ gameEngine.activeObjects.add(o); //o.scale.set(5,5,5); }) - new Grass(Grass.positions(1000,50,50), '/static/textures/grass01.png', 1, .5).then(mesh=>{ - console.log('adding grass') - gameEngine.scene.add(mesh); - }) + // new Grass(Grass.positions(1000,50,50), '/static/textures/grass01.png', 1, .5).then(mesh=>{ + // console.log('adding grass') + // gameEngine.scene.add(mesh); + // }) - new Grass(Grass.positions(250,50,50), '/static/textures/flowers01.png', 1, .75).then(mesh=>{ - gameEngine.scene.add(mesh); - console.log('adding grass') - }) + // new Grass(Grass.positions(250,50,50), '/static/textures/flowers01.png', 1, .75).then(mesh=>{ + // gameEngine.scene.add(mesh); + // console.log('adding grass') + // }) - new Grass(Grass.positions(250,50,50), '/static/textures/flowers02.png', 1, .75).then(mesh=>{ - gameEngine.scene.add(mesh); - console.log('adding grass') - }) + // new Grass(Grass.positions(250,50,50), '/static/textures/flowers02.png', 1, .75).then(mesh=>{ + // gameEngine.scene.add(mesh); + // console.log('adding grass') + // }) }, async expandScenarioData(scene){ scene.data.$environment = (await this.$api.gameObject.load(scene.data.environment)).data diff --git a/src/components/InteractiveObjects/MazeQuizGame/MazeObject.js b/src/components/InteractiveObjects/MazeQuizGame/MazeObject.js index 7755359..3ec460b 100644 --- a/src/components/InteractiveObjects/MazeQuizGame/MazeObject.js +++ b/src/components/InteractiveObjects/MazeQuizGame/MazeObject.js @@ -42,17 +42,65 @@ class MazeObject { po.rigidBody.setRotation(quat, true) } + 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()) + + e[0].position.set(0, 0, offsetZ + context.wallSize/2); + + e[1].rotateY(_tf.rotation.b); + + e[2].rotateY(_tf.rotation.r); + e[3].rotateY(_tf.rotation.f); + e[4].rotateY(_tf.rotation.l); + + e[1].position.set(0, 0, offsetZ + 0); + + e[2].position.set(-context.wallSize/2, 0, offsetZ + context.wallSize/2); + e[3].position.set(0, 0, offsetZ + context.wallSize); + e[4].position.set(context.wallSize/2, 0, offsetZ + context.wallSize/2); + + if (elements[1] == 'wall'){ + addPhysics(def.matrix, [0, 0, offsetZ], context.wallSize, 'front') + } + + if (elements[2] == 'wall'){ + addPhysics(def.matrix, [-context.wallSize/2, 0, offsetZ + context.wallSize/2], context.wallSize) + } + + if (elements[3] == 'wall'){ + addPhysics(def.matrix, [0, 0, offsetZ + context.wallSize], context.wallSize, 'front') + } + + if (elements[4] == 'wall'){ + addPhysics(def.matrix, [context.wallSize/2, 0, offsetZ + context.wallSize/2], context.wallSize) + } + + e.forEach(g => { + g.applyMatrix4(def.matrix); + root.add(g); + }); + } + this.mazeObject = function(def, room, step = 0) { if (!def.matrix){ def.matrix = new Matrix4(); } let offsetZ = 0, e; def.len = def.len || 0; - // if (step == 0) { - // e = o.door.clone(); - // e.rotateY(_tf.rotation.f); - // mazeMeshes.push(e); - // } + if (step == 0) { + // e = o.door.clone(); + // e.rotateY(_tf.rotation.f); + // mazeMeshes.push(e); + addRoom(['floor', 'wall', 'wall', 'door', 'wall'], def, -context.wallSize) + } for (let i = 0; i < def.len; i++) { let t = o.tunnel.clone(); t.position.set(0, 0, i * context.tubeSize); @@ -72,44 +120,7 @@ class MazeObject { addPhysics(def.matrix, [context.tubeSize / 2, 0.6, offsetZ/2], offsetZ) addPhysics(def.matrix, [-context.tubeSize / 2, 0.6, offsetZ/2], 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() - ]; - - e[0].position.set(0, 0, offsetZ + context.wallSize/2); - - e[1].rotateY(_tf.rotation.b); - - e[2].rotateY(_tf.rotation.r); - e[3].rotateY(_tf.rotation.f); - e[4].rotateY(_tf.rotation.l); - - e[1].position.set(0, 0, offsetZ + 0); - - e[2].position.set(-context.wallSize/2, 0, offsetZ + context.wallSize/2); - e[3].position.set(0, 0, offsetZ + context.wallSize); - e[4].position.set(context.wallSize/2, 0, offsetZ + context.wallSize/2); - - if (!def.r){ - addPhysics(def.matrix, [-context.wallSize/2, 0, offsetZ + context.wallSize/2], context.wallSize) - } - - if (!def.f){ - addPhysics(def.matrix, [0, 0, offsetZ + context.wallSize], context.wallSize, 'front') - } - - if (!def.l){ - addPhysics(def.matrix, [context.wallSize/2, 0, offsetZ + context.wallSize/2], context.wallSize) - } - - e.forEach(g => { - g.applyMatrix4(def.matrix); - root.add(g); - }); + addRoom(['floor', 'door', def.r ? 'door' : 'wall', def.f ? 'door' : 'wall', def.l ? 'door' : 'wall'], def, offsetZ) def.objects && def.objects.forEach(async obj => { obj.room = room; diff --git a/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.js b/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.js index d05fa42..e4ec63f 100644 --- a/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.js +++ b/src/components/InteractiveObjects/MazeQuizGame/MazeQuizGame.js @@ -1,9 +1,24 @@ import { MazeObject } from "./MazeObject"; +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,.73,len+.96], rotation:[0,Math.PI, Math.PI/2], scale: [0.03, 0.03, 0.03] }) + }, + answers:{ + r: (len, text) => ({ type: 'text', text, position:[-.5,.3,len+.9], rotation:[0,Math.PI, 0] }), + l: (len, text) => ({ type: 'text', text, position:[.5,.3,len+.9], rotation:[0,Math.PI, 0] }), + f: (len, text) => ({ type: 'text', text, position:[0,.7,len+.9], rotation:[0,Math.PI, 0] }) + } +} + +const tl = 4; class MazeQuizGame { constructor(engine, context, questions) { let def = this.generate(questions); - console.log(def) this.mazeObject = new MazeObject(engine, def) } @@ -16,40 +31,65 @@ class MazeQuizGame { generate(questions, idx = 0){ let cq = questions[idx] if (!cq) return {}; - let len = Math.round(Math.random()*4) + 2; - let lr = Math.round(Math.random()*4) + 2; - let lrv = Math.random() > 0.5; - return { + let len = Math.round(Math.random()*tl) + 2; + + let l = { + l: Math.round(Math.random()*tl) + 2, + r: Math.round(Math.random()*tl) + 2, + f: Math.round(Math.random()*tl) + 2 + } + + let directions = Utils.shuffleArray( ['l', 'r', 'f'] ) + + let mo = { len, objects:[ { - type: 'text', text: cq.s, position:[0,.4,len+.96], rotation:[0,Math.PI, 0] - },{ - type: 'image', value: '/static/textures/arrow.png', position:[-.5,.44,len+.96], rotation:[0,Math.PI, 0], scale: [0.03, 0.03, 0.03] - },{ - type: 'text', text: 'Вярно', position:[-.5,.3,len+.9], rotation:[0,Math.PI, 0] - },{ - 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] - },{ - type: 'text', text: 'Невярно', position:[.5,.3,len+.9], rotation:[0,Math.PI, 0] + type: 'text', text: cq.q, position:[0,.4,len + .96], rotation:[0,Math.PI, 0] } - ], - [lrv?'r':'l']:{ - len: 10 - lr, - [lrv?'l':'r']: { - len: lr, - objects:[ - { - type: 'text', text: cq.h, position:[0,.44,lr+.96], rotation:[0,Math.PI, 0] - } - ] - } - }, - [lrv?'l':'r']:{ - len: lr, - [lrv?'r':'l']: this.generate(questions, idx + 1) - } + ] } + + cq.a.forEach((a, i)=>{ + let d = directions[i]; + mo.objects.push( + defaults.arrows[d](len), + defaults.answers[d](len, a) + ) + let dd; + if (d == 'f'){ + dd = l.l > l.r ? 'l' : 'r'; + }else { + dd = d == 'l' ? 'r' : 'l' + } + if (i == 0){ + mo[d] = { + len: l[d], + [dd]: this.generate(questions, idx + 1) + } + }else{ + mo[d] = { + len: l[d], + [dd]: { + len: 8 - l[d], + objects:[ + { + type: 'text', text: cq.h, position:[0,.44,8 - l[d]+.96], rotation:[0,Math.PI, 0] + } + ] + } + } + } + if (d == 'f'){ + let path = mo[d][dd]; + mo[d][dd] = { + len: 1, + [dd == 'r' ? 'l' : 'r']: path + } + } + }) + + return mo; } } diff --git a/src/components/InteractiveObjects/TextObject.js b/src/components/InteractiveObjects/TextObject.js index f0b394f..b519547 100644 --- a/src/components/InteractiveObjects/TextObject.js +++ b/src/components/InteractiveObjects/TextObject.js @@ -16,10 +16,10 @@ class TextObject { txt.anchorY = 'bottom'; txt.curveRadius = 0; txt.outlineColor = 0xffffff; - txt.outlineWidth = '1%'; + txt.outlineWidth = '15%'; txt.depthOffset = 0.1; //txt.outlineBlur = '50%'; - txt.color = new Color(0xffffff); + txt.color = new Color(0x0); assignParams(txt, obj) let m = new MeshStandardMaterial({ roughness: .73, diff --git a/src/components/InteractiveObjects/VideoPlayer.vue b/src/components/InteractiveObjects/VideoPlayer.vue index 2bedd65..8f66eb1 100644 --- a/src/components/InteractiveObjects/VideoPlayer.vue +++ b/src/components/InteractiveObjects/VideoPlayer.vue @@ -15,7 +15,7 @@