import { BoxGeometry, Mesh, MeshStandardMaterial, Group, Vector3, CatmullRomCurve3} from 'three'; import { LineMaterial, LineGeometry, Line2 } from 'three/examples/jsm/Addons.js'; import { EventManager } from '@/lib/EventManager'; import Utils from '#/app/Utils'; class PairMatchingGame extends EventManager { emits = ['finish', 'interaction'] constructor(engine, data) { super(); return new Promise(async (resolve, reject)=>{ let container = new Group(); let c = data.c, orderArray = Array.from({length:c}, (_, i)=>i); let o = [ Utils.shuffleArray(orderArray), Utils.shuffleArray(orderArray) ] const aq = engine.motionQueue; let dx = 3, dy = 1.2; let bm = new BoxGeometry(1, 1, 1); let material = new MeshStandardMaterial({ map: await engine.loadTexture(data.$go.asset.name), alphaTest: 0.5, emissive: 0x00ff00, emissiveIntensity: 0 // roughness:1, metalness:0, // normalMap: await engine.loadTexture('NormalMap.png', '/static/textures/'), }); //material.map.encoding = sRGBEncoding; for (let i = 0; i < c; i++) { let b = [], uv = [], p = []; for (let xi = 0; xi < 2; xi++){ b[xi] = bm.clone(); uv[xi] = b[xi].getAttribute('uv'); let s = [xi/2, i / c]; for (let i = 0; i < 6; i++) { //top left uv[xi].array[8 * i] = s[0]; uv[xi].array[8 * i + 1] = s[1] + 1 / c; //top right uv[xi].array[8 * i + 2] = s[0] + 1 / 2; uv[xi].array[8 * i + 3] = s[1] + 1 / c; //bottom left uv[xi].array[8 * i + 4] = s[0]; uv[xi].array[8 * i + 5] = s[1]; //bottom right uv[xi].array[8 * i + 6] = s[0] + 1 / 2; uv[xi].array[8 * i + 7] = s[1]; } let mesh = new Mesh(b[xi], material.clone()); mesh.position.set(xi * dx + Math.random() * (xi+0.5) * dx, o[xi][i] * dy, Math.random() * (xi+0.5) * dx); mesh.userData.gd = { pair: xi, id: i } container.add(mesh); } } let clicked, done = []; let connect = (a, b)=>{ let crc = new CatmullRomCurve3([ a.position, new Vector3().copy(a.position).lerpVectors(a.position, b.position, 0.5).multiplyScalar(1 + Math.random() * 0.1 * done.length / c), b.position ]) let g = new LineGeometry().setFromPoints( crc.getPoints(7) ); let m = new Line2(g, new LineMaterial( { color: 0x00FF00, linewidth: 5, // in world units with size attenuation, pixels otherwise } )); container.add(m) } let actionDef = {material:{emissiveIntensity:k=>(1+Math.sin((k*2+1.5)*Math.PI))*4 }}; var clickFn = (i) => { this.dispatchEvent({type:'interaction'}); let oc = clicked; if (done.includes(i.object.userData.gd.id)) return; clicked = i.object; clicked.material.emissive.setHex(0x00ff00); if (oc && oc.userData.gd.pair != clicked.userData.gd.pair){ if (oc.userData.gd.id === clicked.userData.gd.id){ connect(oc, clicked); done.push(oc.userData.gd.id) if (done.length == c) { this.dispatchEvent({type:'finish'}) } }else{ clicked.material.emissive.setHex(0xff0000); oc.material.emissive.setHex(0xff0000); } aq.clear(oc, true); aq.add({ o: clicked, a: actionDef, t: 1 }); aq.add({ o: oc, a: actionDef, t: 1 }); clicked = null; }else{ aq.add({ o: clicked, a: actionDef, t: 1, r: true }) } }; container.children.forEach(c => { engine.clickable.add(c, clickFn); }); this.update = () => { }; this.object = engine.meshUtils.centerOrigin(container); this.dispose = () => { engine.meshUtils.clearMaterial(material); bm.dispose(); super.dispose(); } resolve(this); }) } } export { PairMatchingGame }