diff --git a/.gitignore b/.gitignore
index b58afaf9..ad799a41 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,9 +15,9 @@ Thumbs.db
*.log
.env
-jsconfig.json
node_modules
-build
+*.js
+www/**/*.html
large
old
diff --git a/jsconfig.json b/jsconfig.json
new file mode 100644
index 00000000..347bf03f
--- /dev/null
+++ b/jsconfig.json
@@ -0,0 +1,13 @@
+{
+ "compilerOptions": {
+ "module": "ESNext",
+ "moduleResolution": "Node",
+ "target": "ES2020",
+ "strictNullChecks": true,
+ "strictFunctionTypes": true
+ },
+ "exclude": [
+ "node_modules",
+ "**/node_modules/*"
+ ]
+}
\ No newline at end of file
diff --git a/make.sh b/make.sh
new file mode 100644
index 00000000..f4ad7416
--- /dev/null
+++ b/make.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+npx tsc
+mkdir -p www
+cp ./src/client/*.js ./src/client/*.html ./www/
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 3ea0eee0..f8a273e7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,9 +5,16 @@
"packages": {
"": {
"devDependencies": {
+ "@types/node": "^18.11.5",
"typescript": "^4.8.4"
}
},
+ "node_modules/@types/node": {
+ "version": "18.11.5",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.5.tgz",
+ "integrity": "sha512-3JRwhbjI+cHLAkUorhf8RnqUbFXajvzX4q6fMn5JwkgtuwfYtRQYI3u4V92vI6NJuTsbBQWWh3RZjFsuevyMGQ==",
+ "dev": true
+ },
"node_modules/typescript": {
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
@@ -23,6 +30,12 @@
}
},
"dependencies": {
+ "@types/node": {
+ "version": "18.11.5",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.5.tgz",
+ "integrity": "sha512-3JRwhbjI+cHLAkUorhf8RnqUbFXajvzX4q6fMn5JwkgtuwfYtRQYI3u4V92vI6NJuTsbBQWWh3RZjFsuevyMGQ==",
+ "dev": true
+ },
"typescript": {
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
diff --git a/package.json b/package.json
index 425985bb..2d65b5c7 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,7 @@
{
+ "type": "module",
"devDependencies": {
+ "@types/node": "^18.11.5",
"typescript": "^4.8.4"
}
}
diff --git a/src/client/class.ts b/src/client/class.ts
new file mode 100644
index 00000000..929f293c
--- /dev/null
+++ b/src/client/class.ts
@@ -0,0 +1,267 @@
+
+// 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;
+}
+
+
+class Rectangle implements Component {
+ ctx: CanvasRenderingContext2D;
+ pos: VectorInteger;
+ color: string;
+ width: number;
+ height: number;
+ constructor(ctx: CanvasRenderingContext2D, pos: VectorInteger, color: string, width: number, height: number) {
+ this.ctx = ctx;
+ this.pos = Object.assign({}, pos);
+ this.color = color;
+ this.width = width;
+ this.height = height;
+ }
+ update() {
+ this.ctx.fillStyle = this.color;
+ this.ctx.fillRect(this.pos.x, this.pos.y, this.width, this.height);
+ }
+ clear(pos?: VectorInteger) {
+ if (pos)
+ this.ctx.clearRect(pos.x, pos.y, this.width, this.height);
+ else
+ this.ctx.clearRect(this.pos.x, this.pos.y, this.width, this.height);
+ }
+ collision(collider: Rectangle): boolean { // Collision WIP. To redo
+ var myleft = this.pos.x;
+ var myright = this.pos.x + (this.width);
+ var mytop = this.pos.y;
+ var mybottom = this.pos.y + (this.height);
+ var otherleft = collider.pos.x;
+ var otherright = collider.pos.x + (collider.width);
+ var othertop = collider.pos.y;
+ var otherbottom = collider.pos.y + (collider.height);
+ if ((mybottom < othertop)
+ || (mytop > otherbottom)
+ || (myright < otherleft)
+ || (myleft > otherright)) {
+ return false;
+ }
+ else
+ return true;
+ }
+}
+
+
+interface Moving {
+ dir: Vector;
+ speed: number;
+ move(): void;
+}
+
+
+class MovingRectangle extends Rectangle implements Moving {
+ dir: Vector = new Vector(0,0);
+ speed: number;
+ readonly baseSpeed: number;
+ constructor(ctx: CanvasRenderingContext2D, pos: VectorInteger, color: string, width: number, height: number, baseSpeed: number) {
+ super(ctx, pos, color, width, height);
+ this.baseSpeed = baseSpeed;
+ this.speed = baseSpeed;
+ }
+ move() { // Math.floor WIP until VectorInteger debug
+ this.pos.x += Math.floor(this.dir.x * this.speed);
+ this.pos.y += Math.floor(this.dir.y * this.speed);
+ }
+ moveAndCollide(colliderArr: Rectangle[]) {
+ let oldPos = Object.assign({}, this.pos);
+ this.move();
+ if (colliderArr.some(this.collision, this))
+ {
+ this.pos.x = oldPos.x;
+ this.pos.y = oldPos.y;
+ }
+ else
+ {
+ this.clear(oldPos);
+ this.update();
+ }
+ }
+}
+
+
+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);
+ }
+ bounce(collider?: Rectangle) {
+ /* Could be more generic, but testing only player is enough,
+ because in Pong collider can only be Player or Wall. */
+ if (collider instanceof Player) {
+ this._bouncePlayer(collider);
+ }
+ else {
+ this._bounceWall();
+ }
+ }
+ moveAndBounce(colliderArr: Rectangle[]) {
+ let oldPos = Object.assign({}, this.pos);
+ this.move();
+ let i = colliderArr.findIndex(this.collision, this);
+ if (i != -1)
+ {
+ this.bounce(colliderArr[i]);
+ this.move();
+ }
+ this.clear(oldPos);
+ this.update();
+ }
+ private _bounceWall() { // Should be enough for Wall
+ this.dir.y = this.dir.y * -1;
+ }
+ private _bouncePlayer(collider: Player) { // WIP
+ // Bounce for Player need to be more complexe than this
+ this.speed += this.baseSpeed/20;
+ this.dir.x = this.dir.x * -1;
+ }
+}
+
+// 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;
+ segmentWidth: number;
+ segmentHeight: number;
+ constructor(ctx: CanvasRenderingContext2D, pos: VectorInteger, color: string, width: number, height: number, gapeCount?: number) {
+ super(ctx, pos, color, width, height);
+ if (gapeCount)
+ this.gapeCount = gapeCount;
+ this.segmentCount = this.gapeCount * 2 + 1;
+
+ this.segmentWidth = this.width;
+ this.segmentHeight = this.height / this.segmentCount;
+
+ // for Horizontal Line
+ // this.segmentWidth = this.width / this.segmentCount;
+ // this.segmentHeight = this.height;
+ }
+ update() {
+ this.ctx.fillStyle = this.color;
+ let pos: VectorInteger = new VectorInteger;
+ let i = 0;
+ while (i < this.segmentCount)
+ {
+ // for Horizontal Line
+ // pos.y = this.pos.y;
+ // pos.x = this.pos.x + this.segmentWidth * i;
+ pos.x = this.pos.x;
+ pos.y = this.pos.y + this.segmentHeight * i;
+ this.ctx.fillRect(pos.x, pos.y, this.segmentWidth, this.segmentHeight);
+ i += 2;
+ }
+ }
+}
+
+export {Vector, VectorInteger, Rectangle, MovingRectangle, Player, Ball, TextElem, TextNumericValue, Line}
diff --git a/src/pong.html b/src/client/pong.html
similarity index 81%
rename from src/pong.html
rename to src/client/pong.html
index 4f641946..22e61091 100644
--- a/src/pong.html
+++ b/src/client/pong.html
@@ -17,7 +17,7 @@
}
#canvas-container {
text-align: center;
- border: dashed red 5px;
+ /* border: dashed red 5px; */
/* max-height: 80vh; */
/* overflow: hidden; */
}
@@ -29,13 +29,12 @@
}
-
+
-
-
-
+
+
diff --git a/src/client/pong.ts b/src/client/pong.ts
new file mode 100644
index 00000000..b35208b5
--- /dev/null
+++ b/src/client/pong.ts
@@ -0,0 +1,277 @@
+
+/* Keys
+ Player 1: W/S
+ Player 2: Up/Down
+ Grid On-Off: G
+*/
+
+import {Vector, VectorInteger, Rectangle, MovingRectangle, Player, Ball, TextElem, TextNumericValue, Line} from "./class.js";
+// @ts-check
+
+let gridDisplay = false;
+let ballInPlay = true;
+
+let pong: gameArea;
+
+let wall_top: Rectangle;
+let wall_bottom: Rectangle;
+let player1: Player;
+let player2: Player;
+let ball: Ball;
+let score1: TextNumericValue;
+let score2: TextNumericValue;
+let midLine: Line;
+
+let w_grid_mid: Rectangle;
+let w_grid_u1: Rectangle;
+let w_grid_d1: Rectangle;
+let h_grid_mid: Rectangle;
+let h_grid_u1: Rectangle;
+let h_grid_d1: Rectangle;
+
+function startGame()
+{
+ pong = new gameArea();
+
+ // Const
+ const w = pong.canvas.width;
+ const h = pong.canvas.height;
+ const w_mid = Math.floor(w/2);
+ const h_mid = Math.floor(h/2);
+ const pw = Math.floor(w/50);
+ const ph = pw*5;
+ const ballSize = pw;
+ const scoreSize = Math.floor(w/16);
+ const midLineSize = Math.floor(w/150);
+ const wallSize = Math.floor(w/100);
+ const gridSize = Math.floor(w/500);
+ const playerSpeed = Math.floor(w/75);
+ const ballSpeed = Math.floor(w/75);
+
+ let pos = new VectorInteger;
+ // Component
+ pos.assign(0, 0);
+ wall_top = new Rectangle(pong.ctx, pos, "grey", w, wallSize);
+ pos.assign(0, h-wallSize);
+ wall_bottom = new Rectangle(pong.ctx, pos, "grey", w, wallSize);
+
+ pos.assign(0+pw, h_mid-ph/2);
+ player1 = new Player(pong.ctx, pos, "white", pw, ph, playerSpeed);
+ pos.assign(w-pw-pw, h_mid-ph/2);
+ player2 = new Player(pong.ctx, pos, "white", pw, ph, playerSpeed);
+
+ pos.assign(w_mid-ballSize/2, h_mid-ballSize/2);
+ ball = new Ball(pong.ctx, pos, "white", ballSize, ballSpeed);
+ ball.dir.assign(-0.8, +0.2);
+
+ pos.assign(w_mid-scoreSize*1.6, scoreSize*1.5);
+ score1 = new TextNumericValue(pong.ctx, pos, "white", scoreSize);
+ pos.assign(w_mid+scoreSize*1.1, scoreSize*1.5);
+ score2 = new TextNumericValue(pong.ctx, pos, "white", scoreSize);
+ score1.value = 0;
+ score2.value = 0;
+
+ pos.assign(w_mid-midLineSize/2, 0+wallSize);
+ midLine = new Line(pong.ctx, pos, "white", midLineSize, h-wallSize*2, 15);
+
+ // Grid
+ pos.assign(0, h_mid);
+ w_grid_mid = new Rectangle(pong.ctx, pos, "darkgreen", w, gridSize);
+ pos.assign(0, h/4);
+ w_grid_u1 = new Rectangle(pong.ctx, pos, "darkgreen", w, gridSize);
+ pos.assign(0, h-h/4);
+ w_grid_d1 = new Rectangle(pong.ctx, pos, "darkgreen", w, gridSize);
+ pos.assign(w_mid, 0);
+ h_grid_mid = new Rectangle(pong.ctx, pos, "darkgreen", gridSize, h);
+ pos.assign(w/4, 0);
+ h_grid_u1 = new Rectangle(pong.ctx, pos, "darkgreen", gridSize, h);
+ pos.assign(w-w/4, 0);
+ h_grid_d1 = new Rectangle(pong.ctx, pos, "darkgreen", gridSize, h);
+
+ // Start
+ score1.update(); // first Text draw init the custom font (graphic leftover ortherwise) (a better solution ?)
+ drawInit();
+ pong.start();
+}
+
+class gameArea {
+ keys: string[];
+ interval: number = 0;
+ canvas: HTMLCanvasElement;
+ ctx: CanvasRenderingContext2D;
+ constructor() {
+ this.keys = [];
+ // this.canvas = {};
+ this.canvas = document.createElement("canvas");
+ // this.ctx = {};
+ 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]);
+ }
+ start() {
+ this.interval = window.setInterval(gameLoop, 20);
+ window.addEventListener('keydown', function (e) { pong.addKey(e.key); });
+ window.addEventListener('keyup', function (e) { pong.deleteKey(e.key); });
+ }
+ addKey(key: string) {
+ key = key.toLowerCase();
+ var i = pong.keys.indexOf(key);
+ if (i == -1)
+ pong.keys.push(key);
+ }
+ deleteKey(key: string) {
+ key = key.toLowerCase();
+ var i = pong.keys.indexOf(key);
+ if (i != -1)
+ pong.keys.splice(i, 1);
+ }
+ clear() {
+ this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
+ }
+ stop() {
+ clearInterval(this.interval);
+ }
+}
+
+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)
+ {
+ ball.moveAndBounce([wall_top, wall_bottom, player1, player2]);
+ if (ball.pos.x > pong.canvas.width) {
+ ballInPlay = false;
+ score1.clear();
+ ++score1.value;
+ setTimeout(newRound, 1500);
+ }
+ else if (ball.pos.x < 0 - ball.width) {
+ ballInPlay = false;
+ score2.clear();
+ ++score2.value;
+ setTimeout(newRound, 1500);
+ }
+ }
+
+ draw();
+}
+
+function newRound()
+{
+ // https://fr.wikipedia.org/wiki/Tennis_de_table#Nombre_de_manches
+ if (score1.value >= 11
+ || score2.value >= 11)
+ {
+ if (Math.abs(score1.value - score2.value) >= 2)
+ {
+ if (score1.value > score2.value) {
+ alert("Player 1 WIN");
+ }
+ else {
+ alert("Player 2 WIN");
+ }
+ return;
+ }
+ }
+ ball.pos.x = pong.canvas.width/2;
+ ball.pos.y = (pong.canvas.height * 0.1) + Math.floor(random() * (pong.canvas.height * 0.8));
+ ball.speed = ball.baseSpeed;
+ ballInPlay = true;
+}
+
+function random(min: number = 0, max: number = 1) {
+ return Math.random() * (max - min) + min;
+}
+
+function draw()
+{
+ if (gridDisplay) {
+ drawGrid();
+ }
+ midLine.update();
+ score1.update();
+ score2.update();
+}
+
+function drawStatic()
+{
+ wall_top.update();
+ wall_bottom.update();
+ midLine.update();
+}
+
+function drawInit()
+{
+ pong.clear();
+ drawStatic();
+ player1.update();
+ player2.update();
+}
+
+function drawGrid()
+{
+ w_grid_mid.update();
+ w_grid_u1.update();
+ w_grid_d1.update();
+
+ h_grid_mid.update();
+ h_grid_u1.update();
+ h_grid_d1.update();
+}
+
+function handleInput()
+{
+ var keys = pong.keys;
+ if (keys.length == 0)
+ return;
+
+ if (keys.indexOf("g") != -1)
+ {
+ if (gridDisplay)
+ {
+ pong.clear();
+ drawStatic();
+ }
+ gridDisplay = !gridDisplay;
+ pong.deleteKey("g");
+ }
+ playerMove(keys);
+}
+
+function playerMove(keys: string[])
+{
+ player1.dir.y = 0;
+ if (keys.indexOf("w") != -1) {
+ player1.dir.y += -1;
+ }
+ if (keys.indexOf("s") != -1) {
+ player1.dir.y += 1;
+ }
+ player1.moveAndCollide([wall_top, wall_bottom]);
+
+ player2.dir.y = 0;
+ if (keys.indexOf("ArrowUp".toLowerCase()) != -1) {
+ player2.dir.y += -1;
+ }
+ if (keys.indexOf("ArrowDown".toLowerCase()) != -1) {
+ player2.dir.y += 1;
+ }
+ player2.moveAndCollide([wall_top, wall_bottom]);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+startGame();
diff --git a/src/pong.ts b/src/pong.ts
deleted file mode 100644
index c7d74175..00000000
--- a/src/pong.ts
+++ /dev/null
@@ -1,542 +0,0 @@
-
-/* Keys
- Player 1: W/S
- Player 2: Up/Down
- Grid On-Off: G
-*/
-
-// import {component, score, line} from "./class.js";
-// @ts-check
-
-let gridDisplay = false;
-let ballInPlay = true;
-
-let pong: gameArea;
-
-let wall_top: Rectangle;
-let wall_bottom: Rectangle;
-let player1: Player;
-let player2: Player;
-let ball: Ball;
-let score1: TextNumericValue;
-let score2: TextNumericValue;
-let midLine: Line;
-
-let w_grid_mid: Rectangle;
-let w_grid_u1: Rectangle;
-let w_grid_d1: Rectangle;
-let h_grid_mid: Rectangle;
-let h_grid_u1: Rectangle;
-let h_grid_d1: Rectangle;
-
-function startGame()
-{
- pong = new gameArea();
-
- // Const
- const w = pong.canvas.width;
- const h = pong.canvas.height;
- const w_mid = Math.floor(w/2);
- const h_mid = Math.floor(h/2);
- const pw = Math.floor(w/50);
- const ph = pw*5;
- const ballSize = pw;
- const scoreSize = Math.floor(w/16);
- const midLineSize = Math.floor(w/150);
- const wallSize = Math.floor(w/100);
- const gridSize = Math.floor(w/500);
- const playerSpeed = Math.floor(w/75);
- const ballSpeed = Math.floor(w/75);
-
- let pos = new VectorInteger;
- // Component
- pos.assign(0, 0);
- wall_top = new Rectangle(pos, "grey", w, wallSize);
- pos.assign(0, h-wallSize);
- wall_bottom = new Rectangle(pos, "grey", w, wallSize);
-
- pos.assign(0+pw, h_mid-ph/2);
- player1 = new Player(pos, "white", pw, ph, playerSpeed);
- pos.assign(w-pw-pw, h_mid-ph/2);
- player2 = new Player(pos, "white", pw, ph, playerSpeed);
-
- pos.assign(w_mid-ballSize/2, h_mid-ballSize/2);
- ball = new Ball(pos, "white", ballSize, ballSpeed);
- ball.dir.assign(-0.8, +0.2);
-
- pos.assign(w_mid-scoreSize*1.6, scoreSize*1.5);
- score1 = new TextNumericValue(pos, "white", scoreSize);
- pos.assign(w_mid+scoreSize*1.1, scoreSize*1.5);
- score2 = new TextNumericValue(pos, "white", scoreSize);
- score1.value = 0;
- score2.value = 0;
-
- pos.assign(w_mid-midLineSize/2, 0+wallSize);
- midLine = new Line(pos, "white", midLineSize, h-wallSize*2, 15);
-
- // Grid
- pos.assign(0, h_mid);
- w_grid_mid = new Rectangle(pos, "darkgreen", w, gridSize);
- pos.assign(0, h/4);
- w_grid_u1 = new Rectangle(pos, "darkgreen", w, gridSize);
- pos.assign(0, h-h/4);
- w_grid_d1 = new Rectangle(pos, "darkgreen", w, gridSize);
- pos.assign(w_mid, 0);
- h_grid_mid = new Rectangle(pos, "darkgreen", gridSize, h);
- pos.assign(w/4, 0);
- h_grid_u1 = new Rectangle(pos, "darkgreen", gridSize, h);
- pos.assign(w-w/4, 0);
- h_grid_d1 = new Rectangle(pos, "darkgreen", gridSize, h);
-
- // Start
- score1.update(); // first Text draw init the custom font (graphic leftover ortherwise) (a better solution ?)
- drawInit();
- pong.start();
-}
-
-class gameArea {
- keys: string[];
- interval: number = 0;
- canvas: HTMLCanvasElement;
- ctx: CanvasRenderingContext2D;
- constructor() {
- this.keys = [];
- // this.canvas = {};
- this.canvas = document.createElement("canvas");
- // this.ctx = {};
- 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]);
- }
- start() {
- this.interval = setInterval(gameLoop, 20);
- window.addEventListener('keydown', function (e) { pong.addKey(e.key); });
- window.addEventListener('keyup', function (e) { pong.deleteKey(e.key); });
- }
- addKey(key: string) {
- key = key.toLowerCase();
- var i = pong.keys.indexOf(key);
- if (i == -1)
- pong.keys.push(key);
- }
- deleteKey(key: string) {
- key = key.toLowerCase();
- var i = pong.keys.indexOf(key);
- if (i != -1)
- pong.keys.splice(i, 1);
- }
- clear() {
- this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
- }
- stop() {
- clearInterval(this.interval);
- }
-}
-
-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)
- {
- ball.moveAndBounce([wall_top, wall_bottom, player1, player2]);
- if (ball.pos.x > pong.canvas.width) {
- ballInPlay = false;
- score1.clear();
- ++score1.value;
- setTimeout(newRound, 1500);
- }
- else if (ball.pos.x < 0 - ball.width) {
- ballInPlay = false;
- score2.clear();
- ++score2.value;
- setTimeout(newRound, 1500);
- }
- }
-
- draw();
-}
-
-function newRound()
-{
- // https://fr.wikipedia.org/wiki/Tennis_de_table#Nombre_de_manches
- if (score1.value >= 11
- || score2.value >= 11)
- {
- if (Math.abs(score1.value - score2.value) >= 2)
- {
- if (score1.value > score2.value) {
- alert("Player 1 WIN");
- }
- else {
- alert("Player 2 WIN");
- }
- return;
- }
- }
- ball.pos.x = pong.canvas.width/2;
- ball.pos.y = pong.canvas.height/4 + Math.floor(random() * pong.canvas.height/2);
- ball.speed = ball.baseSpeed;
- ballInPlay = true;
-}
-
-function random(min: number = 0, max: number = 1) {
- return Math.random() * (max - min) + min;
-}
-
-function draw()
-{
- if (gridDisplay) {
- drawGrid();
- }
- midLine.update();
- score1.update();
- score2.update();
-}
-
-function drawStatic()
-{
- wall_top.update();
- wall_bottom.update();
- midLine.update();
-}
-
-function drawInit()
-{
- pong.clear();
- drawStatic();
- player1.update();
- player2.update();
-}
-
-function drawGrid()
-{
- w_grid_mid.update();
- w_grid_u1.update();
- w_grid_d1.update();
-
- h_grid_mid.update();
- h_grid_u1.update();
- h_grid_d1.update();
-}
-
-function handleInput()
-{
- var keys = pong.keys;
- if (keys.length == 0)
- return;
-
- if (keys.indexOf("g") != -1)
- {
- if (gridDisplay)
- {
- pong.clear();
- drawStatic();
- }
- gridDisplay = !gridDisplay;
- pong.deleteKey("g");
- }
- playerMove(keys);
-}
-
-function playerMove(keys: string[])
-{
- player1.dir.y = 0;
- if (keys.indexOf("w") != -1) {
- player1.dir.y += -1;
- }
- if (keys.indexOf("s") != -1) {
- player1.dir.y += 1;
- }
- player1.moveAndCollide([wall_top, wall_bottom]);
-
- player2.dir.y = 0;
- if (keys.indexOf("ArrowUp".toLowerCase()) != -1) {
- player2.dir.y += -1;
- }
- if (keys.indexOf("ArrowDown".toLowerCase()) != -1) {
- player2.dir.y += 1;
- }
- player2.moveAndCollide([wall_top, wall_bottom]);
-}
-
-
-/////////////////////////////////////////////////////////////////////////////
-/////////////////////////////////////////////////////////////////////////////
-// class.js
-
-// 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;
-}
-
-
-class Rectangle implements Component {
- pos: VectorInteger;
- color: string;
- width: number;
- height: number;
- constructor(pos: VectorInteger, color: string, width: number, height: number) {
- this.pos = Object.assign({}, pos);
- this.color = color;
- this.width = width;
- this.height = height;
- }
- update() {
- let ctx = pong.ctx;
- ctx.fillStyle = this.color;
- ctx.fillRect(this.pos.x, this.pos.y, this.width, this.height);
- }
- clear(pos?: VectorInteger) {
- let ctx = pong.ctx;
- if (pos)
- ctx.clearRect(pos.x, pos.y, this.width, this.height);
- else
- ctx.clearRect(this.pos.x, this.pos.y, this.width, this.height);
- }
- collision(collider: Rectangle): boolean { // Collision WIP. To redo
- var myleft = this.pos.x;
- var myright = this.pos.x + (this.width);
- var mytop = this.pos.y;
- var mybottom = this.pos.y + (this.height);
- var otherleft = collider.pos.x;
- var otherright = collider.pos.x + (collider.width);
- var othertop = collider.pos.y;
- var otherbottom = collider.pos.y + (collider.height);
- if ((mybottom < othertop)
- || (mytop > otherbottom)
- || (myright < otherleft)
- || (myleft > otherright)) {
- return false;
- }
- else
- return true;
- }
-}
-
-
-interface Moving {
- dir: Vector;
- speed: number;
- move(): void;
-}
-
-
-class MovingRectangle extends Rectangle implements Moving {
- dir: Vector = new Vector(0,0);
- speed: number;
- readonly baseSpeed: number;
- constructor(pos: VectorInteger, color: string, width: number, height: number, baseSpeed: number) {
- super(pos, color, width, height);
- this.baseSpeed = baseSpeed;
- this.speed = baseSpeed;
- }
- move() { // Math.floor WIP until VectorInteger debug
- this.pos.x += Math.floor(this.dir.x * this.speed);
- this.pos.y += Math.floor(this.dir.y * this.speed);
- }
- moveAndCollide(colliderArr: Rectangle[]) {
- let oldPos = Object.assign({}, this.pos);
- this.move();
- if (colliderArr.some(this.collision, this))
- {
- this.pos.x = oldPos.x;
- this.pos.y = oldPos.y;
- }
- else
- {
- this.clear(oldPos);
- this.update();
- }
- }
-}
-
-
-class Player extends MovingRectangle {
- constructor(pos: VectorInteger, color: string, width: number, height: number, baseSpeed: number) {
- super(pos, color, width, height, baseSpeed);
- }
-}
-
-
-class Ball extends MovingRectangle {
- constructor(pos: VectorInteger, color: string, size: number, baseSpeed: number) {
- super(pos, color, size, size, baseSpeed);
- }
- bounce(collider?: Rectangle) {
- /* Could be more generic, but testing only player is enough,
- because in Pong collider can only be Player or Wall. */
- if (collider instanceof Player) {
- this._bouncePlayer(collider);
- }
- else {
- this._bounceWall();
- }
- }
- moveAndBounce(colliderArr: Rectangle[]) {
- let oldPos = Object.assign({}, this.pos);
- this.move();
- let i = colliderArr.findIndex(this.collision, this);
- if (i != -1)
- {
- this.bounce(colliderArr[i]);
- this.move();
- }
- this.clear(oldPos);
- this.update();
- }
- private _bounceWall() { // Should be enough for Wall
- ball.dir.y = ball.dir.y * -1;
- }
- private _bouncePlayer(collider: Player) { // WIP
- // Bounce for Player need to be more complexe than this
- this.speed += this.baseSpeed/20;
- ball.dir.x = ball.dir.x * -1;
- }
-}
-
-// conflict with Text
-class TextElem implements Component {
- pos: VectorInteger;
- color: string;
- size: number;
- font: string;
- text: string = "";
- constructor(pos: VectorInteger, color: string, size: number, font: string = "Bit5x3") {
- this.pos = Object.assign({}, pos);
- this.color = color;
- this.size = size;
- this.font = font;
- }
- update() {
- let ctx = pong.ctx;
- ctx.font = this.size + "px" + " " + this.font;
- ctx.fillStyle = this.color;
- 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 ctx = pong.ctx;
- let textMetric = 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);
- 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(pos: VectorInteger, color: string, size: number, font?: string) {
- super(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;
- segmentWidth: number;
- segmentHeight: number;
- constructor(pos: VectorInteger, color: string, width: number, height: number, gapeCount?: number) {
- super(pos, color, width, height);
- if (gapeCount)
- this.gapeCount = gapeCount;
- this.segmentCount = this.gapeCount * 2 + 1;
-
- this.segmentWidth = this.width;
- this.segmentHeight = this.height / this.segmentCount;
-
- // for Horizontal Line
- // this.segmentWidth = this.width / this.segmentCount;
- // this.segmentHeight = this.height;
- }
- update() {
- let ctx = pong.ctx;
- ctx.fillStyle = this.color;
- let pos: VectorInteger = new VectorInteger;
- let i = 0;
- while (i < this.segmentCount)
- {
- // for Horizontal Line
- // pos.y = this.pos.y;
- // pos.x = this.pos.x + this.segmentWidth * i;
- pos.x = this.pos.x;
- pos.y = this.pos.y + this.segmentHeight * i;
- ctx.fillRect(pos.x, pos.y, this.segmentWidth, this.segmentHeight);
- i += 2;
- }
- }
-}
diff --git a/src/server/server.ts b/src/server/server.ts
new file mode 100644
index 00000000..6a8523fd
--- /dev/null
+++ b/src/server/server.ts
@@ -0,0 +1,40 @@
+// @ts-check
+
+// var http = require("http");
+// var url = require("url");
+// var fs = require("fs");
+// var path = require("path");
+import http from "http";
+import url from "url";
+import fs from "fs";
+import path from "path";
+
+
+const hostname = "localhost";
+const port = 8080;
+const root = "/mnt/c/Users/Lucky/Desktop/code/ft_transcendence/www/";
+
+const server = http.createServer((req, res) => {
+ // var q = new URL(req.url, `http://${req.getHeaders().host}`)
+ // @ts-ignore
+ var q = url.parse(req.url, true);
+ var filename = root + q.pathname;
+ fs.readFile(filename, (err, data) => {
+ if (err) {
+ res.writeHead(404, {"Content-Type": "text/html"});
+ return res.end("404 Not Found");
+ }
+ if (path.extname(filename) === ".html") {
+ res.writeHead(200, {"Content-Type": "text/html"});
+ }
+ if (path.extname(filename) === ".js") {
+ res.writeHead(200, {"Content-Type": "application/javascript"});
+ }
+ res.write(data);
+ return res.end();
+ });
+});
+
+server.listen(port, hostname, () => {
+ console.log(`Server running at http://${hostname}:${port}/`);
+});
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index fddada1e..338cf3cc 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,7 +1,9 @@
{
- "include": ["./src"],
+ "include": ["src"],
+// "exclude": ["node_modules"],
"compilerOptions": {
- "outDir": "./build",
+ // "outDir": "./build",
+ // "types": ["node"], /* Specify type package names to be included without being referenced in a source file. */
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
@@ -27,14 +29,14 @@
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
- "module": "commonjs", /* Specify what module code is generated. */
+ // "module": "commonjs", /* Specify what module code is generated. */
+ "module": "ES6", /* Specify what module code is generated. */
// "rootDir": "./", /* Specify the root folder within your source files. */
- // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
+ "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
- // "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "resolveJsonModule": true, /* Enable importing .json files. */
diff --git a/src/Bit5x3.woff b/www/Bit5x3.woff
similarity index 100%
rename from src/Bit5x3.woff
rename to www/Bit5x3.woff
diff --git a/src/Bit5x3.woff2 b/www/Bit5x3.woff2
similarity index 100%
rename from src/Bit5x3.woff2
rename to www/Bit5x3.woff2