From 975763d20fc4554254dce9b60fa39983d1a2d73c Mon Sep 17 00:00:00 2001 From: tomoron Date: Fri, 4 Oct 2024 00:10:42 +0200 Subject: [PATCH] add client side colisions to reduce lag(add debuging, ball is white when client is predicting movement) --- .../djangoserver/file/server/server/Game.py | 22 ++- .../server/server/typeRequests/gameRequest.py | 3 +- .../static/javascript/multiOnlineGame/Ball.js | 184 ++++++++++++++++-- .../static/javascript/multiOnlineGame/Map.js | 3 +- .../javascript/typeResponse/typeGame.js | 12 ++ 5 files changed, 204 insertions(+), 20 deletions(-) diff --git a/docker-compose/requirements/djangoserver/file/server/server/Game.py b/docker-compose/requirements/djangoserver/file/server/server/Game.py index e4f536a..afe4b3c 100644 --- a/docker-compose/requirements/djangoserver/file/server/server/Game.py +++ b/docker-compose/requirements/djangoserver/file/server/server/Game.py @@ -6,7 +6,7 @@ # By: edbernar +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2024/09/09 16:10:26 by tomoron #+# #+# # -# Updated: 2024/09/30 15:35:47 by tomoron ### ########.fr # +# Updated: 2024/10/01 16:35:10 by tomoron ### ########.fr # # # # **************************************************************************** # @@ -38,6 +38,7 @@ from .gameActions.ping import ping # 5 : ball_move : send new directtion/movement to the client # - pos : [x, z] # - velocity : [x, z] +# - game_time : ms since start of game # # 6 : goal : someone scored a goal # - is_opponent diff --git a/docker-compose/requirements/nginx/static/javascript/multiOnlineGame/Ball.js b/docker-compose/requirements/nginx/static/javascript/multiOnlineGame/Ball.js index c3eea1b..b8466c5 100644 --- a/docker-compose/requirements/nginx/static/javascript/multiOnlineGame/Ball.js +++ b/docker-compose/requirements/nginx/static/javascript/multiOnlineGame/Ball.js @@ -11,6 +11,8 @@ /* ************************************************************************** */ import * as THREE from '/static/javascript/three/build/three.module.js' +import { map, opponent, player} from '/static/javascript/multiOnlineGame/multiOnlineGamePage.js' + class Ball { @@ -18,9 +20,25 @@ class Ball centerPos = {}; limits = {}; interval = null; - lastTime = 0; - velocity = [0, 0]; - lastPos = [0, 0, 0]; + start = 0; + srvPos = { + time : 0, + pos : [0, 0, 1], + vel : [0, 0] + } + ballRadius = 0.15 + + mapLimits = { + left : -3.5 + this.ballRadius, + right : 3.5 - this.ballRadius, + back : -6.25 + this.ballRadius, + front : 6.25 - this.ballRadius + } + + wallWidth = 0.1 + wallLength = 1 + + playerLength = 1 + (this.ballRadius * 4) constructor(scene, map) { @@ -95,17 +113,161 @@ class Ball updatePos(content) { - this.lastTime = new Date().getTime(); - this.lastPos = [content.pos[0], this.object.position.y, content.pos[1]]; - this.velocity = content.velocity; + 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() { - const deltaTime = ((new Date().getTime()) - this.lastTime) / 1000; - const x = this.lastPos[0] + (deltaTime * this.velocity[0]); - const z = this.lastPos[2] + (deltaTime * this.velocity[1]); - this.object.position.set(x, this.object.position.y, z); + // 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]); } dispose() @@ -127,4 +289,4 @@ class Ball } -export { Ball }; \ No newline at end of file +export { Ball }; diff --git a/docker-compose/requirements/nginx/static/javascript/multiOnlineGame/Map.js b/docker-compose/requirements/nginx/static/javascript/multiOnlineGame/Map.js index 5edeea9..b827015 100644 --- a/docker-compose/requirements/nginx/static/javascript/multiOnlineGame/Map.js +++ b/docker-compose/requirements/nginx/static/javascript/multiOnlineGame/Map.js @@ -361,6 +361,7 @@ class Map meshWallObs.position.set(x, this.playerLimits.up - 0.1, y); else meshWallObs.position.set(x, 0.4, y); + this.arrObject.push({mesh : meshWallObs, name:"", type:"wallObstacle", isUp:onTop}) return (meshWallObs); }; @@ -1075,4 +1076,4 @@ function createRing(colorO) { return new THREE.Mesh(geometry, material); } -export { Map, createStar, createBox, createRectangle, createRing, colorList }; \ No newline at end of file +export { Map, createStar, createBox, createRectangle, createRing, colorList }; diff --git a/docker-compose/requirements/nginx/static/javascript/typeResponse/typeGame.js b/docker-compose/requirements/nginx/static/javascript/typeResponse/typeGame.js index 6e25abf..4d78d59 100644 --- a/docker-compose/requirements/nginx/static/javascript/typeResponse/typeGame.js +++ b/docker-compose/requirements/nginx/static/javascript/typeResponse/typeGame.js @@ -14,8 +14,20 @@ import { MultiOnlineGamePage, opponent, ball, player, map } from "/static/javasc import { WaitingGamePage } from "/static/javascript/waitingGame/main.js" import { pageRenderer } from '/static/javascript/main.js' +let stopSrvUpdate = false + +document.addEventListener('keypress',(e)=>{ + if(e.key == 'q') + { + console.log("stopped server updates") + stopSrvUpdate = true + } +}); + function typeGame(content) { + if(stopSrvUpdate) + return if (pageRenderer.actualPage == WaitingGamePage) { if (content.action == 1)