89 lines
3.5 KiB
JavaScript
89 lines
3.5 KiB
JavaScript
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 } |