import { BoxGeometry, Mesh, MeshStandardMaterial, Group, Vector3 } from 'three'; import { LineGeometry } from 'three/examples/jsm/Addons.js'; import { LineMaterial } from 'three/examples/jsm/Addons.js'; import { Line2 } from 'three/examples/jsm/Addons.js'; import { centerOrigin } from '@/lib/MeshUtils'; import { EventManager } from '@/lib/EventManager'; import Utils from '@/lib/Utils'; class PairMatchingGame extends EventManager { emits = ['finish'] 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, // 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); mesh.position.set(xi * dx, o[xi][i] * dy, 0); mesh.userData.gd = { pair: xi, id: i } container.add(mesh); } } let clicked, done = []; let connect = (a, b)=>{ let g = new LineGeometry(); g.setFromPoints([ a.position, new Vector3().copy(a.position).lerpVectors(a.position, b.position, 0.5).multiplyScalar(1.1), b.position ]); let m = new Line2(g, new LineMaterial( { color: 0x00FF00, linewidth: 5, // in world units with size attenuation, pixels otherwise dashed: false, alphaToCoverage: true, } )); container.add(m) } let clickFn = (i) => { let oc = clicked; clicked = i.object; if (done.includes(clicked.userData.gd.id)) return; if (oc && oc.userData.gd.pair != clicked.userData.gd.pair){ oc.scale.setScalar(1); clicked.scale.setScalar(1); if (oc.userData.gd.id === clicked.userData.gd.id){ connect(oc, clicked); done.push(oc.userData.gd.id) }else{ clicked = null; } }else{ clicked.scale.setScalar(1.2); } }; container.children.forEach(c => { engine.clickable.add(c, clickFn); }); this.update = () => { }; this.object = centerOrigin(container); resolve(this); }) } } export { PairMatchingGame }