From 20317db5a372be5620d1e0b2731fdde857ab0708 Mon Sep 17 00:00:00 2001 From: Dmytro Pastukh Date: Mon, 21 Sep 2020 17:15:35 +0200 Subject: [PATCH] Move all to Game class --- src/index.html => index.html | 0 index.ts | 1 + src/Game.ts | 188 ++++++++++++++++++++++++++++ src/{game => }/components/Ball.ts | 0 src/{game => }/components/Brick.ts | 6 +- src/components/BrickGrid.ts | 75 +++++++++++ src/{game => }/components/Paddle.ts | 0 src/game/Game.ts | 177 -------------------------- src/index.ts | 1 - src/style.css | 3 - webpack.config.ts | 4 +- 11 files changed, 271 insertions(+), 184 deletions(-) rename src/index.html => index.html (100%) create mode 100644 index.ts create mode 100644 src/Game.ts rename src/{game => }/components/Ball.ts (100%) rename src/{game => }/components/Brick.ts (95%) create mode 100644 src/components/BrickGrid.ts rename src/{game => }/components/Paddle.ts (100%) delete mode 100644 src/game/Game.ts delete mode 100644 src/index.ts delete mode 100644 src/style.css diff --git a/src/index.html b/index.html similarity index 100% rename from src/index.html rename to index.html diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..20008d0 --- /dev/null +++ b/index.ts @@ -0,0 +1 @@ +import './src/Game'; \ No newline at end of file diff --git a/src/Game.ts b/src/Game.ts new file mode 100644 index 0000000..d83de01 --- /dev/null +++ b/src/Game.ts @@ -0,0 +1,188 @@ +import { BrickGrid } from './components/BrickGrid'; +import { Ball } from './components/Ball'; +import { Paddle } from './components/Paddle'; + + + +class Game { + canvas: HTMLCanvasElement; + ctx: CanvasRenderingContext2D; + ball: Ball; + paddle: Paddle; + brickGrid: BrickGrid; + + + dx = 2; + dy = -2; + rightPressed = false; + leftPressed = false; + score = 0; + lives = 3; + brickColumnCount = 5; // TODO get rid of + brickRowCount = 3; // TODO get rid of + + constructor(config: { canvas: HTMLCanvasElement}) { + this.canvas = config.canvas; + this.ctx = this.canvas.getContext("2d"); + this.ball = new Ball({ + ctx: this.ctx, + x: this.canvas.width / 2, + y: this.canvas.height - 30, + color: '#f95', + radius: 10 + }); + this.paddle = new Paddle({ + ctx: this.ctx, + x: (this.canvas.width - 75) / 2, + y: this.canvas.height - 10, + height: 10, + width: 75 + }) + + + this.brickGrid = new BrickGrid({ + ctx: this.ctx, + rows: this.brickRowCount, + cols: this.brickColumnCount, + brickHeight: 20, + brickWidth: 75 + }); + + document.addEventListener("keydown", this.handleKeyDown.bind(this), false); + document.addEventListener("keyup", this.handleKeyUp.bind(this), false); + document.addEventListener("mousemove", this.handleMouseMove.bind(this), false); + + this.listenStart(); + } + + start() { + this.brickGrid.generateBricks(); + this.draw(); + } + + listenStart() { + this.handleStartClick = this.handleStartClick.bind(this); + this.handleStartPress = this.handleStartPress.bind(this); + + this.canvas.addEventListener("click", this.handleStartClick) + document.addEventListener('keyup', this.handleStartPress) + } + stopListenStart() { + this.canvas.removeEventListener('click', this.handleStartClick) + document.removeEventListener('keyup', this.handleStartPress) + } + + handleStartClick() { + this.stopListenStart(); + this.start(); + } + + handleStartPress(e: KeyboardEvent) { + if (e.key === ' ' || e.code === 'Space') { + this.stopListenStart(); + this.start(); + } + } + + + handleMouseMove(e) { + var relativeX = e.clientX - this.canvas.offsetLeft; + if (relativeX > 0 && relativeX < this.canvas.width) { + this.paddle.x = relativeX - this.paddle.width / 2; + } + } + + handleKeyDown(e) { + if (e.key == "Right" || e.key == "ArrowRight") { + this.rightPressed = true; + } else if (e.key == "Left" || e.key == "ArrowLeft") { + this.leftPressed = true; + } + } + + handleKeyUp(e) { + if (e.key == "Right" || e.key == "ArrowRight") { + this.rightPressed = false; + } else if (e.key == "Left" || e.key == "ArrowLeft") { + this.leftPressed = false; + } + } + + + collisionDetection() { + if (this.brickGrid.checkCollision(this.ball)) { + this.dy = -this.dy; + this.score++; + } +} + + checkScore() { + if (this.score == this.brickRowCount * this.brickColumnCount) { + console.log("YOU WIN, CONGRATULATIONS!"); + document.location.reload(); + // clearInterval(interval); + } +} + drawScore() { + this.ctx.font = "16px Arial"; + this.ctx.fillStyle = "#0095dd"; + this.ctx.fillText("Score: " + this.score, 8, 20); +} + drawLives() { + this.ctx.font = "16px Arial"; + this.ctx.fillStyle = "#0095DD"; + this.ctx.fillText("Lives: " + this.lives, this.canvas.width - 65, 20); +} + + draw() { + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); + this.brickGrid.draw(); + this.ball.draw(); + this.paddle.draw(); + this.collisionDetection(); + this.checkScore(); + this.drawScore(); + this.drawLives(); + + if (this.ball.x + this.dx > this.canvas.width - this.ball.radius || this.ball.x + this.dx < this.ball.radius) { + this.dx = -this.dx; + } + if (this.ball.y + this.dy < this.ball.radius) { + this.dy = -this.dy; + } else if (this.ball.y + this.dy > this.canvas.height - this.ball.radius) { + if (this.ball.x > this.paddle.x && this.ball.x < this.paddle.x + this.paddle.width) { + this.ball.y -= this.paddle.height; + if (this.ball.y) { + this.dy = -this.dy; + } + } else { + this.lives--; + if (!this.lives) { + // alert("GAME OVER"); + document.location.reload(); + // clearInterval(interval); // Needed for Chrome to end game + } else { + this.ball.x = this.canvas.width / 2; + this.ball.y = this.canvas.height - 30; + this.dx = 2; + this.dy = -2; + this.paddle.x = (this.canvas.width - this.paddle.width) / 2; + } + } + } + + if (this.rightPressed && this.paddle.x < this.canvas.width - this.paddle.width) { + this.paddle.x += 7; + } else if (this.leftPressed && this.paddle.x > 0) { + this.paddle.x -= 7; + } + + this.ball.x += this.dx; + this.ball.y += this.dy; + requestAnimationFrame(this.draw.bind(this)); +} +} + +const game = new Game({ + canvas: document.getElementById("myCanvas") as HTMLCanvasElement +}); \ No newline at end of file diff --git a/src/game/components/Ball.ts b/src/components/Ball.ts similarity index 100% rename from src/game/components/Ball.ts rename to src/components/Ball.ts diff --git a/src/game/components/Brick.ts b/src/components/Brick.ts similarity index 95% rename from src/game/components/Brick.ts rename to src/components/Brick.ts index b41d439..a263a65 100644 --- a/src/game/components/Brick.ts +++ b/src/components/Brick.ts @@ -1,4 +1,4 @@ -export class Brick { +export class Brick{ x: BrickConfig['x']; y: BrickConfig['y']; #ctx: BrickConfig['ctx'] @@ -41,6 +41,10 @@ export class Brick { this.#ctx.closePath(); } } + + destroy() { + this.status = false + } } interface BrickConfig { diff --git a/src/components/BrickGrid.ts b/src/components/BrickGrid.ts new file mode 100644 index 0000000..06d6669 --- /dev/null +++ b/src/components/BrickGrid.ts @@ -0,0 +1,75 @@ +import { Ball } from './Ball'; +import { Brick } from './Brick'; + +export class BrickGrid { + #ctx: BrickGridConfig['ctx'] + cols: BrickGridConfig['cols'] + rows: BrickGridConfig['rows'] + brickWidth: BrickGridConfig['brickWidth'] + brickHeight: BrickGridConfig['brickHeight'] + + bricks: Brick[][] = [] + + + constructor(config: BrickGridConfig) { + this.cols = config.cols; + this.rows = config.rows; + + this.#ctx = config.ctx; + this.brickWidth = config.brickWidth; + this.brickHeight = config.brickHeight; + } + + generateBricks() { + for (var c = 0; c < this.cols; c++) { + this.bricks[c] = []; + for (var r = 0; r < this.rows; r++) { + this.bricks[c][r] = new Brick({ + x: 0, + y: 0, + column: c, + row: r, + ctx: this.#ctx, + width: this.brickWidth, + height: this.brickHeight, + padding: 10, + offsetLeft: 30, + offsetTop: 30 + }); + } + } + } + + draw() { + for (const brick of this.bricks.flat()) { + brick.draw(); + } + } + + + checkCollision(ball: Ball): boolean { + for (const brick of this.bricks.flat()) { + if (brick.status === true) { + if ( + ball.x > brick.x && + ball.x < brick.x + this.brickWidth && + ball.y > brick.y && + ball.y < brick.y + this.brickHeight + ) { + + brick.destroy(); + return true + } + } + } + return false; + } +} + +interface BrickGridConfig { + ctx: CanvasRenderingContext2D, + rows: number, + cols: number, + brickWidth: number, + brickHeight: number, +} \ No newline at end of file diff --git a/src/game/components/Paddle.ts b/src/components/Paddle.ts similarity index 100% rename from src/game/components/Paddle.ts rename to src/components/Paddle.ts diff --git a/src/game/Game.ts b/src/game/Game.ts deleted file mode 100644 index 72d3c76..0000000 --- a/src/game/Game.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { Ball } from './components/Ball'; -import { Brick } from './components/Brick'; -import { Paddle } from './components/Paddle'; - -// class Game { -// constructor() {} -// } - - -const canvas = document.getElementById("myCanvas") as HTMLCanvasElement; -const ctx = canvas.getContext("2d"); - - -const ball = new Ball({ - ctx: ctx, - x: canvas.width / 2, - y: canvas.height - 30, - color: '#ff95DD', - radius: 10 -}) - -const paddle = new Paddle({ - ctx: ctx, - x: (canvas.width - 75) / 2, - y: canvas.height - 10, - height: 10, - width: 75 -}); - - -var dx = 2; -var dy = -2; -var rightPressed = false; -var leftPressed = false; -var brickRowCount = 3; -var brickColumnCount = 5; -var brickWidth = 75; -var brickHeight = 20; -var score = 0; -var lives = 3; - -var bricks = []; -for (var c = 0; c < brickColumnCount; c++) { - bricks[c] = []; - for (var r = 0; r < brickRowCount; r++) { - bricks[c][r] = new Brick({ - x: 0, - y: 0, - column: c, - row: r, - ctx: ctx, - width: 75, - height: 30, - padding: 10, - offsetLeft: 30, - offsetTop: 30 - }); - } -} - -document.addEventListener("keydown", keyDownHandler, false); -document.addEventListener("keyup", keyUpHandler, false); -document.addEventListener("mousemove", mouseMoveHandler, false); - -function mouseMoveHandler(e) { - var relativeX = e.clientX - canvas.offsetLeft; - if (relativeX > 0 && relativeX < canvas.width) { - paddle.x = relativeX - paddle.width / 2; - } -} - -function keyDownHandler(e) { - if (e.key == "Right" || e.key == "ArrowRight") { - rightPressed = true; - } else if (e.key == "Left" || e.key == "ArrowLeft") { - leftPressed = true; - } -} - -function keyUpHandler(e) { - if (e.key == "Right" || e.key == "ArrowRight") { - rightPressed = false; - } else if (e.key == "Left" || e.key == "ArrowLeft") { - leftPressed = false; - } -} - -function collisionDetection() { - for (var c = 0; c < brickColumnCount; c++) { - for (var r = 0; r < brickRowCount; r++) { - var b = bricks[c][r]; - if (b.status == 1) { - if ( - ball.x > b.x && - ball.x < b.x + brickWidth && - ball.y > b.y && - ball.y < b.y + brickHeight - ) { - dy = -dy; - b.status = 0; - score++; - if (score == brickRowCount * brickColumnCount) { - alert("YOU WIN, CONGRATULATIONS!"); - document.location.reload(); - // clearInterval(interval); - } - } - } - } - } -} -function drawScore() { - ctx.font = "16px Arial"; - ctx.fillStyle = "#0095dd"; - ctx.fillText("Score: " + score, 8, 20); -} -function drawLives() { - ctx.font = "16px Arial"; - ctx.fillStyle = "#0095DD"; - ctx.fillText("Lives: " + lives, canvas.width - 65, 20); -} -function drawBricks() { - for (var c = 0; c < brickColumnCount; c++) { - for (var r = 0; r < brickRowCount; r++) { - bricks[c][r].draw(); - } - } -} - -function draw() { - ctx.clearRect(0, 0, canvas.width, canvas.height); - drawBricks(); - ball.draw(); - paddle.draw(); - collisionDetection(); - drawScore(); - drawLives(); - - if (ball.x + dx > canvas.width - ball.radius || ball.x + dx < ball.radius) { - dx = -dx; - } - if (ball.y + dy < ball.radius) { - dy = -dy; - } else if (ball.y + dy > canvas.height - ball.radius) { - if (ball.x > paddle.x && ball.x < paddle.x + paddle.width) { - ball.y -= paddle.height; - if (ball.y) { - dy = -dy; - } - } else { - lives--; - if (!lives) { - // alert("GAME OVER"); - document.location.reload(); - // clearInterval(interval); // Needed for Chrome to end game - } else { - ball.x = canvas.width / 2; - ball.y = canvas.height - 30; - dx = 2; - dy = -2; - paddle.x = (canvas.width - paddle.width) / 2; - } - } - } - - if (rightPressed && paddle.x < canvas.width - paddle.width) { - paddle.x += 7; - } else if (leftPressed && paddle.x > 0) { - paddle.x -= 7; - } - - ball.x += dx; - ball.y += dy; - requestAnimationFrame(draw); -} - -draw(); \ No newline at end of file diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index 3326f59..0000000 --- a/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -import './game/Game'; \ No newline at end of file diff --git a/src/style.css b/src/style.css deleted file mode 100644 index 38317a7..0000000 --- a/src/style.css +++ /dev/null @@ -1,3 +0,0 @@ -h1, h2 { - font-family: Lato; -} \ No newline at end of file diff --git a/webpack.config.ts b/webpack.config.ts index e169f56..c73833a 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -3,11 +3,11 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); module.exports = { - entry: './src/index.ts', + entry: './index.ts', plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ - template: 'src/index.html' + template: './index.html' }), ], module: {