import { MazeObject } from "./MazeObject"; import Utils from "#/app/Utils"; import { EventManager } from '@/lib/EventManager'; const params = { scale: 3, wallSize: 3 * 1.2, tubeSize: 3 * 1.2, } const imgParams = { type: 'ImageObject', width: params.wallSize*0.033, height: params.wallSize*0.033, value: 'arrow.webp', path: '/static/meshes/quiz/', distance: params.wallSize*3 } const textParams = { type: 'TextObject', maxWidth:0.44, fontPath:'/static/fonts/Montserrat-Regular.ttf', fontSize:0.025, distance: params.wallSize*3 } const defaults = { arrows:{ r: len => ({ position:[-.5,.25,len+.9], rotation:[0,Math.PI, 0], ...imgParams }), l: len => ({ position:[.5,.25,len+.9], rotation:[0,Math.PI, Math.PI], ...imgParams }), f: len => ({ position:[0,.37,len+.96], rotation:[0,Math.PI, Math.PI/2], ...imgParams }) }, answers:{ r: (len, text) => ({ ...textParams, text, position:[-.5,.3,len+.9], rotation:[0,Math.PI, 0] }), l: (len, text) => ({ ...textParams, text, position:[.5,.3,len+.9], rotation:[0,Math.PI, 0] }), f: (len, text) => ({ ...textParams, anchorY:'top', text, position:[0,.3,len+.9], rotation:[0,Math.PI, 0] }) } } const tl = 4; class MazeQuizGame extends EventManager { emits = ['finish', 'sceneSwitch', 'interaction'] constructor(engine, data) { super(); this.data = data; data.noPhysics = true; this.params = { ...params, mazeFile: data.style || 'quiz-s2.gltf', io: this } this.maxPoints = (data.points || 0) + (data.questionPoints||0) * data.questions.length; this.minPoints = this.maxPoints - (data.questionPenalty||0) * data.questions.length; return new Promise(async (resolve, reject)=>{ let questions = data.shuffle ? Utils.shuffleArray(data.questions) : data.questions; let def = this.generate(questions); this.mazeObject = new MazeObject(engine, def, this.params) engine.addEventListener('collision', async e=>{ let ud1 = engine.physics.world.getCollider(e.handle1)?.parent()?.userData, ud2 = engine.physics.world.getCollider(e.handle2)?.parent()?.userData; let ud = {...ud1, ...ud2} //console.log('collision', ud) if (ud.finish){ if (e.started){ engine.dashboard.levelProgress.update(1) engine.hero.animationsMap._idle = engine.hero.animationsMap.idle if ( engine.hero.animationsMap?.win){ engine.hero.animationsMap.idle = engine.hero.animationsMap.win } // await Utils.wait(1000); // engine.hero.cameraDelta = Math.PI; // engine.hero.direction += Math.PI; //engine.hero.model.rotation.y += Math.PI; engine.motionQueue.add({ o: engine.hero, a:{cameraDelta: k=>k*Math.PI*4 }, t: 12 }); this.dispatchEvent({type:'finish'}) }else{ engine.hero.animationsMap.idle = engine.hero.animationsMap._idle engine.hero.cameraDelta = 0 } } if (ud.qid !== undefined && e.started){ engine.dashboard.updateText(ud.question.q) engine.dashboard.levelProgress.update(ud.qid / questions.length) this.dispatchEvent({type:'interaction'}); } if (ud.corner && e.started){ let q = ud.corner.question; if (!q.pointsAdded){ let qid = data.questions.indexOf(q); if (!ud.corner.penalty){ q.pointsAdded = true; engine.dashboard.addPoints(data.questionPoints - !!q.applyPenalty * data.questionPenalty) engine.tm?.post('answer', null, { question: qid, correct: true }); }else{ q.applyPenalty = true; engine.tm?.post('answer', null, { question: qid, correct: false }); } } } //console.log(e, ud, engine.hero?.animationsMap); }) await this.mazeObject.load(); this.object = this.mazeObject.object; resolve(this); }) } generate(questions, qid = 0, len){ let question = questions[qid] len = len || Math.round(Math.random()*tl) + 2; if (!question) return { len, userData: { finish: true }, objects:[ // { // type: 'GltfObject', // position:[0,.22,len + .52], scale: [0.33, 0.33, 0.33], rotation: [0, Math.PI/4, 0], // value: 'trophy.glb', path: imgParams.path, distance: params.wallSize*2, // motion: { a:{rotation: { y: k=>k*Math.PI*2 }}, r: true, t: 4 } // } { type: 'SceneSwitcher', switchScene: this.data.switchScene, switchType: this.data.switchType, position:[0,.22,len + .52], scale: [0.33, 0.33, 0.33], distance: this.params.wallSize*4 } ] }; let directions = Utils.shuffleArray( ['l', 'r', 'f'] ) let mo = { len, userData: { question, qid }, objects:[ { ...textParams, text: question.q, fontSize:0.033, maxWidth:0.55, position:[0,.55,len + .96], rotation:[0,Math.PI, 0] } ] } question.a.filter(a=>!!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 = Math.random() > 0.5 ? 'l' : 'r'; }else { dd = d == 'l' ? 'r' : 'l' } if (i == 0){ let next = this.generate(questions, qid + 1, 5) next.userData.corner = { question }; mo[d] = { len: 5, [dd]: next } }else{ mo[d] = { userData: { question, qid, answer: i }, len: 5, [dd]: { userData: { corner: { question, penalty: true } }, len: 3, objects:[ { ...textParams, color:0xc71414, text: question.h, fontSize:0.033, maxWidth:0.66, position:[0,.44,3+.96], rotation:[0,Math.PI, 0] },{ ...imgParams, value:'x.webp', position:[0,.33,3+.96], rotation:[0,Math.PI, 0] } ] } } } if (d == 'f'){ mo[d].len = 2; if (i == 0){ let path = mo[d][dd]; mo[d][dd] = { len: 1, [dd == 'r' ? 'l' : 'r']: path } } } }) return mo; } } export { MazeQuizGame }