194 lines
7.6 KiB
JavaScript
194 lines
7.6 KiB
JavaScript
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 } |