basic node server
+ very interesting back and forth in TS/JS configs 🤡
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -15,9 +15,9 @@ Thumbs.db
|
|||||||
*.log
|
*.log
|
||||||
|
|
||||||
.env
|
.env
|
||||||
jsconfig.json
|
|
||||||
node_modules
|
node_modules
|
||||||
build
|
*.js
|
||||||
|
www/**/*.html
|
||||||
|
|
||||||
large
|
large
|
||||||
old
|
old
|
||||||
|
|||||||
13
jsconfig.json
Normal file
13
jsconfig.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleResolution": "Node",
|
||||||
|
"target": "ES2020",
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"strictFunctionTypes": true
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"**/node_modules/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
4
make.sh
Normal file
4
make.sh
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
npx tsc
|
||||||
|
mkdir -p www
|
||||||
|
cp ./src/client/*.js ./src/client/*.html ./www/
|
||||||
13
package-lock.json
generated
13
package-lock.json
generated
@@ -5,9 +5,16 @@
|
|||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/node": "^18.11.5",
|
||||||
"typescript": "^4.8.4"
|
"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": {
|
"node_modules/typescript": {
|
||||||
"version": "4.8.4",
|
"version": "4.8.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
|
||||||
@@ -23,6 +30,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"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": {
|
"typescript": {
|
||||||
"version": "4.8.4",
|
"version": "4.8.4",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/node": "^18.11.5",
|
||||||
"typescript": "^4.8.4"
|
"typescript": "^4.8.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
267
src/client/class.ts
Normal file
267
src/client/class.ts
Normal 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}
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
}
|
}
|
||||||
#canvas-container {
|
#canvas-container {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
border: dashed red 5px;
|
/* border: dashed red 5px; */
|
||||||
/* max-height: 80vh; */
|
/* max-height: 80vh; */
|
||||||
/* overflow: hidden; */
|
/* overflow: hidden; */
|
||||||
}
|
}
|
||||||
@@ -29,13 +29,12 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body onload="startGame()">
|
|
||||||
|
|
||||||
|
<body>
|
||||||
<div id="canvas-container">
|
<div id="canvas-container">
|
||||||
<!-- <p> =) </p> -->
|
<!-- <p> =) </p> -->
|
||||||
</div>
|
</div>
|
||||||
|
<script src="http://localhost:8080/pong.js" type="module" defer></script>
|
||||||
<!-- <script type="module" src="pong.js"></script> -->
|
|
||||||
<script src="../build/pong.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
277
src/client/pong.ts
Normal file
277
src/client/pong.ts
Normal 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();
|
||||||
542
src/pong.ts
542
src/pong.ts
@@ -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
40
src/server/server.ts
Normal 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}/`);
|
||||||
|
});
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
{
|
{
|
||||||
"include": ["./src"],
|
"include": ["src"],
|
||||||
|
// "exclude": ["node_modules"],
|
||||||
"compilerOptions": {
|
"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 */
|
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||||
|
|
||||||
/* Projects */
|
/* Projects */
|
||||||
@@ -27,14 +29,14 @@
|
|||||||
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||||
|
|
||||||
/* Modules */
|
/* 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. */
|
// "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. */
|
// "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. */
|
// "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. */
|
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||||
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
|
// "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. */
|
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||||
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
|
||||||
// "resolveJsonModule": true, /* Enable importing .json files. */
|
// "resolveJsonModule": true, /* Enable importing .json files. */
|
||||||
|
|||||||
Reference in New Issue
Block a user