From f73932c131a03466f2dc9d6d7572674ccbd8ddfc Mon Sep 17 00:00:00 2001 From: LuckyLaszlo Date: Thu, 1 Dec 2022 17:48:34 +0100 Subject: [PATCH] multiBalls refactoring with ballsArr[] --- src/client/class/GameComponentsClient.ts | 16 ++--- src/client/draw.ts | 9 +-- src/client/gameLoop.ts | 9 +-- src/client/ws.ts | 25 ++++---- src/server/class/GameSession.ts | 82 +++++++++--------------- src/shared_js/class/Event.ts | 28 ++------ src/shared_js/class/GameComponents.ts | 36 +++++++---- src/shared_js/constants.ts | 2 + src/shared_js/utils.ts | 11 +++- 9 files changed, 97 insertions(+), 121 deletions(-) diff --git a/src/client/class/GameComponentsClient.ts b/src/client/class/GameComponentsClient.ts index 047e3589..2ab6aefe 100644 --- a/src/client/class/GameComponentsClient.ts +++ b/src/client/class/GameComponentsClient.ts @@ -11,9 +11,7 @@ class GameComponentsExtensionForClient extends GameComponents { wallBottom: RectangleClient; playerLeft: RacketClient; playerRight: RacketClient; - ball: BallClient; - ball2?: BallClient; - ball3?: BallClient; + ballsArr: BallClient[]; constructor(options: en.MatchOptions, ctx: CanvasRenderingContext2D) { super(options); @@ -21,12 +19,12 @@ class GameComponentsExtensionForClient extends GameComponents { this.wallBottom = new RectangleClient(this.wallBottom.pos, this.wallBottom.width, this.wallBottom.height, ctx, "grey"); this.playerLeft = new RacketClient(this.playerLeft.pos, this.playerLeft.width, this.playerLeft.height, this.playerLeft.baseSpeed, ctx, "white"); this.playerRight = new RacketClient(this.playerRight.pos, this.playerRight.width, this.playerRight.height, this.playerRight.baseSpeed, ctx, "white"); - this.ball = new BallClient(this.ball.pos, this.ball.width, this.ball.baseSpeed, this.ball.speedIncrease, ctx, "white"); - if (options & en.MatchOptions.multiBalls) - { // ALTERNATIVE POSSIBLE, Array of balls - this.ball2 = new BallClient(this.ball2.pos, this.ball2.width, this.ball2.baseSpeed, this.ball2.speedIncrease, ctx, "white"); - this.ball3 = new BallClient(this.ball3.pos, this.ball3.width, this.ball3.baseSpeed, this.ball3.speedIncrease, ctx, "white"); - } + + const newBallsArr: BallClient[] = []; + this.ballsArr.forEach((ball) => { + newBallsArr.push(new BallClient(ball.pos, ball.width, ball.baseSpeed, ball.speedIncrease, ctx, "white")); + }); + this.ballsArr = newBallsArr; } } diff --git a/src/client/draw.ts b/src/client/draw.ts index 848633da..5d87e7a6 100644 --- a/src/client/draw.ts +++ b/src/client/draw.ts @@ -25,12 +25,9 @@ function drawDynamic() gc.scoreRight.update(); gc.playerLeft.update(); gc.playerRight.update(); - gc.ball.update(); - if (c.optionsPLACEHOLDER & en.MatchOptions.multiBalls) - { // ALTERNATIVE POSSIBLE, Array of balls - gc.ball2.update(); - gc.ball3.update(); - } + gc.ballsArr.forEach((ball) => { + ball.update(); + }); } function drawStatic() diff --git a/src/client/gameLoop.ts b/src/client/gameLoop.ts index 55d53f82..76773e58 100644 --- a/src/client/gameLoop.ts +++ b/src/client/gameLoop.ts @@ -23,12 +23,9 @@ function gameLoop() } // client prediction - gc.ball.moveAndBounce(delta_time, [gc.wallTop, gc.wallBottom, gc.playerLeft, gc.playerRight]); - if (c.optionsPLACEHOLDER & en.MatchOptions.multiBalls) - { // ALTERNATIVE POSSIBLE, Array of balls - gc.ball2.moveAndBounce(delta_time, [gc.wallTop, gc.wallBottom, gc.playerLeft, gc.playerRight]); - gc.ball3.moveAndBounce(delta_time, [gc.wallTop, gc.wallBottom, gc.playerLeft, gc.playerRight]); - } + gc.ballsArr.forEach((ball) => { + ball.moveAndBounce(delta_time, [gc.wallTop, gc.wallBottom, gc.playerLeft, gc.playerRight]); + }); } function opponentInterpolation(delta: number) diff --git a/src/client/ws.ts b/src/client/ws.ts index 559f0c83..aea26ed0 100644 --- a/src/client/ws.ts +++ b/src/client/ws.ts @@ -90,20 +90,17 @@ function gameUpdate(data: ev.EventGameUpdate) { console.log("gameUpdate"); - 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 (c.optionsPLACEHOLDER & en.MatchOptions.multiBalls) - { // ALTERNATIVE POSSIBLE, Array of balls - gc.ball2.pos.assign(data.ball2.x, data.ball2.y); - gc.ball2.dir.assign(data.ball2.dirX, data.ball2.dirY); - gc.ball2.speed = data.ball2.speed; - - gc.ball3.pos.assign(data.ball3.x, data.ball3.y); - gc.ball3.dir.assign(data.ball3.dirX, data.ball3.dirY); - gc.ball3.speed = data.ball3.speed; - } + data.ballsArr.forEach((ball, i) => { + gc.ballsArr[i].pos.assign(ball.x, ball.y); + gc.ballsArr[i].dir.assign(ball.dirX, ball.dirY); + gc.ballsArr[i].speed = ball.speed; + }); + /* // Equivalent to + gc.ballsArr.forEach((ball, i) => { + ball.pos.assign(data.ballsArr[i].x, data.ballsArr[i].y); + ball.dir.assign(data.ballsArr[i].dirX, data.ballsArr[i].dirY); + ball.speed = data.ballsArr[i].speed; + }); */ const predictionPos = new VectorInteger(clientInfo.racket.pos.x, clientInfo.racket.pos.y); // debug diff --git a/src/server/class/GameSession.ts b/src/server/class/GameSession.ts index adb5cb1a..f25f11d4 100644 --- a/src/server/class/GameSession.ts +++ b/src/server/class/GameSession.ts @@ -20,6 +20,7 @@ class GameSession { clientsUpdateInterval: NodeJS.Timer | number = 0; components: GameComponentsServer; matchOptions: en.MatchOptions; + matchEnded: boolean = false; actual_time: number; last_time: number; @@ -31,14 +32,14 @@ class GameSession { this.components = new GameComponentsServer(this.matchOptions); } start() { - setTimeout(this.resume, c.matchStartDelay, this); const gc = this.components; - setTimeout(this._newRound, c.matchStartDelay + c.newRoundDelay, this, gc.ball); - if (this.matchOptions & en.MatchOptions.multiBalls) - { // ALTERNATIVE POSSIBLE, Array of balls - setTimeout(this._newRound, c.matchStartDelay + c.newRoundDelay + c.newRoundDelay*0.33, this, gc.ball2); - setTimeout(this._newRound, c.matchStartDelay + c.newRoundDelay + c.newRoundDelay*0.66, this, gc.ball3); - } + setTimeout(this.resume, c.matchStartDelay, this); + + let timeout = c.matchStartDelay + c.newRoundDelay; + gc.ballsArr.forEach((ball) => { + setTimeout(this._newRound, timeout, this, ball); + timeout += c.newRoundDelay*0.5; + }); } resume(s: GameSession) { s.playersMap.forEach( (client) => { @@ -91,35 +92,26 @@ class GameSession { }); */ const gc = s.components; - s._ballMovement(s.delta_time, gc.ball); - if (s.matchOptions & en.MatchOptions.multiBalls) - { // ALTERNATIVE POSSIBLE, Array of balls - s._ballMovement(s.delta_time, gc.ball2); - s._ballMovement(s.delta_time, gc.ball3); - } - /* - gc.ballArr.forEach( (ball) => { - s._ballMovement(s.delta_time, ball); - }); - */ + gc.ballsArr.forEach((ball) => { + s._ballMovement(s.delta_time, ball); + }); } private _ballMovement(delta: number, ball: Ball) { const gc = this.components; if (ball.ballInPlay) { ball.moveAndBounce(delta, [gc.wallTop, gc.wallBottom, gc.playerLeft, gc.playerRight]); - if (ball.pos.x > c.w) { + if (ball.pos.x > c.w + || ball.pos.x < 0 - ball.width) + { ball.ballInPlay = false; - ++gc.scoreLeft; - this.playersMap.forEach( (client) => { - client.socket.send(JSON.stringify(new ev.EventScoreUpdate(gc.scoreLeft, gc.scoreRight))); - }); - setTimeout(this._newRound, c.newRoundDelay, this, ball); - } - else if (ball.pos.x < 0 - ball.width) { - ball.ballInPlay = false; - ++gc.scoreRight; - + if (this.matchEnded) { + return; + } + + if (ball.pos.x > c.w) { ++gc.scoreLeft; } + else if (ball.pos.x < 0 - ball.width) { ++gc.scoreRight; } + this.playersMap.forEach( (client) => { client.socket.send(JSON.stringify(new ev.EventScoreUpdate(gc.scoreLeft, gc.scoreRight))); }); @@ -132,27 +124,16 @@ class GameSession { const update = new ev.EventGameUpdate(); update.playerLeft.y = gc.playerLeft.pos.y; update.playerRight.y = gc.playerRight.pos.y; - - update.ball.x = gc.ball.pos.x; - update.ball.y = gc.ball.pos.y; - update.ball.dirX = gc.ball.dir.x; - update.ball.dirY = gc.ball.dir.y; - update.ball.speed = gc.ball.speed; - if (s.matchOptions & en.MatchOptions.multiBalls) - { // ALTERNATIVE POSSIBLE, Array of balls - update.ball2.x = gc.ball2.pos.x; - update.ball2.y = gc.ball2.pos.y; - update.ball2.dirX = gc.ball2.dir.x; - update.ball2.dirY = gc.ball2.dir.y; - update.ball2.speed = gc.ball2.speed; - - update.ball3.x = gc.ball3.pos.x; - update.ball3.y = gc.ball3.pos.y; - update.ball3.dirX = gc.ball3.dir.x; - update.ball3.dirY = gc.ball3.dir.y; - update.ball3.speed = gc.ball3.speed; - } - + gc.ballsArr.forEach((ball) => { + update.ballsArr.push({ + x: ball.pos.x, + y: ball.pos.y, + dirX: ball.dir.x, + dirY: ball.dir.y, + speed: ball.speed + }); + }); + s.playersMap.forEach( (client) => { update.lastInputId = client.lastInputId; client.socket.send(JSON.stringify(update)); @@ -176,6 +157,7 @@ class GameSession { ball.ballInPlay = true; } private _matchEnd(s: GameSession) { + s.matchEnded = true; const gc = s.components; let eventEnd: ev.EventMatchEnd; diff --git a/src/shared_js/class/Event.ts b/src/shared_js/class/Event.ts index d8849e10..7694605b 100644 --- a/src/shared_js/class/Event.ts +++ b/src/shared_js/class/Event.ts @@ -32,27 +32,13 @@ class EventGameUpdate extends ServerEvent { playerRight = { y: 0 }; - ball = { - x: 0, - y: 0, - dirX: 0, - dirY: 0, - speed: 0 - }; - ball2? = { // ALTERNATIVE POSSIBLE, Array of balls - x: 0, - y: 0, - dirX: 0, - dirY: 0, - speed: 0 - }; - ball3? = { - x: 0, - y: 0, - dirX: 0, - dirY: 0, - speed: 0 - }; + ballsArr: { + x: number, + y: number, + dirX: number, + dirY: number, + speed: number + }[] = []; lastInputId = 0; constructor() { // TODO: constructor that take GameComponentsServer maybe ? super(en.EventTypes.gameUpdate); diff --git a/src/shared_js/class/GameComponents.ts b/src/shared_js/class/GameComponents.ts index 16375851..4bb0d2c1 100644 --- a/src/shared_js/class/GameComponents.ts +++ b/src/shared_js/class/GameComponents.ts @@ -3,15 +3,14 @@ import * as c from "../constants.js" import * as en from "../../shared_js/enums.js" import { VectorInteger } from "./Vector.js"; import { Rectangle, Racket, Ball } from "./Rectangle.js"; +import { clamp, random } from "../utils.js"; class GameComponents { wallTop: Rectangle; wallBottom: Rectangle; playerLeft: Racket; playerRight: Racket; - ball: Ball; - ball2?: Ball; - ball3?: Ball; + ballsArr: Ball[] = []; constructor(options: en.MatchOptions) { let pos = new VectorInteger; @@ -26,18 +25,27 @@ class GameComponents { pos.assign(c.w-c.pw-c.pw, c.h_mid-c.ph/2); this.playerRight = new Racket(pos, c.pw, c.ph, c.racketSpeed); - pos.assign(-c.ballSize, -c.ballSize); // ball out =) - this.ball = new Ball(pos, c.ballSize, c.ballSpeed, c.ballSpeedIncrease); - this.ball.dir.assign(-0.8, +0.2); - - if (options & en.MatchOptions.multiBalls) - { // ALTERNATIVE POSSIBLE, Array of balls - pos.assign(-c.ballSize, -c.ballSize); // ball out =) - this.ball2 = new Ball(pos, c.ballSize, c.ballSpeed, c.ballSpeedIncrease); - this.ball2.dir.assign(-0.8, +0.2); - this.ball3 = new Ball(pos, c.ballSize, c.ballSpeed, c.ballSpeedIncrease); - this.ball3.dir.assign(-0.8, +0.2); + let ballsCount = 1; + if (options & en.MatchOptions.multiBalls) { + ballsCount = c.multiBallsCount; } + pos.assign(-c.ballSize, -c.ballSize); // ball out =) + while (this.ballsArr.length < ballsCount) { + this.ballsArr.push(new Ball(pos, c.ballSize, c.ballSpeed, c.ballSpeedIncrease)) + } + this.ballsArr.forEach((ball) => { + ball.dir.x = 1; + if (random() > 0.5) { + ball.dir.x *= -1; + } + + ball.dir.y = clamp(random(), 0, 0.2); + if (random() > 0.5) { + ball.dir.y *= -1; + } + + ball.dir = ball.dir.normalized(); + }); } } diff --git a/src/shared_js/constants.ts b/src/shared_js/constants.ts index 886d7a55..cd76f51e 100644 --- a/src/shared_js/constants.ts +++ b/src/shared_js/constants.ts @@ -19,3 +19,5 @@ export const normalizedSpeed = false; // for consistency in speed independent of export const matchStartDelay = 3000; // millisecond export const newRoundDelay = 1500; // millisecond + +export const multiBallsCount = 3; diff --git a/src/shared_js/utils.ts b/src/shared_js/utils.ts index b1746e9e..50feb05f 100644 --- a/src/shared_js/utils.ts +++ b/src/shared_js/utils.ts @@ -7,4 +7,13 @@ function sleep (ms: number) { return new Promise((resolve) => setTimeout(resolve, ms)); } -export {random, sleep} +function clamp(n: number, min: number, max: number) : number +{ + if (n < min) + n = min; + else if (n > max) + n = max; + return (n); +} + +export {random, sleep, clamp}