import { Color, Group, DoubleSide, RepeatWrapping, MeshStandardMaterial } from "three" import { EventManager } from '@/lib/EventManager'; import { centerOrigin } from "@/lib/MeshUtils"; class ClassicPuzzle extends EventManager { emits = ['finish', 'interaction'] constructor(engine, data, objPrefix='Plane'){ super(); const container = new Group(); const that = this; return new Promise(async (resolve, reject)=>{ let gltf = await engine.load(`puzzle-${data.dimension}.glb`, '/static/meshes/classic-puzzle/'); let map = await engine.loadTexture(data.$go.asset.name); map.wrapS = RepeatWrapping; map.wrapT = RepeatWrapping; map.flipY = false; map.needsUpdate = true; let dragZone = gltf.scene.getObjectByName('DragZone'); dragZone.material.side = DoubleSide; let eventsFn= { start(){ that.dispatchEvent({type:'interaction'}); }, drag(){}, end(e){ if (Math.abs(e.o.position.x)<.1 && Math.abs(e.o.position.y)<.1){ e.o.position.set(0,0,0); engine.draggable.remove(e.o); e.o.material = doneMaterial; done++; if (done == pCount){ doneMaterial.emissiveIntensity = .5; engine.motionQueue.add({ o: doneMaterial, t:1.5, d:1, a:{ emissiveIntensity:0 }, f:()=>{ that.dispatchEvent({type:'finish'}) } }); } } } } let pCount = 0; dragZone.visible = false; let defaultMaterial = new MeshStandardMaterial({ map, emissiveIntensity: 0.05, lightMapIntensity: 10, side:DoubleSide, roughness: 1, metalness: 0, }) gltf.scene.children.forEach((o, i)=>{ if (o.name.startsWith(objPrefix)){ let pp = o.clone(); container.add(pp); defaultMaterial.emissiveMap ??= pp.material.emissiveMap; pp.material = defaultMaterial; pp.position.set(2*Math.random()-1, 2*Math.random() - 1, 0.01*(i+1)); engine.draggable.add(pp, dragZone, eventsFn); pCount++; } }); let doneMaterial = defaultMaterial.clone(); doneMaterial.emissive = new Color(10,114,10); defaultMaterial.emissive = new Color(114,10,10); engine.motionQueue.add( { o: defaultMaterial, r: true, t:1.5, d:1, rd:true, a:{emissiveIntensity:function(k){return .05*Math.sin(k*3.14);}} }); let done0 = container.children[Math.floor(Math.random() * container.children.length)]; let done = 1; done0.material = doneMaterial; done0.position.set(0,0,0); engine.draggable.remove(done0) container.add(dragZone); this.object = centerOrigin(container); resolve(this); }) } } export { ClassicPuzzle }