pong now in TypeScript
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -15,3 +15,9 @@ Thumbs.db
|
|||||||
*.log
|
*.log
|
||||||
|
|
||||||
.env
|
.env
|
||||||
|
jsconfig.json
|
||||||
|
node_modules
|
||||||
|
build
|
||||||
|
|
||||||
|
large
|
||||||
|
old
|
||||||
|
|||||||
33
package-lock.json
generated
Normal file
33
package-lock.json
generated
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"name": "ft_transcendence",
|
||||||
|
"lockfileVersion": 2,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^4.8.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/typescript": {
|
||||||
|
"version": "4.8.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
|
||||||
|
"integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
|
||||||
|
"dev": true,
|
||||||
|
"bin": {
|
||||||
|
"tsc": "bin/tsc",
|
||||||
|
"tsserver": "bin/tsserver"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"typescript": {
|
||||||
|
"version": "4.8.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz",
|
||||||
|
"integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
5
package.json
Normal file
5
package.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^4.8.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
298
pong.html
298
pong.html
@@ -1,298 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
#canvas-container {
|
|
||||||
text-align: center;
|
|
||||||
border: dashed red 5px;
|
|
||||||
/* max-height: 80vh; */
|
|
||||||
/* overflow: hidden; */
|
|
||||||
}
|
|
||||||
canvas {
|
|
||||||
background-color: #333333;
|
|
||||||
max-width: 75vw;
|
|
||||||
/* max-height: 100vh; */
|
|
||||||
/* width: 80%; */
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body onload="startGame()">
|
|
||||||
|
|
||||||
<div id="canvas-container">
|
|
||||||
<!-- <p> =) </p> -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// "use strict";
|
|
||||||
|
|
||||||
var gridDisplay = false;
|
|
||||||
|
|
||||||
function startGame()
|
|
||||||
{
|
|
||||||
gameArea.createGameArea();
|
|
||||||
|
|
||||||
// Const
|
|
||||||
w = gameArea.canvas.width;
|
|
||||||
h = gameArea.canvas.height;
|
|
||||||
w_mid = w/2;
|
|
||||||
h_mid = h/2;
|
|
||||||
const pw = w/50;
|
|
||||||
const ph = pw*5;
|
|
||||||
const ball_size = pw; // const ball_size = w/50;
|
|
||||||
const score_size = w/16;
|
|
||||||
const wall_size = w/100;
|
|
||||||
const playerSpeed = w/75;
|
|
||||||
const ballSpeed = w/150;
|
|
||||||
|
|
||||||
// Component
|
|
||||||
player1 = new component(pw, ph, "white", 0+w/50, h_mid-ph/2);
|
|
||||||
player2 = new component(pw, ph, "white", w-w/50-pw, h_mid-ph/2);
|
|
||||||
ball = new component(ball_size, ball_size, "white", w_mid-ball_size/2, h_mid-ball_size/2);
|
|
||||||
player1.speed = playerSpeed;
|
|
||||||
player2.speed = playerSpeed;
|
|
||||||
ball.speed = ballSpeed;
|
|
||||||
ball.dirX = -0.5;
|
|
||||||
ball.dirY = +0.5;
|
|
||||||
score1 = new score(score_size+"px", "Consolas", "white", w_mid-w/8, w/12);
|
|
||||||
score2 = new score(score_size+"px", "Consolas", "white", w_mid+w/8-score_size/2, w/12);
|
|
||||||
|
|
||||||
wall_top = new component(w, wall_size, "grey", 0, 0);
|
|
||||||
wall_bottom = new component(w, wall_size, "grey", 0, h-wall_size);
|
|
||||||
|
|
||||||
// Grid
|
|
||||||
const grid_size = w/500;
|
|
||||||
w_grid_mid = new component(w, grid_size, "darkgreen", 0, h_mid);
|
|
||||||
w_grid_u1 = new component(w, grid_size, "darkgreen", 0, h/4);
|
|
||||||
w_grid_d1 = new component(w, grid_size, "darkgreen", 0, h-h/4);
|
|
||||||
h_grid_mid = new component(grid_size, h, "darkgreen", w_mid, 0);
|
|
||||||
h_grid_u1 = new component(grid_size, h, "darkgreen", w/4, 0);
|
|
||||||
h_grid_d1 = new component(grid_size, h, "darkgreen", w-w/4, 0);
|
|
||||||
|
|
||||||
// dashed line TODO
|
|
||||||
// midLine = new component(grid_size, h, "white", w_mid, 0);
|
|
||||||
|
|
||||||
gameArea.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
var gameArea = {
|
|
||||||
keys: [],
|
|
||||||
canvas : document.createElement("canvas"),
|
|
||||||
createGameArea : function() {
|
|
||||||
/* ratio 5/3 (1.66) */
|
|
||||||
var ratio = 1.66666;
|
|
||||||
this.canvas.width = 1500;
|
|
||||||
this.canvas.height = this.canvas.width / ratio;
|
|
||||||
this.ctx = this.canvas.getContext("2d");
|
|
||||||
var container = document.getElementById("canvas-container");
|
|
||||||
container.insertBefore(this.canvas, container.childNodes[0]);
|
|
||||||
},
|
|
||||||
start : function() {
|
|
||||||
this.interval = setInterval(gameLoop, 20);
|
|
||||||
window.addEventListener('keydown', function (e)
|
|
||||||
{ gameArea.addKey(e.key); })
|
|
||||||
window.addEventListener('keyup', function (e)
|
|
||||||
{ gameArea.deleteKey(e.key); })
|
|
||||||
},
|
|
||||||
addKey : function(key) {
|
|
||||||
key = key.toLowerCase();
|
|
||||||
var i = gameArea.keys.indexOf(key);
|
|
||||||
if (i == -1)
|
|
||||||
gameArea.keys.push(key);
|
|
||||||
},
|
|
||||||
deleteKey : function(key) {
|
|
||||||
key = key.toLowerCase();
|
|
||||||
var i = gameArea.keys.indexOf(key);
|
|
||||||
if (i != -1)
|
|
||||||
gameArea.keys.splice(i, 1);
|
|
||||||
},
|
|
||||||
clear : function() {
|
|
||||||
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
|
||||||
},
|
|
||||||
stop : function() {
|
|
||||||
clearInterval(this.interval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function score(size, font, color, x, y)
|
|
||||||
{
|
|
||||||
this.size = size;
|
|
||||||
this.font = font;
|
|
||||||
this.color = color;
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.text = "0";
|
|
||||||
this.update = function() {
|
|
||||||
ctx = gameArea.ctx;
|
|
||||||
ctx.font = this.size + " " + this.font;
|
|
||||||
ctx.fillStyle = this.color;
|
|
||||||
ctx.fillText(this.text, this.x, this.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function component(width, height, color, x, y)
|
|
||||||
{
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
this.color = color;
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.dirX = 0;
|
|
||||||
this.dirY = 0;
|
|
||||||
this.speed = 1.0;
|
|
||||||
this.update = function() {
|
|
||||||
ctx = gameArea.ctx;
|
|
||||||
ctx.fillStyle = this.color;
|
|
||||||
ctx.fillRect(this.x, this.y, this.width, this.height);
|
|
||||||
}
|
|
||||||
this.move = function() {
|
|
||||||
this.x += this.dirX * this.speed;
|
|
||||||
this.y += this.dirY * this.speed;
|
|
||||||
}
|
|
||||||
this.collision = function(collider) { // From W3schools. To redo.
|
|
||||||
var myleft = this.x;
|
|
||||||
var myright = this.x + (this.width);
|
|
||||||
var mytop = this.y;
|
|
||||||
var mybottom = this.y + (this.height);
|
|
||||||
var otherleft = collider.x;
|
|
||||||
var otherright = collider.x + (collider.width);
|
|
||||||
var othertop = collider.y;
|
|
||||||
var otherbottom = collider.y + (collider.height);
|
|
||||||
if ((mybottom < othertop) ||
|
|
||||||
(mytop > otherbottom) ||
|
|
||||||
(myright < otherleft) ||
|
|
||||||
(myleft > otherright)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
this.bounce = function() { // WIP
|
|
||||||
ball.dirX = ball.dirX * -1;
|
|
||||||
ball.dirY = ball.dirY * -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bad drawLine, TODO make a drawLine with fillRect()
|
|
||||||
function drawLine(start, end, color, pattern)
|
|
||||||
{
|
|
||||||
ctx = gameArea.ctx;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.setLineDash(pattern);
|
|
||||||
ctx.moveTo(start[0], start[1]);
|
|
||||||
ctx.lineTo(end[0], end[1]);
|
|
||||||
ctx.strokeStyle = color;
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
|
|
||||||
function line(width, height, color, x, y)
|
|
||||||
{
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
this.color = color;
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.dirX = 0;
|
|
||||||
this.dirY = 0;
|
|
||||||
this.speed = 1.0;
|
|
||||||
this.update = function() {
|
|
||||||
ctx = gameArea.ctx;
|
|
||||||
ctx.fillStyle = this.color;
|
|
||||||
ctx.fillRect(this.x, this.y, this.width, this.height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function gameLoop()
|
|
||||||
{
|
|
||||||
handleInput();
|
|
||||||
|
|
||||||
ball.move();
|
|
||||||
if (ball.collision(wall_top))
|
|
||||||
ball.bounce();
|
|
||||||
if (ball.collision(wall_bottom))
|
|
||||||
ball.bounce();
|
|
||||||
if (ball.collision(player1))
|
|
||||||
ball.bounce();
|
|
||||||
if (ball.collision(player2))
|
|
||||||
ball.bounce();
|
|
||||||
|
|
||||||
draw();
|
|
||||||
}
|
|
||||||
|
|
||||||
function draw()
|
|
||||||
{
|
|
||||||
gameArea.clear();
|
|
||||||
|
|
||||||
if (gridDisplay)
|
|
||||||
drawGrid();
|
|
||||||
|
|
||||||
// drawLine([w_mid, 0], [w_mid, h], "white", [10, 10]); // bad
|
|
||||||
|
|
||||||
wall_top.update();
|
|
||||||
wall_bottom.update();
|
|
||||||
player1.update();
|
|
||||||
player2.update();
|
|
||||||
ball.update();
|
|
||||||
score1.update();
|
|
||||||
score2.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 = gameArea.keys;
|
|
||||||
if (keys.length == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (keys.indexOf("g") != -1)
|
|
||||||
{
|
|
||||||
gridDisplay = !gridDisplay;
|
|
||||||
gameArea.deleteKey("g");
|
|
||||||
}
|
|
||||||
playerMove(keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
function playerMove(keys)
|
|
||||||
{
|
|
||||||
player1.dirY = 0;
|
|
||||||
if (keys.indexOf("w") != -1)
|
|
||||||
{ player1.dirY += -1; }
|
|
||||||
if (keys.indexOf("s") != -1)
|
|
||||||
{ player1.dirY += 1; }
|
|
||||||
player1.move();
|
|
||||||
if (player1.collision(wall_top) || player1.collision(wall_bottom))
|
|
||||||
{
|
|
||||||
player1.dirY = player1.dirY * -1;
|
|
||||||
player1.move();
|
|
||||||
}
|
|
||||||
|
|
||||||
player2.dirY = 0;
|
|
||||||
if (keys.indexOf("ArrowUp".toLowerCase()) != -1)
|
|
||||||
{ player2.dirY += -1; }
|
|
||||||
if (keys.indexOf("ArrowDown".toLowerCase()) != -1)
|
|
||||||
{ player2.dirY += 1; }
|
|
||||||
player2.move();
|
|
||||||
if (player2.collision(wall_top) || player2.collision(wall_bottom))
|
|
||||||
{
|
|
||||||
player2.dirY = player2.dirY * -1;
|
|
||||||
player2.move();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
33
src/pong.html
Normal file
33
src/pong.html
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background-color: #222425;
|
||||||
|
}
|
||||||
|
#canvas-container {
|
||||||
|
text-align: center;
|
||||||
|
border: dashed red 5px;
|
||||||
|
/* max-height: 80vh; */
|
||||||
|
/* overflow: hidden; */
|
||||||
|
}
|
||||||
|
canvas {
|
||||||
|
background-color: #333333;
|
||||||
|
max-width: 75vw;
|
||||||
|
/* max-height: 100vh; */
|
||||||
|
/* width: 80%; */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body onload="startGame()">
|
||||||
|
|
||||||
|
<div id="canvas-container">
|
||||||
|
<!-- <p> =) </p> -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <script type="module" src="pong.js"></script> -->
|
||||||
|
<script src="../build/pong.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
359
src/pong.ts
Normal file
359
src/pong.ts
Normal file
@@ -0,0 +1,359 @@
|
|||||||
|
|
||||||
|
// import {component, score, line} from "./class.js";
|
||||||
|
// @ts-check
|
||||||
|
|
||||||
|
let gridDisplay = false;
|
||||||
|
|
||||||
|
let pong: gameArea;
|
||||||
|
|
||||||
|
let wall_top: Rectangle;
|
||||||
|
let wall_bottom: Rectangle;
|
||||||
|
let player1: Player;
|
||||||
|
let player2: Player;
|
||||||
|
let ball: Ball;
|
||||||
|
let score1: TextElem;
|
||||||
|
let score2: TextElem;
|
||||||
|
|
||||||
|
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
|
||||||
|
let w = pong.canvas.width;
|
||||||
|
let h = pong.canvas.height;
|
||||||
|
let w_mid = w/2;
|
||||||
|
let h_mid = h/2;
|
||||||
|
const pw = w/50;
|
||||||
|
const ph = pw*5;
|
||||||
|
const ball_size = pw; // const ball_size = w/50;
|
||||||
|
const score_size = w/16;
|
||||||
|
const wall_size = w/100;
|
||||||
|
const playerSpeed = w/75;
|
||||||
|
const ballSpeed = w/75;
|
||||||
|
|
||||||
|
// Component
|
||||||
|
wall_top = new Rectangle({x: 0, y: 0}, "grey", w, wall_size);
|
||||||
|
wall_bottom = new Rectangle({x: 0, y: h-wall_size}, "grey", w, wall_size);
|
||||||
|
|
||||||
|
player1 = new Player({x: 0+w/50, y: h_mid-ph/2}, "white", pw, ph);
|
||||||
|
player2 = new Player({x: w-w/50-pw, y: h_mid-ph/2}, "white", pw, ph);
|
||||||
|
player1.speed = playerSpeed;
|
||||||
|
player2.speed = playerSpeed;
|
||||||
|
|
||||||
|
ball = new Ball({x: w_mid-ball_size/2, y: h_mid-ball_size/2}, "white", ball_size);
|
||||||
|
ball.speed = ballSpeed;
|
||||||
|
ball.dir.x = -0.8;
|
||||||
|
ball.dir.y = +0.2;
|
||||||
|
|
||||||
|
score1 = new TextElem({x: w_mid-w/8, y: w/12}, "white", score_size+"px");
|
||||||
|
score1.text = "0";
|
||||||
|
score2 = new TextElem({x: w_mid+w/8-score_size/2, y: w/12}, "white", score_size+"px");
|
||||||
|
score2.text = "0";
|
||||||
|
|
||||||
|
// Grid
|
||||||
|
const grid_size = w/500;
|
||||||
|
w_grid_mid = new Rectangle({x: 0, y: h_mid}, "darkgreen", w, grid_size);
|
||||||
|
w_grid_u1 = new Rectangle({x: 0, y: h/4}, "darkgreen", w, grid_size);
|
||||||
|
w_grid_d1 = new Rectangle({x: 0, y: h-h/4}, "darkgreen", w, grid_size);
|
||||||
|
h_grid_mid = new Rectangle({x: w_mid, y: 0}, "darkgreen", grid_size, h);
|
||||||
|
h_grid_u1 = new Rectangle({x: w/4, y: 0}, "darkgreen", grid_size, h);
|
||||||
|
h_grid_d1 = new Rectangle({x: w-w/4, y: 0}, "darkgreen", grid_size, h);
|
||||||
|
|
||||||
|
// dashed line TODO
|
||||||
|
// midLine = new component(grid_size, h, "white", w_mid, 0);
|
||||||
|
|
||||||
|
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() {
|
||||||
|
// @ts-ignore
|
||||||
|
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||||
|
}
|
||||||
|
stop() {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bad drawLine, TODO make a drawLine with fillRect()
|
||||||
|
// function drawLine(start, end, color, pattern)
|
||||||
|
// {
|
||||||
|
// let ctx = pong.ctx;
|
||||||
|
// ctx.beginPath();
|
||||||
|
// ctx.setLineDash(pattern);
|
||||||
|
// ctx.moveTo(start[0], start[1]);
|
||||||
|
// ctx.lineTo(end[0], end[1]);
|
||||||
|
// ctx.strokeStyle = color;
|
||||||
|
// ctx.stroke();
|
||||||
|
// }
|
||||||
|
|
||||||
|
function gameLoop()
|
||||||
|
{
|
||||||
|
handleInput();
|
||||||
|
|
||||||
|
ball.move();
|
||||||
|
if (ball.collision(wall_top) || ball.collision(wall_bottom))
|
||||||
|
ball.bounce();
|
||||||
|
else if (ball.collision(player1))
|
||||||
|
ball.bounce(player1);
|
||||||
|
else if (ball.collision(player2))
|
||||||
|
ball.bounce(player2);
|
||||||
|
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw()
|
||||||
|
{
|
||||||
|
pong.clear();
|
||||||
|
|
||||||
|
if (gridDisplay)
|
||||||
|
drawGrid();
|
||||||
|
|
||||||
|
// drawLine([w_mid, 0], [w_mid, h], "white", [10, 10]); // bad
|
||||||
|
|
||||||
|
wall_top.update();
|
||||||
|
wall_bottom.update();
|
||||||
|
player1.update();
|
||||||
|
player2.update();
|
||||||
|
ball.update();
|
||||||
|
score1.update();
|
||||||
|
score2.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)
|
||||||
|
{
|
||||||
|
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.move();
|
||||||
|
if (player1.collision(wall_top) || player1.collision(wall_bottom))
|
||||||
|
{
|
||||||
|
player1.dir.y = player1.dir.y * -1;
|
||||||
|
player1.move();
|
||||||
|
}
|
||||||
|
|
||||||
|
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.move();
|
||||||
|
if (player2.collision(wall_top) || player2.collision(wall_bottom))
|
||||||
|
{
|
||||||
|
player2.dir.y = player2.dir.y * -1;
|
||||||
|
player2.move();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// class.js
|
||||||
|
|
||||||
|
type Vector = {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface Component {
|
||||||
|
pos: Vector;
|
||||||
|
color: string;
|
||||||
|
// ctx: CanvasRenderingContext2D;
|
||||||
|
update(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Rectangle implements Component {
|
||||||
|
pos: Vector;
|
||||||
|
color: string;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
constructor(pos: Vector, color: string, width: number, height: number) {
|
||||||
|
this.pos = 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);
|
||||||
|
}
|
||||||
|
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 Player extends Rectangle implements Moving {
|
||||||
|
dir: Vector = {x: 0.0, y: 0.0};
|
||||||
|
speed: number = 1;
|
||||||
|
constructor(pos: Vector, color: string, width: number, height: number) {
|
||||||
|
super(pos, color, width, height);
|
||||||
|
}
|
||||||
|
move() {
|
||||||
|
this.pos.x += this.dir.x * this.speed;
|
||||||
|
this.pos.y += this.dir.y * this.speed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Ball extends Rectangle implements Moving {
|
||||||
|
dir: Vector = {x: 0.0, y: 0.0};
|
||||||
|
speed: number = 1;
|
||||||
|
constructor(pos: Vector, color: string, size: number) {
|
||||||
|
super(pos, color, size, size);
|
||||||
|
}
|
||||||
|
move() {
|
||||||
|
this.pos.x += this.dir.x * this.speed;
|
||||||
|
this.pos.y += this.dir.y * this.speed;
|
||||||
|
}
|
||||||
|
bounce(collider?: Rectangle) {
|
||||||
|
if (collider instanceof Player)
|
||||||
|
this._bouncePlayer(collider);
|
||||||
|
else // Could be more generic, but it's OK, because in Pong collider can only be Player or Wall.
|
||||||
|
this._bounceWall();
|
||||||
|
|
||||||
|
}
|
||||||
|
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
|
||||||
|
ball.dir.x = ball.dir.x * -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// conflict with Text
|
||||||
|
class TextElem implements Component {
|
||||||
|
pos: Vector;
|
||||||
|
color: string;
|
||||||
|
size: string;
|
||||||
|
font: string = "Consolas";
|
||||||
|
text: string = "";
|
||||||
|
constructor(pos: Vector, color: string, size: string, font?: string) {
|
||||||
|
this.pos = pos;
|
||||||
|
this.color = color;
|
||||||
|
this.size = size;
|
||||||
|
if (font)
|
||||||
|
this.font = font;
|
||||||
|
}
|
||||||
|
update() {
|
||||||
|
let ctx = pong.ctx;
|
||||||
|
ctx.font = this.size + " " + this.font;
|
||||||
|
ctx.fillStyle = this.color;
|
||||||
|
ctx.fillText(this.text, this.pos.x, this.pos.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// class line {
|
||||||
|
// width: number;
|
||||||
|
// height: number;
|
||||||
|
// color: string;
|
||||||
|
// x: number;
|
||||||
|
// y: number;
|
||||||
|
// constructor(width: number, height: number, color: string, x: number, y: number) {
|
||||||
|
// this.width = width;
|
||||||
|
// this.height = height;
|
||||||
|
// this.color = color;
|
||||||
|
// this.x = x;
|
||||||
|
// this.y = y;
|
||||||
|
// }
|
||||||
|
// update() {
|
||||||
|
// let ctx = pong.ctx;
|
||||||
|
// ctx.fillStyle = this.color;
|
||||||
|
// ctx.fillRect(this.x, this.y, this.width, this.height);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
105
tsconfig.json
Normal file
105
tsconfig.json
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
{
|
||||||
|
"include": ["./src"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./build",
|
||||||
|
/* Visit https://aka.ms/tsconfig to read more about this file */
|
||||||
|
|
||||||
|
/* Projects */
|
||||||
|
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
|
||||||
|
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||||
|
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
|
||||||
|
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
|
||||||
|
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||||
|
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||||
|
|
||||||
|
/* Language and Environment */
|
||||||
|
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
|
||||||
|
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
|
||||||
|
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
||||||
|
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
||||||
|
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||||
|
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
|
||||||
|
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||||
|
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
|
||||||
|
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
|
||||||
|
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||||
|
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||||
|
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
|
||||||
|
|
||||||
|
/* Modules */
|
||||||
|
"module": "commonjs", /* 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. */
|
||||||
|
// "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. */
|
||||||
|
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
|
||||||
|
|
||||||
|
/* JavaScript Support */
|
||||||
|
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
|
||||||
|
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
|
||||||
|
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
|
||||||
|
|
||||||
|
/* Emit */
|
||||||
|
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||||
|
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||||
|
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||||
|
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||||
|
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
|
||||||
|
// "outDir": "./", /* Specify an output folder for all emitted files. */
|
||||||
|
// "removeComments": true, /* Disable emitting comments. */
|
||||||
|
// "noEmit": true, /* Disable emitting files from a compilation. */
|
||||||
|
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||||
|
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
|
||||||
|
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||||
|
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||||
|
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||||
|
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||||
|
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||||
|
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||||
|
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||||
|
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
|
||||||
|
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
|
||||||
|
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||||
|
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
|
||||||
|
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||||
|
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||||
|
|
||||||
|
/* Interop Constraints */
|
||||||
|
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
||||||
|
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
||||||
|
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
|
||||||
|
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||||
|
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
|
||||||
|
|
||||||
|
/* Type Checking */
|
||||||
|
"strict": true, /* Enable all strict type-checking options. */
|
||||||
|
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
|
||||||
|
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
|
||||||
|
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||||
|
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
|
||||||
|
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||||
|
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
|
||||||
|
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
|
||||||
|
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||||
|
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
|
||||||
|
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
|
||||||
|
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||||
|
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||||
|
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||||
|
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
|
||||||
|
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||||
|
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
|
||||||
|
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||||
|
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||||
|
|
||||||
|
/* Completeness */
|
||||||
|
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||||
|
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user