diff --git a/frontend/static/js/views/Game.js b/frontend/static/js/views/Game.js index 4354d0a..2851c04 100644 --- a/frontend/static/js/views/Game.js +++ b/frontend/static/js/views/Game.js @@ -43,18 +43,40 @@ export default class extends AbstractView { class Game { constructor() { + //Global variables + this.globVars = { + CANVASHEIGHT: 270, + CANVASWIDTH: 480, + PADDLEHEIGHT: 70, + PADDLEWIDTH: 10, + PADDLEMARGIN: 5, + PADDLESPEED: 3, + BALLRADIUS: 5, + BALLSPEED: 2, + MAXBOUNCEANGLE: 10 * (Math.PI / 12) + }; + this.canvas = document.createElement('canvas'); this.canvas.id = 'gameCanvas'; - this.canvas.width = 480; - this.canvas.height = 270; + this.canvas.width = this.globVars.CANVASWIDTH; + this.canvas.height = this.globVars.CANVASHEIGHT; this.canvas.style.border = '1px solid #d3d3d3'; this.canvas.style.backgroundColor = '#f1f1f1'; this.context = this.canvas.getContext('2d'); - - this.paddle = new Paddle(this.context); - this.ball = new Ball(this.context); document.getElementById('app').appendChild(this.canvas); + this.paddles = [ + new Paddle(this.context, + this.globVars.PADDLEMARGIN, + this.globVars + ), + new Paddle(this.context, + this.globVars.CANVASWIDTH - this.globVars.PADDLEMARGIN - this.globVars.PADDLEWIDTH, + this.globVars + ) + ]; + this.ball = new Ball(this.context, this.globVars); + this.interval = setInterval(this.updateGame.bind(this), 10); this.keys = []; @@ -79,20 +101,27 @@ class Game { if (this.keys.includes('Escape')) this.cleanup(); + //Paddle movement if (this.keys.includes('s') && - this.paddle.y + this.paddle.height < this.canvas.height - this.paddle.x) - this.paddle.y += this.paddle.speed; + this.paddles[0].y + this.globVars.PADDLEHEIGHT < this.globVars.CANVASHEIGHT - this.globVars.PADDLEMARGIN) + this.paddles[0].y += this.globVars.PADDLESPEED; if (this.keys.includes('w') && - this.paddle.y > 0 + this.paddle.x) - this.paddle.y -= this.paddle.speed; + this.paddles[0].y > 0 + this.globVars.PADDLEMARGIN) + this.paddles[0].y -= this.globVars.PADDLESPEED; + + if (this.keys.includes('ArrowDown') && + this.paddles[1].y + this.globVars.PADDLEHEIGHT < this.globVars.CANVASHEIGHT - this.globVars.PADDLEMARGIN) + this.paddles[1].y += this.globVars.PADDLESPEED; + if (this.keys.includes('ArrowUp') && + this.paddles[1].y > 0 + this.globVars.PADDLEMARGIN) + this.paddles[1].y -= this.globVars.PADDLESPEED; + + //Ball collisions + if (this.detectCollision(this.paddles[0], this.ball)) + this.calculateBallVelocity(this.paddles[0].getCenter().y, this.ball); + else if (this.detectCollision(this.paddles[1], this.ball)) + this.calculateBallVelocity(this.paddles[1].getCenter().y, this.ball, -1); - if (this.ball.x - this.ball.radius <= this.paddle.x + this.paddle.width - && (this.ball.y >= this.paddle.y && this.ball.y <= this.paddle.y + this.paddle.height)) - this.ball.vx *= -1; - if (this.ball.x - this.ball.radius <= 0) - this.ball.vx *= -1; - else if (this.ball.x + this.ball.radius >= this.canvas.width) - this.ball.vx *= -1; if (this.ball.y - this.ball.radius <= 0) this.ball.vy *= -1; else if (this.ball.y + this.ball.radius >= this.canvas.height) @@ -101,10 +130,30 @@ class Game { this.ball.y += this.ball.vy; this.clear(); - this.paddle.update(); + this.paddles[0].update(); + this.paddles[1].update(); this.ball.update(); } + detectCollision(paddle, ball) { + let paddleCenter = paddle.getCenter(); + let dx = Math.abs(ball.x - paddleCenter.x); + let dy = Math.abs(ball.y - paddleCenter.y); + if (dx <= ball.radius + paddle.width / 2 && + dy <= ball.radius + paddle.height / 2) + return true; + return false; + } + + calculateBallVelocity(paddleCenterY, ball, side = 1) { + let relativeIntersectY = paddleCenterY - ball.y; + let normRelIntersectY = relativeIntersectY / this.globVars.PADDLEHEIGHT / 2; + let bounceAngle = normRelIntersectY * this.globVars.MAXBOUNCEANGLE; + + ball.vx = this.globVars.BALLSPEED * side * Math.cos(bounceAngle); + ball.vy = this.globVars.BALLSPEED * -Math.sin(bounceAngle); + } + keyUpHandler(ev) { const idx = this.keys.indexOf(ev.key); if (idx != -1) @@ -118,12 +167,11 @@ class Game { } class Paddle { - constructor(context) { - this.width = 10; - this.height = 70; - this.x = 5; - this.y = 100; - this.speed = 3; + constructor(context, paddleSide, globVars) { + this.width = globVars.PADDLEWIDTH; + this.height = globVars.PADDLEHEIGHT; + this.x = paddleSide; + this.y = globVars.CANVASHEIGHT / 2 - this.height / 2; this.ctx = context; this.update(); } @@ -132,15 +180,22 @@ class Paddle { this.ctx.fillStyle = 'black'; this.ctx.fillRect(this.x, this.y, this.width, this.height); } + + getCenter() { + return { + x: this.x + this.width / 2, + y: this.y + this.height / 2 + }; + } } class Ball { - constructor(context) { - this.radius = 5; - this.x = 240; - this.y = 135; - this.vx = 2; - this.vy = 2; + constructor(context, globVars) { + this.radius = globVars.BALLRADIUS; + this.x = globVars.CANVASWIDTH / 2; + this.y = globVars.CANVASHEIGHT / 2; + this.vx = -globVars.BALLSPEED; + this.vy = 0; this.ctx = context; this.update(); }