diff --git a/src/client/gameLoop.ts b/src/client/gameLoop.ts index b8c7cafd..1b8d212d 100644 --- a/src/client/gameLoop.ts +++ b/src/client/gameLoop.ts @@ -1,5 +1,5 @@ -import { gc } from "./global.js"; +import { gc, clientInfo } from "./global.js"; let actual_time: number = Date.now(); let last_time: number; @@ -7,17 +7,31 @@ let delta_time: number; function gameLoop() { - /* - // I try to clear only what need to be update. - // Will revert to clear() all if not satisfactory. - pong.clear(); - */ last_time = actual_time; actual_time = Date.now(); delta_time = (actual_time - last_time) / 1000; + // interpolation + // console.log(`dir.y: ${clientInfo.opponent.dir.y}, pos.y: ${clientInfo.opponent.pos.y}, opponentNextPos.y: ${clientInfo.opponentNextPos.y}`); + if (clientInfo.opponent.dir.y != 0 ) { + opponentInterpolation(delta_time); + } + // client prediction gc.ball.moveAndBounce(delta_time, [gc.wallTop, gc.wallBottom, gc.playerLeft, gc.playerRight]); } +function opponentInterpolation(delta: number) +{ + // interpolation + clientInfo.opponent.moveAndCollide(delta, [gc.wallTop, gc.wallBottom]); + + if ((clientInfo.opponent.dir.y > 0 && clientInfo.opponent.pos.y > clientInfo.opponentNextPos.y) + || (clientInfo.opponent.dir.y < 0 && clientInfo.opponent.pos.y < clientInfo.opponentNextPos.y)) + { + clientInfo.opponent.dir.y = 0; + clientInfo.opponent.pos.y = clientInfo.opponentNextPos.y; + } +} + export {gameLoop} diff --git a/src/client/ws.ts b/src/client/ws.ts index e2d76537..ae4cc2e3 100644 --- a/src/client/ws.ts +++ b/src/client/ws.ts @@ -8,6 +8,7 @@ import { RacketClient } from "./class/RectangleClient.js"; import { repeatInput } from "./handleInput.js"; import { soundRoblox } from "./audio.js" import { sleep } from "./utils.js"; +import { Vector, VectorInteger } from "../shared_js/class/Vector.js"; const wsPort = 8042; const wsUrl = "ws://" + document.location.hostname + ":" + wsPort + "/pong"; @@ -17,6 +18,8 @@ class ClientInfo { id = ""; side: en.PlayerSide; racket: RacketClient; + opponent: RacketClient; + opponentNextPos: VectorInteger; } export const clientInfo = new ClientInfo(); @@ -43,12 +46,17 @@ function preMatchListener(this: WebSocket, event: MessageEvent) { break; case en.EventTypes.matchmakingComplete: clientInfo.side = (data).side; - if (clientInfo.side === en.PlayerSide.left) { + if (clientInfo.side === en.PlayerSide.left) + { clientInfo.racket = gc.playerLeft; + clientInfo.opponent = gc.playerRight; } - else if (clientInfo.side === en.PlayerSide.right) { + else if (clientInfo.side === en.PlayerSide.right) + { clientInfo.racket = gc.playerRight; + clientInfo.opponent = gc.playerLeft; } + clientInfo.opponentNextPos = new VectorInteger(clientInfo.opponent.pos.x, clientInfo.opponent.pos.y); clientInfo.racket.color = "darkgreen"; // for testing purpose socket.send(JSON.stringify( new ev.ClientEvent(en.EventTypes.clientPlayerReady) )); matchmakingComplete(); @@ -66,7 +74,7 @@ function inGameListener(event: MessageEvent) const data: ev.ServerEvent = JSON.parse(event.data); switch (data.type) { case en.EventTypes.gameUpdate: - // setTimeout(gameUpdate, 1000, data as ev.EventGameUpdate); // artificial latency for testing purpose + // setTimeout(gameUpdate, 500, data as ev.EventGameUpdate); // artificial latency for testing purpose gameUpdate(data as ev.EventGameUpdate); break; case en.EventTypes.scoreUpdate: @@ -82,14 +90,36 @@ function gameUpdate(data: ev.EventGameUpdate) { console.log("gameUpdate"); - gc.playerLeft.pos.y = data.playerLeft.y; - gc.playerRight.pos.y = data.playerRight.y; - gc.ball.pos.assign(data.ball.x, data.ball.y); gc.ball.dir.assign(data.ball.dirX, data.ball.dirY); gc.ball.speed = data.ball.speed; + if (clientInfo.side === en.PlayerSide.left) { + clientInfo.racket.pos.assign(clientInfo.racket.pos.x, data.playerLeft.y); + } + else if (clientInfo.side === en.PlayerSide.right) { + clientInfo.racket.pos.assign(clientInfo.racket.pos.x, data.playerRight.y); + } - repeatInput(data.lastInputId); // server reconciliation + // interpolation + clientInfo.opponent.pos.assign(clientInfo.opponentNextPos.x, clientInfo.opponentNextPos.y); + if (clientInfo.side === en.PlayerSide.left) { + clientInfo.opponentNextPos.assign(clientInfo.opponent.pos.x, data.playerRight.y); + } + else if (clientInfo.side === en.PlayerSide.right) { + clientInfo.opponentNextPos.assign(clientInfo.opponent.pos.x, data.playerLeft.y); + } + + clientInfo.opponent.dir = new Vector( + clientInfo.opponentNextPos.x - clientInfo.opponent.pos.x, + clientInfo.opponentNextPos.y - clientInfo.opponent.pos.y + ); + + if (Math.abs(clientInfo.opponent.dir.x) + Math.abs(clientInfo.opponent.dir.y) !== 0) { + clientInfo.opponent.dir = clientInfo.opponent.dir.normalized(); + } + + // server reconciliation + repeatInput(data.lastInputId); } function scoreUpdate(data: ev.EventScoreUpdate) diff --git a/src/shared_js/class/Rectangle.ts b/src/shared_js/class/Rectangle.ts index b8fdeb75..3fc10310 100644 --- a/src/shared_js/class/Rectangle.ts +++ b/src/shared_js/class/Rectangle.ts @@ -42,9 +42,7 @@ class MovingRectangle extends Rectangle implements Moving { this.speed = baseSpeed; } move(delta: number) { // Math.floor WIP until VectorInteger debug - // console.log("delta: "+ delta); - // console.log("speed: "+ this.speed); - // console.log("speed*delta: "+ this.speed * delta); + // console.log(`delta: ${delta}, speed: ${this.speed}, speed*delta: ${this.speed * delta}`); this.pos.x += Math.floor(this.dir.x * this.speed * delta); this.pos.y += Math.floor(this.dir.y * this.speed * delta); }