From d7aa2b633b7919e39d0f6f31f4e0d32c20752045 Mon Sep 17 00:00:00 2001 From: LuckyLaszlo Date: Wed, 26 Oct 2022 22:21:55 +0200 Subject: [PATCH] local pong done, start multiplayer implementation --- make.sh | 9 +- src/client/class/GameArea.ts | 36 +++ src/client/{class.ts => class/Rectangle.ts} | 119 +--------- src/client/class/Text.ts | 53 +++++ src/client/class/Vector.ts | 45 ++++ src/client/class/interface.ts | 18 ++ src/client/draw.ts | 40 ++++ src/client/gameLoop.ts | 60 +++++ src/client/handleInput.ts | 46 ++++ src/client/pong.html | 8 +- src/client/pong.ts | 232 +++----------------- src/client/utils.ts | 6 + src/server/server.ts | 1 - www/favicon.ico | Bin 0 -> 15406 bytes 14 files changed, 350 insertions(+), 323 deletions(-) create mode 100644 src/client/class/GameArea.ts rename src/client/{class.ts => class/Rectangle.ts} (61%) create mode 100644 src/client/class/Text.ts create mode 100644 src/client/class/Vector.ts create mode 100644 src/client/class/interface.ts create mode 100644 src/client/draw.ts create mode 100644 src/client/gameLoop.ts create mode 100644 src/client/handleInput.ts create mode 100644 src/client/utils.ts create mode 100644 www/favicon.ico diff --git a/make.sh b/make.sh index f4ad7416..5a4999f6 100644 --- a/make.sh +++ b/make.sh @@ -1,4 +1,11 @@ #!/bin/bash npx tsc + mkdir -p www -cp ./src/client/*.js ./src/client/*.html ./www/ \ No newline at end of file +cp ./src/client/*.html ./www/ + +mkdir -p www/js +cp ./src/client/*.js ./www/js/ + +mkdir -p www/js/class +cp ./src/client/class/*.js ./www/js/class/ diff --git a/src/client/class/GameArea.ts b/src/client/class/GameArea.ts new file mode 100644 index 00000000..fc775c58 --- /dev/null +++ b/src/client/class/GameArea.ts @@ -0,0 +1,36 @@ + +class GameArea { + keys: string[]; + interval: number = 0; + canvas: HTMLCanvasElement; + ctx: CanvasRenderingContext2D; + constructor() { + this.keys = []; + this.canvas = document.createElement("canvas"); + this.ctx = this.canvas.getContext("2d") as CanvasRenderingContext2D; + /* ratio 5/3 (1.66) */ + const ratio = 1.66666; + this.canvas.width = 1500; + this.canvas.height = this.canvas.width / ratio; + let container = document.getElementById("canvas-container"); + if (container) + container.insertBefore(this.canvas, container.childNodes[0]); + } + addKey(key: string) { + key = key.toLowerCase(); + var i = this.keys.indexOf(key); + if (i == -1) + this.keys.push(key); + } + deleteKey(key: string) { + key = key.toLowerCase(); + var i = this.keys.indexOf(key); + if (i != -1) + this.keys.splice(i, 1); + } + clear() { + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + } +} + +export {GameArea} diff --git a/src/client/class.ts b/src/client/class/Rectangle.ts similarity index 61% rename from src/client/class.ts rename to src/client/class/Rectangle.ts index 929f293c..743eedca 100644 --- a/src/client/class.ts +++ b/src/client/class/Rectangle.ts @@ -1,60 +1,6 @@ -// type Vector = { -// x: number; -// y: number; -// } - -class Vector { - x: number; - y: number; - constructor(x: number = 0, y: number = 0) { - this.x = x; - this.y = y; - } - assign(x: number, y: number) { - this.x = x; - this.y = y; - } -} - -class VectorInteger extends Vector { - // PLACEHOLDER - // VectorInteger with set/get dont work (No draw on the screen). Why ? -} - -/* -class VectorInteger { - // private _x: number = 0; - // private _y: number = 0; - // constructor(x: number = 0, y: number = 0) { - // this._x = x; - // this._y = y; - // } - // get x(): number { - // return this._x; - // } - // set x(v: number) { - // // this._x = Math.floor(v); - // this._x = v; - // } - // get y(): number { - // return this._y; - // } - // set y(v: number) { - // // this._y = Math.floor(v); - // this._y = v; - // } -} -*/ - -interface Component { - pos: VectorInteger; - color: string; - ctx: CanvasRenderingContext2D; // TODO: reference in place of global 'pong.ctx' call - update(): void; - clear(): void; -} - +import {Vector, VectorInteger} from "./Vector.js"; +import {Component, Moving} from "./interface.js"; class Rectangle implements Component { ctx: CanvasRenderingContext2D; @@ -99,14 +45,6 @@ class Rectangle implements Component { } } - -interface Moving { - dir: Vector; - speed: number; - move(): void; -} - - class MovingRectangle extends Rectangle implements Moving { dir: Vector = new Vector(0,0); speed: number; @@ -136,14 +74,12 @@ class MovingRectangle extends Rectangle implements Moving { } } - class Player extends MovingRectangle { constructor(ctx: CanvasRenderingContext2D, pos: VectorInteger, color: string, width: number, height: number, baseSpeed: number) { super(ctx, pos, color, width, height, baseSpeed); } } - class Ball extends MovingRectangle { constructor(ctx: CanvasRenderingContext2D, pos: VectorInteger, color: string, size: number, baseSpeed: number) { super(ctx, pos, color, size, size, baseSpeed); @@ -180,55 +116,6 @@ class Ball extends MovingRectangle { } } -// conflict with Text -class TextElem implements Component { - ctx: CanvasRenderingContext2D; - pos: VectorInteger; - color: string; - size: number; - font: string; - text: string = ""; - constructor(ctx: CanvasRenderingContext2D, pos: VectorInteger, color: string, size: number, font: string = "Bit5x3") { - this.ctx = ctx; - this.pos = Object.assign({}, pos); - this.color = color; - this.size = size; - this.font = font; - } - update() { - this.ctx.font = this.size + "px" + " " + this.font; - this.ctx.fillStyle = this.color; - this.ctx.fillText(this.text, this.pos.x, this.pos.y); - } - clear() { - // clear no very accurate for Text - // https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics - let textMetric = this.ctx.measureText(this.text); - // console.log("textMetric.width = "+textMetric.width); - // console.log("size = "+this.size); - // console.log("x = "+this.pos.x); - // console.log("y = "+this.pos.y); - this.ctx.clearRect(this.pos.x - 1, this.pos.y-this.size + 1, textMetric.width, this.size); - // +1 and -1 because float imprecision (and Math.floor() with VectorInteger dont work for the moment) - // (or maybe its textMetric imprecision ?) - } -} - -class TextNumericValue extends TextElem { - private _value: number = 0; - constructor(ctx: CanvasRenderingContext2D, pos: VectorInteger, color: string, size: number, font?: string) { - super(ctx, pos, color, size, font); - } - get value() { - return this._value; - } - set value(v: number) { - this._value = v; - this.text = v.toString(); - } -} - - class Line extends Rectangle { gapeCount: number = 0; segmentCount: number; @@ -264,4 +151,4 @@ class Line extends Rectangle { } } -export {Vector, VectorInteger, Rectangle, MovingRectangle, Player, Ball, TextElem, TextNumericValue, Line} +export {Rectangle, MovingRectangle, Player, Ball, Line} diff --git a/src/client/class/Text.ts b/src/client/class/Text.ts new file mode 100644 index 00000000..4c7e675a --- /dev/null +++ b/src/client/class/Text.ts @@ -0,0 +1,53 @@ + +import {Vector, VectorInteger} from "./Vector.js"; +import {Component, Moving} from "./interface.js"; + +// conflict with Text +class TextElem implements Component { + ctx: CanvasRenderingContext2D; + pos: VectorInteger; + color: string; + size: number; + font: string; + text: string = ""; + constructor(ctx: CanvasRenderingContext2D, pos: VectorInteger, color: string, size: number, font: string = "Bit5x3") { + this.ctx = ctx; + this.pos = Object.assign({}, pos); + this.color = color; + this.size = size; + this.font = font; + } + update() { + this.ctx.font = this.size + "px" + " " + this.font; + this.ctx.fillStyle = this.color; + this.ctx.fillText(this.text, this.pos.x, this.pos.y); + } + clear() { + // clear no very accurate for Text + // https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics + let textMetric = this.ctx.measureText(this.text); + // console.log("textMetric.width = "+textMetric.width); + // console.log("size = "+this.size); + // console.log("x = "+this.pos.x); + // console.log("y = "+this.pos.y); + this.ctx.clearRect(this.pos.x - 1, this.pos.y-this.size + 1, textMetric.width, this.size); + // +1 and -1 because float imprecision (and Math.floor() with VectorInteger dont work for the moment) + // (or maybe its textMetric imprecision ?) + } +} + +class TextNumericValue extends TextElem { + private _value: number = 0; + constructor(ctx: CanvasRenderingContext2D, pos: VectorInteger, color: string, size: number, font?: string) { + super(ctx, pos, color, size, font); + } + get value() { + return this._value; + } + set value(v: number) { + this._value = v; + this.text = v.toString(); + } +} + +export {TextElem, TextNumericValue} diff --git a/src/client/class/Vector.ts b/src/client/class/Vector.ts new file mode 100644 index 00000000..278394a1 --- /dev/null +++ b/src/client/class/Vector.ts @@ -0,0 +1,45 @@ + +class Vector { + x: number; + y: number; + constructor(x: number = 0, y: number = 0) { + this.x = x; + this.y = y; + } + assign(x: number, y: number) { + this.x = x; + this.y = y; + } +} + +class VectorInteger extends Vector { + // PLACEHOLDER + // VectorInteger with set/get dont work (No draw on the screen). Why ? +} + +/* +class VectorInteger { + // private _x: number = 0; + // private _y: number = 0; + // constructor(x: number = 0, y: number = 0) { + // this._x = x; + // this._y = y; + // } + // get x(): number { + // return this._x; + // } + // set x(v: number) { + // // this._x = Math.floor(v); + // this._x = v; + // } + // get y(): number { + // return this._y; + // } + // set y(v: number) { + // // this._y = Math.floor(v); + // this._y = v; + // } +} +*/ + +export {Vector, VectorInteger} diff --git a/src/client/class/interface.ts b/src/client/class/interface.ts new file mode 100644 index 00000000..a06ef28e --- /dev/null +++ b/src/client/class/interface.ts @@ -0,0 +1,18 @@ + +import {Vector, VectorInteger} from "./Vector.js"; + +interface Component { + pos: VectorInteger; + color: string; + ctx: CanvasRenderingContext2D; + update(): void; + clear(): void; +} + +interface Moving { + dir: Vector; + speed: number; + move(): void; +} + +export {Component, Moving} diff --git a/src/client/draw.ts b/src/client/draw.ts new file mode 100644 index 00000000..5cacdfa5 --- /dev/null +++ b/src/client/draw.ts @@ -0,0 +1,40 @@ +import * as g from "./pong.js" +import {gridDisplay} from "./handleInput.js"; + +function draw() +{ + if (gridDisplay) { + drawGrid(); + } + g.midLine.update(); + g.score1.update(); + g.score2.update(); +} + +function drawStatic() +{ + g.wall_top.update(); + g.wall_bottom.update(); + g.midLine.update(); +} + +function drawInit() +{ + g.pong.clear(); + drawStatic(); + g.player1.update(); + g.player2.update(); +} + +function drawGrid() +{ + g.w_grid_mid.update(); + g.w_grid_u1.update(); + g.w_grid_d1.update(); + + g.h_grid_mid.update(); + g.h_grid_u1.update(); + g.h_grid_d1.update(); +} + +export {draw, drawStatic, drawInit, drawGrid} diff --git a/src/client/gameLoop.ts b/src/client/gameLoop.ts new file mode 100644 index 00000000..fdecf9ab --- /dev/null +++ b/src/client/gameLoop.ts @@ -0,0 +1,60 @@ +import * as g from "./pong.js" +import * as d from "./draw.js"; +import {random} from "./utils.js"; +import {handleInput} from "./handleInput.js"; + +let ballInPlay = true; + +function gameLoop() +{ + /* + // I try to clear only what need to be update. + // Will revert to clear() all if not satisfactory. + pong.clear(); + */ + handleInput(); + + if (ballInPlay) + { + g.ball.moveAndBounce([g.wall_top, g.wall_bottom, g.player1, g.player2]); + if (g.ball.pos.x > g.pong.canvas.width) { + ballInPlay = false; + g.score1.clear(); + ++g.score1.value; + setTimeout(newRound, 1500); + } + else if (g.ball.pos.x < 0 - g.ball.width) { + ballInPlay = false; + g.score2.clear(); + ++g.score2.value; + setTimeout(newRound, 1500); + } + } + + d.draw(); +} + +function newRound() +{ + // https://fr.wikipedia.org/wiki/Tennis_de_table#Nombre_de_manches + if (g.score1.value >= 11 + || g.score2.value >= 11) + { + if (Math.abs(g.score1.value - g.score2.value) >= 2) + { + if (g.score1.value > g.score2.value) { + alert("Player 1 WIN"); + } + else { + alert("Player 2 WIN"); + } + return; + } + } + g.ball.pos.x = g.pong.canvas.width/2; + g.ball.pos.y = (g.pong.canvas.height * 0.1) + Math.floor(random() * (g.pong.canvas.height * 0.8)); + g.ball.speed = g.ball.baseSpeed; + ballInPlay = true; +} + +export {gameLoop} diff --git a/src/client/handleInput.ts b/src/client/handleInput.ts new file mode 100644 index 00000000..c8beda70 --- /dev/null +++ b/src/client/handleInput.ts @@ -0,0 +1,46 @@ +import * as g from "./pong.js" +import * as d from "./draw.js"; + +let gridDisplay = false; + +function handleInput() +{ + var keys = g.pong.keys; + if (keys.length == 0) + return; + + if (keys.indexOf("g") != -1) + { + if (gridDisplay) + { + g.pong.clear(); + d.drawStatic(); + } + gridDisplay = !gridDisplay; + g.pong.deleteKey("g"); + } + playerMove(keys); +} + +function playerMove(keys: string[]) +{ + g.player1.dir.y = 0; + if (keys.indexOf("w") != -1) { + g.player1.dir.y += -1; + } + if (keys.indexOf("s") != -1) { + g.player1.dir.y += 1; + } + g.player1.moveAndCollide([g.wall_top, g.wall_bottom]); + + g.player2.dir.y = 0; + if (keys.indexOf("ArrowUp".toLowerCase()) != -1) { + g.player2.dir.y += -1; + } + if (keys.indexOf("ArrowDown".toLowerCase()) != -1) { + g.player2.dir.y += 1; + } + g.player2.moveAndCollide([g.wall_top, g.wall_bottom]); +} + +export {handleInput, gridDisplay} diff --git a/src/client/pong.html b/src/client/pong.html index 22e61091..976f2aa4 100644 --- a/src/client/pong.html +++ b/src/client/pong.html @@ -4,9 +4,9 @@