basic node server

+ very interesting back and forth in TS/JS configs 🤡
This commit is contained in:
LuckyLaszlo
2022-10-26 19:27:06 +02:00
parent e56c8e0b67
commit a831b7954c
13 changed files with 629 additions and 554 deletions

Binary file not shown.

Binary file not shown.

267
src/client/class.ts Normal file
View File

@@ -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}

View File

@@ -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 @@
}
</style>
</head>
<body onload="startGame()">
<body>
<div id="canvas-container">
<!-- <p> =) </p> -->
</div>
<!-- <script type="module" src="pong.js"></script> -->
<script src="../build/pong.js"></script>
<script src="http://localhost:8080/pong.js" type="module" defer></script>
</body>
</html>

277
src/client/pong.ts Normal file
View File

@@ -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();

View File

@@ -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;
}
}
}

40
src/server/server.ts Normal file
View File

@@ -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}/`);
});