massive interactive objects refactoring

This commit is contained in:
2026-04-04 10:57:43 +03:00
parent 401a6cb144
commit 6009d52139
30 changed files with 104 additions and 28 deletions
@@ -0,0 +1,139 @@
import { BoxGeometry, Mesh, MeshBasicMaterial, Group, VideoTexture } from 'three';
import { EventManager } from '@/lib/EventManager';
class PuzzleGame1 extends EventManager {
emits = ['finish', 'interaction']
constructor(engine, data) {
super();
return new Promise(async (resolve, reject)=>{
let w = data.w, h = data.h, wh = w*h;
let container = new Group();
const aq = engine.motionQueue;
const pr = [[0, 2], [0, -1], [0, 1], [1, 0], [-1, 0], [0, 0]];
let d = 1.2;
let bm = new BoxGeometry(1, 1, 1);
let map, vi;
if (data.$go.type == 'video'){
await new Promise((resolve, reject)=>{
vi = document.createElement('video');
vi.src = engine.assetPath + data.$go.asset.name;
vi.muted = true;
vi.addEventListener('loadedmetadata', async ()=>{
map = new VideoTexture( vi );
resolve();
}, { once: true });
})
}else{
map = await engine.loadTexture(data.$go.asset.name);
}
let material = new MeshBasicMaterial({
map,
// roughness:1, metalness:0,
// normalMap: await engine.loadTexture('NormalMap.png', '/static/textures/'),
});
//material.map.encoding = sRGBEncoding;
for (let i = 0; i < wh; i++) {
let b = bm.clone();
let uv = b.getAttribute('uv');
//0-8->R, 8-16->L, 16-24->Top, 24-32->Bottom, 32-40->Front, 40-48->Back
let x = i % w, y = Math.trunc(i / w);
let idxs = [(i+1) % wh, (i+2)%wh, (i+3)%wh, (i+4)%wh, i, y*w + w - x -1]
for (let i = 0; i < 6; i++) {
let idx = idxs[i];
let x = idx % w, y = Math.trunc(idx / w)
let s = [x / w, y / h];
//top left
uv.array[8 * i] = s[0];
uv.array[8 * i + 1] = s[1] + 1 / h;
//top right
uv.array[8 * i + 2] = s[0] + 1 / w;
uv.array[8 * i + 3] = s[1] + 1 / h;
//bottom left
uv.array[8 * i + 4] = s[0];
uv.array[8 * i + 5] = s[1];
//bottom right
uv.array[8 * i + 6] = s[0] + 1 / w;
uv.array[8 * i + 7] = s[1];
}
let mesh = new Mesh(b, material);
mesh.position.set((i % w) * d, (Math.trunc(i / w)) * d, 0);
let ri = Math.floor(Math.random() * 5);
mesh.rotation.set(pr[ri][0] * Math.PI / 2, pr[ri][1] * Math.PI / 2, 0);
mesh._ri = ri;
if (idxs[4] == idxs[5]){
mesh._dd = true;
}
container.add(mesh);
}
// container.children[0].onBeforeRender = () => {
// this.update();
// };
var check = () => {
let i = 0;
container.children.forEach(o=>{
if (o._ri == 5 || o._dd && o._ri == 0) i++;
})
return i == wh;
};
let clickFn = (i) => {
this.dispatchEvent({type:'interaction'});
if (vi?.paused) vi.play();
if (!this.done && !aq.isActive(i.object)) {
i.object._ri = (i.object._ri + 1) % 6;
aq.add({
o: i.object,
a: { rotation: { x: pr[i.object._ri][0] * Math.PI / 2, y: pr[i.object._ri][1] * Math.PI / 2 } },
t: .5,
s: 'PG2'
});
}
};
container.children.forEach(c => {
engine.clickable.add(c, clickFn);
});
this.update = () => {
if (aq.isIdle('PG2') && !this.done && check()) {
this.done = true;
container.children.forEach((c, i) => {
aq.add({
o: c,
a: { position: { x: i % w, y: Math.trunc(i/w)} },
t: 1,
f: i == 0 ? ()=>{
this.dispatchEvent({type:'finish'})
} : undefined,
s: 'PG2'
});
});
//engine.dashboard.addPoints(10);
}
};
engine.addEventListener('beforeRender', this.update)
this.object = engine.meshUtils.centerOrigin(container);
this.dispose = () => {
//console.log('disposing PG1')
engine.meshUtils.clearMaterial(material);
bm.dispose();
super.dispose();
}
resolve(this);
})
}
}
export { PuzzleGame1 }