/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* Ball.js :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: edbernar diffTop) { speed *= -1; this.setCastShadow(true); } else this.setCastShadow(false); if (this.interval) clearInterval(this.interval); this.interval = setInterval(() => { this.object.position.y += speed; if ((speed > 0 && this.object.position.y >= this.limits.up) || (speed < 0 && this.object.position.y <= this.limits.down)) { clearInterval(this.interval); this.interval = null; if (speed > 0) this.setPosition(this.object.position.x, this.limits.up, this.object.position.z); else this.setPosition(this.object.position.x, this.limits.down, this.object.position.z); } speed -= speed * slower; }, 10); } updatePos(content) { if(content.game_time == 0) this.start = performance.now() let gameTime = performance.now() - this.start if(content.game_time > gameTime) this.start -= content.game_time - gameTime this.srvPos = { time : content.game_time, pos : [content.pos[0], content.pos[1]], vel : content.velocity } } getBetterPositions() { let walls = [] // let jumpers = [] for(let x = 0; x < map.arrObject.length; x++) { // if(map.arrObject[x].type == "jumperBottom" || map.arrObject[x].type == "jumperTop") // { // let jumper = map.arrObject[x] // jumpers.push({pos:[jumper.mesh.children[0].position.x,jumper.mesh.children[0].position.z], // isUp : jumper.type == "jumperTop"}) // } if(map.arrObject[x].type == "wallObstacle") { let wall = map.arrObject[x] walls.push({pos:[wall.mesh.position.x, wall.mesh.position.z],isUp:wall.isUp}) } } return({walls:walls/*,jumpers:jumpers*/}) } hitPlayer(ballSlope, ballOffset, ballVel) { let playerPos = ballVel[0] < 0 ? opponent.object.position.x : player.object.position.x let limit = this.mapLimits.front if(ballVel[1] < 0) limit *= -1 let hitPos = this.lineIntersect(limit, ballSlope, ballOffset) let relPos = hitPos - playerPos return(Math.abs(relPos) < this.playerLength / 2) } closestTimeMapLimit(ballSlope, ballOffset, ballPos, ballVel) { let time = Infinity; let tmpTime = Infinity; if(ballVel[0] < 0) { let dist = ballPos[0] - this.mapLimits.left time = dist / Math.abs(ballVel[0]) } else if(ballVel[0] > 0) { let dist = this.mapLimits.right - ballPos[0] time = dist / Math.abs(ballVel[0]) } if(ballVel[1] < 0) { let dist = ballPos[1] - this.mapLimits.back tmpTime = dist / Math.abs(ballVel[1]) } if(ballVel[1] > 0) { let dist = this.mapLimits.front - ballPos[1] tmpTime = dist / Math.abs(ballVel[1]) } if(tmpTime < time && this.hitPlayer(ballSlope, ballOffset, ballVel)) return([2, tmpTime]) return([1, time]) } lineIntersect(line, ballSlope, ballOffset) { return((line - ballOffset) / ballSlope) } getWallHitTime(walls, ballSlope, ballOffset, ballPos, ballVel, ballUp) { let wallSide = (this.wallWidth / 2) + this.ballRadius if(ballVel[1] > 0) wallSide *= -1 let hitPos = this.lineIntersect(wallSide, ballSlope, ballOffset) let finalTime = Infinity for(let i = 0; i < walls.length; i++) { if(walls[i].isUp != ballUp) continue; let relPos = walls[i].pos[0] - hitPos if(Math.abs(relPos) < (this.wallLength / 2) + this.ballRadius) { let time = (hitPos - ballPos[0]) / ballVel[0] if(time > 0 && time < finalTime) finalTime = time } } return(finalTime) } getNextPosTime(obstacles, ballPos,ballVel, ballUp) { let hitDir; let time; let nextPos = [ballPos[0] + ballVel[0], ballPos[1] + ballVel[1]] let ballSlope = (nextPos[1] - ballPos[1]) / (nextPos[0] - ballPos[0]) let ballOffset = ballPos[1] - (ballSlope * ballPos[0]); [hitDir, time] = this.closestTimeMapLimit(ballSlope, ballOffset, ballPos, ballVel) let wallHitTime = this.getWallHitTime(obstacles.walls, ballSlope, ballOffset, ballPos, ballVel, ballUp) if(wallHitTime > 0 && wallHitTime < time) [hitDir ,time] = [2, wallHitTime] ballVel[hitDir - 1] *= -1 return([time, ballVel]) } calcNewPos(delta,obstacles, ballPos, ballVel, ballUp) { //kill me let iter = 0 if((ballVel[0] == 0 && ballVel[1] == 0) || delta <= 0) return(ballPos) while(1) { let time; let nextVel; [time, nextVel] = this.getNextPosTime(obstacles, ballPos, [...ballVel], ballUp) if((time * 1000) > delta) return([ballPos[0] + (ballVel[0] * (delta / 1000)),ballPos[1] + (ballVel[1] * (delta /1000))]) ballPos[0] += ballVel[0] * time ballPos[1] += ballVel[1] * time ballVel = nextVel delta -= time * 1000 this.object.material.color.set(0xffffff) iter++; if(iter == 50) return([0,0]) } } update() { // TODO: m[ae]th this.object.material.color.set(0xff5555) let gameTime = performance.now() - this.start let lastPosDelta = gameTime - this.srvPos.time let ballPos = [...this.srvPos.pos]; let ballVel = [...this.srvPos.vel]; let ballUp = this.object.position.y > (this.limits.up / 2) let betterPositions = this.getBetterPositions() let newPos = this.calcNewPos(lastPosDelta,betterPositions, ballPos, ballVel, ballUp) this.object.position.set(newPos[0], this.object.position.y, newPos[1]); this.updateTrail(); } updateTrail() { const trailColors = trailGeometry.attributes.customColor.array; for (let i = trailPositions.length - 3; i >= 3; i--) trailPositions[i] = trailPositions[i - 3]; trailPositions[0] = this.object.position.x; trailPositions[1] = this.object.position.y; trailPositions[2] = this.object.position.z; for (let i = 0; i < 33; i++) trailSizes[i] = Math.max(0.5 * (1 - i / 33), 0.1); for (let i = 0; i < 33; i++) { const alpha = Math.max(1 - i / 33, 0); trailColors[i * 4] = 1.0 / Math.max(this.srvPos.vel[0] < 0 ? - this.srvPos.vel[0] : this.srvPos.vel[0], 0.3); trailColors[i * 4 + 1] = 1.0 / Math.max(this.srvPos.vel[1] < 0 ? - this.srvPos.vel[1] : this.srvPos.vel[1], 0.3); trailColors[i * 4 + 2] = 1.0 / Math.max((this.srvPos.vel[0] < 0 ? - this.srvPos.vel[0] : this.srvPos.vel[0]) + this.srvPos.vel[1] < 0 ? - this.srvPos.vel[1] : this.srvPos.vel[1], 0.3); trailColors[i * 4 + 3] = alpha; } trailGeometry.attributes.position.needsUpdate = true; trailGeometry.attributes.size.needsUpdate = true; trailGeometry.attributes.customColor.needsUpdate = true; } dispose() { if (this.interval) clearInterval(this.interval); this.interval = null; if (this.object) { if (this.object.geometry) this.object.geometry.dispose(); if (this.object.material) this.object.material.dispose(); if (this.object.texture) this.object.texture.dispose(); } this.object = null; } } let trailGeometry = null; let trailPositions = null; let trailMaterial = null; let trailSizes = null; let trail = null; const vertexShader = ` attribute float size; attribute vec4 customColor; varying vec4 vColor; void main() { vColor = customColor; // Envoie la couleur de la particule vec4 mvPosition = modelViewMatrix * vec4(position, 1.0); gl_PointSize = size * (300.0 / -mvPosition.z); gl_Position = projectionMatrix * mvPosition; } `; const fragmentShader = ` varying vec4 vColor; // Reçoit la couleur et l'alpha du vertex shader void main() { gl_FragColor = vColor; // Utilise la couleur avec l'alpha } `; function makeParticules(scene) { trailGeometry = new THREE.BufferGeometry(); trailPositions = new Float32Array(99); trailGeometry.setAttribute('position', new THREE.BufferAttribute(trailPositions, 3)); trailSizes = new Float32Array(33); trailGeometry.setAttribute('size', new THREE.BufferAttribute(trailSizes, 1)); const trailColors = new Float32Array(132); trailGeometry.setAttribute('customColor', new THREE.BufferAttribute(trailColors, 4)); trailMaterial = new THREE.ShaderMaterial({ vertexShader: vertexShader, fragmentShader: fragmentShader, transparent: true, blending: THREE.AdditiveBlending }); trail = new THREE.Points(trailGeometry, trailMaterial); scene.add(trail); } export { Ball };