I recently made a JS Pong game. It works well, but the ball rarely gets stuck at the bottom or top. It looks like it is halfway through the wall and constantly bouncing. Video of the issue happening. You can try the game here. I do not know why this issue is happening because the logic seems right and works 90% of the time correctly. Here are the main two functions of my program:
function moveAll() {
if (showingWinScreen) {
return;
}
computerMovement();
ballX += ballSpeedX;
ballY += ballSpeedY;
if (ballY <= 10) {
ballSpeedY = -ballSpeedY;
} else if (ballY >= HEIGHT - 10) {
ballSpeedY = -ballSpeedY;
}
if (ballX >= WIDTH - 10) {
if ((ballY > paddleY) && (ballY < paddleY + 100)) {
ballSpeedX = -ballSpeedX;
var deltaY = ballY - paddleY - 50;
ballSpeedY = deltaY / 5;
} else {
player1Score++;
ballReset();
}
} else if (ballX <= 10) {
if ((ballY > mouseY - 50) && (ballY < mouseY + 50)) {
ballSpeedX = -ballSpeedX;
deltaY = ballY - mouseY;
ballSpeedY = deltaY / 6;
} else {
player2Score++;
ballReset();
}
}
}
function drawAll() {
if (showingWinScreen) {
colorRect(0, 0, WIDTH, HEIGHT, "black");
canvas.fillStyle = "yellow";
canvas.fillText("Click to continue!", 300, 300);
if (player1Score == WINNING_SCORE) {
canvas.fillText("You won!", 360, 500);
} else if (player2Score == WINNING_SCORE) {
canvas.fillText("The computer beat you!", 280, 500);
}
return;
}
colorRect(0, 0, WIDTH, HEIGHT, "black");
drawNet();
makeCircle(ballX, ballY, 10, 0, Math.PI * 2, "red");
colorRect(790, paddleY, 10, 100, "cyan");
colorRect(0, mouseY - 50, 10, 100, "yellow");
canvas.fillStyle = "white";
canvas.fillText(player1Score + " " + player2Score, 360, 100);
}
Thank you for your help!
I think there's only one case in which this could happen: when, in a colliding frame, you decrease the speed.
When the speed remains the same, no matter what, your ball will always bounce back to the previous' frames position:
var cvs = document.querySelector("canvas");
var ctx = cvs.getContext("2d");
var balls = [
Ball(50, 50, 0, 5, 5, "red"),
Ball(100, 50, 0, 5, 10, "blue"),
Ball(150, 50, 0, 5, 15, "green"),
Ball(200, 50, 0, 5, 20, "yellow")
];
var next = () => {
updateFrame(balls);
drawFrame(balls);
}
var loop = () => {
requestAnimationFrame(() => {
next();
loop();
});
}
next();
function Ball(x, y, vx, vy, r, color) {
return {
x: x,
y: y,
vx: vx,
vy: vy,
r: r,
color: color
}
};
function updateBall(b) {
b.x += b.vx;
b.y += b.vy;
if (b.y <= b.r ||
b.y >= cvs.height - b.r) {
b.vy *= -1;
}
};
function drawBall(b) {
ctx.beginPath();
ctx.fillStyle = b.color;
ctx.arc(b.x, b.y, b.r, 0, 2 * Math.PI, false);
ctx.fill();
}
function updateFrame(balls) {
balls.forEach(updateBall);
}
function drawFrame(balls) {
ctx.clearRect(0, 0, cvs.width, cvs.height);
balls.forEach(drawBall);
};
<canvas width="300" height="150" style="background: #454545"></canvas>
<button onclick="next()">next</button>
<button onclick="loop()">run</button>
But when the speed changes, things get stuck:
var cvs = document.querySelector("canvas");
var ctx = cvs.getContext("2d");
var balls = [
Ball(50, 50, 0, 10, 5, "red"),
Ball(100, 50, 0, 10, 10, "blue"),
Ball(150, 50, 0, 10, 15, "green"),
Ball(200, 50, 0, 10, 20, "yellow")
];
var next = () => {
updateFrame(balls);
drawFrame(balls);
}
var loop = () => {
requestAnimationFrame(() => {
next();
loop();
});
}
next();
function Ball(x, y, vx, vy, r, color) {
return {
x: x,
y: y,
vx: vx,
vy: vy,
r: r,
color: color
}
};
function updateBall(b) {
b.x += b.vx;
b.y += b.vy;
if (b.y <= b.r ||
b.y >= cvs.height - b.r) {
b.vy *= -0.5;
}
};
function drawBall(b) {
ctx.beginPath();
ctx.fillStyle = b.color;
ctx.arc(b.x, b.y, b.r, 0, 2 * Math.PI, false);
ctx.fill();
}
function updateFrame(balls) {
balls.forEach(updateBall);
}
function drawFrame(balls) {
ctx.clearRect(0, 0, cvs.width, cvs.height);
balls.forEach(drawBall);
};
<canvas width="300" height="150" style="background: #454545"></canvas>
<button onclick="next()">next</button>
<button onclick="loop()">run</button>
In your case, I'm thinking this can only happen when there's a paddle collision AND a wall collision simultaneously.
A quick-to-implement solution would be to check if the new position is valid before translating the ball position. If you don't want the precise location, you can place the ball at the point of collision. Note that this will produce a slightly off frame.
E.g.:
var newY = ballY + ballSpeedY;
// Top wall
if(newY <= 10) {
ballY = 10;
ballSpeedY = -ballSpeedY;
}
// Bottom wall
else if(newY >= HEIGHT-10){
ballY = HEIGHT - 10;
ballSpeedY = -ballSpeedY;
}
// No collision
else {
ballY = newY;
}
Update: a more detailed description of what can happen
Let's say your ball collides with the top border of your canvas and with your paddle in the same frame.
First, you move the ball to the colliding position: ballY += ballSpeedY; Say your ballY is 4, and your ballSpeedY is -5, you'll position the ball to -1, inside the wall.
If this were to be the only collision, you should be okay. You flip the speed (ballSpeedY = -ballSpeedY), so in the next frame, your ball should be back at -1 + 5 = 4, so ballY will be 4 again, and your ball will move towards 4 + 5 = 9 in the next frame.
Now a problem arises, when in the -1 positioned frame, you collide with the paddle as well! When the paddle hits the ball, you modify the ballspeed: ballSpeedY = deltaY / 5;. If this turns out to be < 1, your ball won't be able to exit the wall in the next frame. Instead of -1 + 5 = 4, your ball will, for example, move to: -1 + 0.5 = -0.5.
Now, your ball won't be able to get back in to play, since the next frame will, again, calculate a collision and flip the speed. This results in the bouncy, trembling effect you see when the ball gets stuck.
A naive but pretty decent solution, is to only update the position of the ball to a valid position. I.e.: never to a colliding coordinate.
var animate = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) {
window.setTimeout(callback, 1000 / 60)
};
var canvas = document.createElement("canvas");
var width = 400;
var height = 600;
canvas.width = width;
canvas.height = height;
var context = canvas.getContext('2d');
var player = new Player();
var computer = new Computer();
var ball = new Ball(200, 300);
var keysDown = {};
var render = function () {
context.fillStyle = "#FF00FF";
context.fillRect(0, 0, width, height);
player.render();
computer.render();
ball.render();
};
var update = function () {
player.update();
computer.update(ball);
ball.update(player.paddle, computer.paddle);
};
var step = function () {
update();
render();
animate(step);
};
function Paddle(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.x_speed = 0;
this.y_speed = 0;
}
Paddle.prototype.render = function () {
context.fillStyle = "#0000FF";
context.fillRect(this.x, this.y, this.width, this.height);
};
Paddle.prototype.move = function (x, y) {
this.x += x;
this.y += y;
this.x_speed = x;
this.y_speed = y;
if (this.x < 0) {
this.x = 0;
this.x_speed = 0;
} else if (this.x + this.width > 400) {
this.x = 400 - this.width;
this.x_speed = 0;
}
};
function Computer() {
this.paddle = new Paddle(175, 10, 50, 10);
}
Computer.prototype.render = function () {
this.paddle.render();
};
Computer.prototype.update = function (ball) {
var x_pos = ball.x;
var diff = -((this.paddle.x + (this.paddle.width / 2)) - x_pos);
if (diff < 0 && diff < -4) {
diff = -5;
} else if (diff > 0 && diff > 4) {
diff = 5;
}
this.paddle.move(diff, 0);
if (this.paddle.x < 0) {
this.paddle.x = 0;
} else if (this.paddle.x + this.paddle.width > 400) {
this.paddle.x = 400 - this.paddle.width;
}
};
function Player() {
this.paddle = new Paddle(175, 580, 50, 10);
}
Player.prototype.render = function () {
this.paddle.render();
};
Player.prototype.update = function () {
for (var key in keysDown) {
var value = Number(key);
if (value == 37) {
this.paddle.move(-4, 0);
} else if (value == 39) {
this.paddle.move(4, 0);
} else {
this.paddle.move(0, 0);
}
}
};
function Ball(x, y) {
this.x = x;
this.y = y;
this.x_speed = 0;
this.y_speed = 3;
}
Ball.prototype.render = function () {
context.beginPath();
context.arc(this.x, this.y, 5, 2 * Math.PI, false);
context.fillStyle = "#000000";
context.fill();
};
Ball.prototype.update = function (paddle1, paddle2) {
this.x += this.x_speed;
this.y += this.y_speed;
var top_x = this.x - 5;
var top_y = this.y - 5;
var bottom_x = this.x + 5;
var bottom_y = this.y + 5;
if (this.x - 5 < 0) {
this.x = 5;
this.x_speed = -this.x_speed;
} else if (this.x + 5 > 400) {
this.x = 395;
this.x_speed = -this.x_speed;
}
if (this.y < 0 || this.y > 600) {
this.x_speed = 0;
this.y_speed = 3;
this.x = 200;
this.y = 300;
}
if (top_y > 300) {
if (top_y < (paddle1.y + paddle1.height) && bottom_y > paddle1.y && top_x < (paddle1.x + paddle1.width) && bottom_x > paddle1.x) {
this.y_speed = -3;
this.x_speed += (paddle1.x_speed / 2);
this.y += this.y_speed;
}
} else {
if (top_y < (paddle2.y + paddle2.height) && bottom_y > paddle2.y && top_x < (paddle2.x + paddle2.width) && bottom_x > paddle2.x) {
this.y_speed = 3;
this.x_speed += (paddle2.x_speed / 2);
this.y += this.y_speed;
}
}
};
document.body.appendChild(canvas);
animate(step);
window.addEventListener("keydown", function (event) {
keysDown[event.keyCode] = true;
});
window.addEventListener("keyup", function (event) {
delete keysDown[event.keyCode];
});
http://jsfiddle.net/kHJr6/2/
Related
Here is the link to my project so far.
I want to make a ball(an ellipse) bounce around all four walls of the canvas and as this happens I would also like to change the colour of the ball and speed after each bounce(randomly of course). P.S I want the ball to continue bouncing around the canvas off all four walls. Thanks for the help!!
This is the code I have tried. It gets the ball across the y-axis from top to bottom and keeps going, but I don't know how to get it to bounce off the left and right sides. I would just like the ball to bounce on all four sides in a clockwise direction(left wall, top, right wall, bottom, etc etc.)
EDITED
// position of the ball
var y = 33;
// how far the ball moves every time
var speed = 2;
draw = function() {
background(127, 204, 255);
fill(66, 66, 66);
ellipse(200, y, 50, 50);
// move the ball
y = y + speed;
if (y > 371)
{
speed = -5;
}
if (y < 31)
{
speed = 5;
}
};
Here is the finished project.
noStroke();
// The Speed Of The Ball When It Starts
var initialSpeedX = 5;
var initialSpeedY = -3;
// The Current Speed Of The Ball
var ballSpeedX = +initialSpeedX;
var ballSpeedY = -initialSpeedY;
// The Current Location Of The Ball
var ballX = 0;
var ballY = 0;
// Check If The Ball Is Moving
var ballMoving = false;
var draw = function() {
background(120, 228, 255);
// Move The Ball
if (ballMoving) {
ballX += ballSpeedX;
ballY += ballSpeedY;
}
else {
ballX = mouseX;
ballY = 465;
}
// Draw The Ball
ellipse(ballX, ballY, 70, 70);
// Check If Ball Has Hit The Top
if (ballY <= 35) {
ballSpeedY = -ballSpeedY;
fill(243, 255, 10);
}
// Check If The Ball Has Hit The Left Wall
if (ballX <= 35) {
ballSpeedX = -ballSpeedX;
fill(235, 135, 12);
}
// Check If The Ball Has Hit The Right Wall
if (ballX >= 465) {
ballSpeedX = -ballSpeedX;
fill(255, 0, 0);
}
// Check If Ball Has Hit The Bottom
if (ballY >= 465) {
ballSpeedY = -ballSpeedY;
fill(0, 255, 9);
}
};
// When The Mouse Is Clicked
var mouseClicked = function() {
if (!ballMoving) {
// Reset The Ball Speed
ballSpeedX = initialSpeedX;
ballSpeedY = initialSpeedY;
ballMoving = true;
}
};
You have some problems with your code. The curly brace that closes the first if was typed in the wrong place. To make the ball bounce, just multiply your speed by -1. Take a look:
// The position of the ball
var x = 25;
// How far the ball moves every time
var speed = 3;
var draw = function() {
background(47, 222, 126);
// The ball
fill(48, 46, 48);
ellipse(x, 200, 50, 50);
// Moves the ball
x = x + speed;
if (x > 375) {
speed = -speed;
} else if (x < 214) {
speed = -speed;
}
};
This is a more complete example:
var canvas = document.getElementById( "myCanvas" );
var context = canvas.getContext( "2d" );
var width = 400;
var height = 200;
var ball = {
x: 100,
y: 100,
radius: 25,
xSpeed: 3,
ySpeed: 3,
draw: function( ctx ) {
ctx.beginPath();
ctx.arc( this.x, this.y, this.radius, 0, 2*Math.PI );
ctx.fill();
},
move: function() {
this.x += this.xSpeed;
this.y += this.ySpeed;
}
}
setInterval( function(){
context.clearRect( 0, 0, width, height );
context.strokeRect( 0, 0, width, height );
ball.move();
// right
if ( ball.x + ball.radius >= width ) {
ball.x = width - ball.radius;
ball.xSpeed = -ball.xSpeed;
}
// left
if ( ball.x - ball.radius <= 0 ) {
ball.x = ball.radius;
ball.xSpeed = -ball.xSpeed;
}
// down
if ( ball.y + ball.radius >= height ) {
ball.y = height - ball.radius;
ball.ySpeed = -ball.ySpeed;
}
// up
if ( ball.y - ball.radius <= 0 ) {
ball.y = ball.radius;
ball.ySpeed = -ball.ySpeed;
}
ball.draw( context );
}, 10 );
<canvas id="myCanvas" width="400" height="200"></canvas>
And this have some physics simulation...
var canvas = document.getElementById( "myCanvas" );
var context = canvas.getContext( "2d" );
var width = 400;
var height = 200;
var gravity = 1;
var ball = {
x: 100,
y: 100,
radius: 25,
xSpeed: 1,
ySpeed: 1,
friction: 0.99,
elasticity: 0.9,
draw: function( ctx ) {
ctx.beginPath();
ctx.arc( this.x, this.y, this.radius, 0, 2*Math.PI );
ctx.fill();
},
move: function() {
this.x += this.xSpeed;
this.y += this.ySpeed;
}
}
setInterval( function(){
context.clearRect( 0, 0, width, height );
context.strokeRect( 0, 0, width, height );
ball.move();
// right
if ( ball.x + ball.radius >= width ) {
ball.x = width - ball.radius;
ball.xSpeed = -ball.xSpeed * ball.elasticity;
}
// left
if ( ball.x - ball.radius <= 0 ) {
ball.x = ball.radius;
ball.xSpeed = -ball.xSpeed * ball.elasticity;
}
// down
if ( ball.y + ball.radius >= height ) {
ball.y = height - ball.radius;
ball.ySpeed = -ball.ySpeed * ball.elasticity;
}
// up
if ( ball.y - ball.radius <= 0 ) {
ball.y = ball.radius;
ball.ySpeed = -ball.ySpeed * ball.elasticity;
}
ball.xSpeed = ball.friction;
ball.ySpeed = ball.ySpeed + ball.friction + gravity;
ball.draw( context );
}, 10 );
<canvas id="myCanvas" width="400" height="200"></canvas>
The ball seems to bounce off one side of the paddle, but when it comes from the side it glitches through the paddle. I just can't find a way behind it and it really bothers me. I am using some logic gates to define where the ball's direction is need to be invereted
function startGame() {
GameArea.start();
Ball1 = new CircleComp('white' , window.innerWidth - 200 , window.innerHeight - 20);
Ball1.ySpeed = 13.5;
Ball1.xSpeed = 6;
Paddle1 = new PaddleComp( 87, 83, 0, window.innerHeight / 2.5, 10, 70);
Paddle2 = new PaddleComp( 38, 40, window.innerWidth - 10, window.innerHeight / 2.5, 10 , 70);
}
var GameArea = {
canvas : canvas = document.querySelector("canvas"),
start : function (){
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
this.ctx = this.canvas.getContext('2d');
this.interval = setInterval(updateGameArea, 20);
window.addEventListener('keydown', function (e) {
GameArea.keys = (GameArea.keys || []);
GameArea.keys[e.keyCode] = true;
})
window.addEventListener('keyup', function (e) {
GameArea.keys[e.keyCode] = false;
})
},
clear : function() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function CircleComp(color, x , y){
this.x = x;
this.y = y;
this.width = 8;
this.height = 8;
var context1 = GameArea.ctx;
this.update = function(){
context1.beginPath();
context1.fillStyle = color;
context1.fillRect(this.x, this.y, this.width, this.height);
context1.fill();
context1.stroke();
this.updatePosition();
}
this.updatePosition = function(){
this.y += this.ySpeed;
this.x += this.xSpeed;
if(this.x + this.width > GameArea.canvas.width){
this.xSpeed = -this.xSpeed;
}
if(this.y + this.height > GameArea.canvas.height){
this.ySpeed = -this.ySpeed;;
}
if(this.x - this.width < 0){
this.xSpeed = -this.xSpeed;
}
if(this.y - this.height < 0){
this.ySpeed = -this.ySpeed;
}
if(this.y + this.height > Paddle2.y && this.y - this.width < (Paddle2.y + 130) && this.x + this.width > Paddle2.x ){
this.xSpeed = -this.xSpeed;
}
if(this.y + this.height > Paddle1.y && this.y - this.width < (Paddle1.y + 70) && this.x - this.height < Paddle1.x + 10){
this.xSpeed = -this.xSpeed;
}
}
}
function PaddleComp(Upkey, Downkey, x, y, width, height){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.ySpeed = 0;
var context2 = GameArea.ctx;
this.update = function(){
context2.fillStyle = 'white';
context2.fillRect(x,this.y,this.width,this.height);
this.updatePosition();
}
this.updatePosition = function() {
this.ySpeed = 0;
if (GameArea.keys && GameArea.keys[Upkey]) {
this.ySpeed = -15; //console.log('Up');
}
if (GameArea.keys && GameArea.keys[Downkey]) {
this.ySpeed = 15; //console.log('Down');
}
if ((GameArea.keys && GameArea.keys[Downkey]) && this.y + 130 > window.innerHeight){
this.ySpeed = this.ySpeed -15 ;
}
if ((GameArea.keys && GameArea.keys[Upkey]) && this.y < 0 ){
this.ySpeed = this.ySpeed +15 ;
}
this.y += this.ySpeed;
}
}
function updateGameArea(){
GameArea.clear();
Paddle1.update();
Paddle2.update();
Ball1.update();
}
<html>
<head>
<meta charset='urf-8'>
<style>
canvas{
border: 0px solid black;
background-color: black;
}
body{
margin: 0;
overflow: hidden;
}
</style>
</head>
<body onload='startGame()'>
<canvas></canvas>
<script src='Pong.js'></script>
</body>
</html>
Could not see directly what the problem was with your code so i just rewrote the code with the ball, bat (paddle) test function in the ball Object and called from the players object. ball.checkPad(player); tests if the ball has hit the players bat. To help picture what is happening I have slowed it all down and made the bats real phat. When the ball hits the bat it will turn yellow and the bat red for a second or so.
There is plenty of comments in the parts you asked about,
Hope it helps
Demo copied from OP question.
const setting = {
speed : 2, // of ball
left : 0,
width : 400,
height : 200,
padWidth : 50,
padHeight : 80,
padSpeed : 4, // double balls
hitPauseCount : 30, // nuber of frames to hold when there is a collisiotn so you
// can check all is good
}
const keys = {
ArrowUp : false,
ArrowDown : false,
ArrowLeft : false,
ArrowRight : false,
keyEvent(e) { // dont use keyCode it has depreciated
if (keys[e.code] !== undefined) {
keys[e.code] = e.type === "keydown";
e.preventDefault();
}
}
}
var ctx;
var ball1, paddle1, paddle2;
var gameArea = {
start() {
canvas.width = setting.width;
canvas.height = setting.height;
ctx = canvas.getContext('2d');
requestAnimationFrame(updateGameArea);
},
clear() {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
}
}
gameArea.start();
ball = new CircleComp('white', window.innerWidth - 200, window.innerHeight - 20);
ball.ySpeed = setting.speed;
ball.xSpeed = setting.speed;
paddle1 = new PaddleComp("ArrowUp", "ArrowDown", setting.left, setting.height / 2, setting.padWidth, setting.padHeight);
paddle2 = new PaddleComp("ArrowLeft", "ArrowRight", setting.width - setting.padWidth, setting.height / 2, setting.padWidth, setting.padHeight);
window.addEventListener('keydown', keys.keyEvent);
window.addEventListener('keyup', keys.keyEvent);
function CircleComp(color, x, y) {
this.x = x;
this.y = y;
this.width = 8;
this.height = 8;
this.xSpeed = setting.speed;
var hit = 0;
var restartCount;
var serveDirection;
this.reset = function(){
this.x = ctx.canvas.width /2;
this.y = ctx.canvas.height / 2;
this.xSpeed = -this.xSpeed
this.ySpeed = setting.speed * Math.sign(Math.random() - 0.5);
restartCount = 60;
}
this.draw = function () {
if(hit > 0){
hit -= 1;
ctx.fillStyle = "yellow";
}else{
ctx.fillStyle = color;
}
ctx.fillRect(this.x, this.y, this.width, this.height);
}
// next funtion is called by the player objects
this.checkPad = function (player) {
if (player.x > canvas.width / 2) { // is player on left or right
if (this.xSpeed > 0) { // player on right only check if ball moving rigth
if (this.x + this.width > player.x) { // ball is in paddles zone
//if not bottom of ball above top of bat or top of ball bellow bottom of bat
if (!(this.y + this.height <= player.y || this.y >= player.y + player.height)) {
// ball and bat in contact
// is ball moving down and the balls top edge above the player
// then ball has hit the top side of the bat
if(this.ySpeed > 0 && this.y <= player.y){
this.y = player.y - this.width;
this.ySpeed = -setting.speed;
}else if(this.ySpeed < 0 && this.y + this.height >= player.y + player.height){ // do bottom check
this.y = player.y + player.height;
this.ySpeed = setting.speed;
}else{ // ball hit front of bat
this.x = player.x - this.width;
this.xSpeed = - setting.speed;
}
player.hit = setting.hitPauseCount; // counters to show FX when a hit happens
hit = setting.hitPauseCount;
}
}
}
} else { // player must be left
if (this.xSpeed < 0) { // ball must move left
if (this.x < player.x + player.width) { // ball is in paddles zone
if (!(this.y + this.height <= player.y || this.y >= player.y + player.height)) {
// ball and bat in contact
// ball and bat in contact
// is ball moving down and the balls top edge above the player
// then ball has hit the top side of the bat
if(this.ySpeed > 0 && this.y <= player.y){
this.y = player.y - this.width;
this.ySpeed = -setting.speed;
}else if(this.ySpeed < 0 && this.y + this.height >= player.y + player.height){ // do bottom check
this.y = player.y + player.height;
this.ySpeed = setting.speed;
}else{ // ball hit front of bat
this.x = player.x + player.width;
this.xSpeed = setting.speed;
}
player.hit = setting.hitPauseCount; // counters to show FX when a hit happens
hit = setting.hitPauseCount;
}
}
}
}
}
this.update = function () {
if(restartCount > 0){ // wait for restart pause
restartCount -= 1;
}else{
if(hit > 0){ // do nothing if paused
return;
}
this.y += this.ySpeed;
this.x += this.xSpeed;
if (this.x + this.width >= canvas.width) {
this.reset(); // point
} else if (this.x < 0) {
this.reset(); // point
}
if (this.y + this.height >= canvas.height) {
this.y = canvas.height - this.height;
this.ySpeed = -setting.speed;
} else if (this.y < 0) {
this.y = 0;
this.ySpeed = setting.speed;
}
}
}
this.reset();
}
function PaddleComp(upKey, downKey, x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.hit = 0;
this.draw = function () {
if(this.hit > 0){
this.hit -= 1;
ctx.fillStyle = "red";
}else{
ctx.fillStyle = '#9CF';
}
ctx.fillRect(this.x, this.y, this.width, this.height);
}
this.update = function () {
if (keys[upKey]) {
this.y -= setting.padSpeed;
};
if (keys[downKey]) {
this.y += setting.padSpeed;
};
if (this.y < 0) {
this.y = 0;
}
if (this.y + this.height >= canvas.height) {
this.y = canvas.height - this.height;
}
ball.checkPad(this);
}
}
function updateGameArea() {
gameArea.clear();
paddle1.update();
paddle2.update();
ball.update();
paddle1.draw();
paddle2.draw();
ball.draw();
requestAnimationFrame(updateGameArea);
}
<canvas id=canvas style='background:#69C;border:2px blue solid'></canvas>
I'm trying to make a brick game with a ball and a player (platform). If the ball hits the player, it should go off in the other direction like ping pong. However, it's not detecting the collision.
Here's the code
html:
<canvas id="canvas" width= "400" height= "400"></canvas>
css:
#canvas{border:1px solid black}
Js:
var width = 400
var height = 400
var drawRect = function (x, y) {
ctx.fillRect(x, y, 30, 5)
};
// The Ball constructor
var Player = function () {
this.x = 395
this.y = 395
this.xSpeed = 5;
this.ySpeed = 0;
};
// Update the ball's position based on its speed
Player.prototype.move = function () {
this.x += this.xSpeed;
this.y += this.ySpeed;
if (this.x < 0) {
this.x = width;
} else if (this.x > width) {
this.x = 0;
} else if (this.y < 0) {
this.y = height;
} else if (this.y > height) {
this.y = 0;
}
};
// Draw the ball at its current position
Player.prototype.draw = function () {
drawRect(this.x, this.y);
};
// Set the ball's direction based on a string
Player.prototype.setDirection = function (direction) {
if (direction === "left") {
this.xSpeed = -5;
this.ySpeed = 0;
} else if (direction === "right") {
this.xSpeed = 5;
this.ySpeed = 0;
} else if (direction === "stop") {
this.xSpeed = 0;
this.ySpeed = 0;
}
};
// Create the ball object
var player = new Player();
// An object to convert keycodes into action names
var keyActions = {
32: "stop",
37: "left",
38: "up",
39: "right",
40: "down"
};
// The keydown handler that will be called for every keypress
$("html").keydown(function (event) {
var direction = keyActions[event.keyCode];
player.setDirection(direction);
});
var Ball = function () {
this.x = 100;
this.y = 100;
this.xSpeed = -2
this.ySpeed = 3;
};
var circle = function (x, y, radius, fillCircle) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false)
if (fillCircle) {
ctx.fill();
} else {
ctx.stroke();
}
}
Ball.prototype.move = function () {
this.x += this.xSpeed
this.y += this.ySpeed
};
Ball.prototype.draw = function () {
circle(this.x, this.y, 3, true);
};
Ball.prototype.checkCollision = function () {
if (this.x < 0 || this.x > 400) {
this.xSpeed = -this.xSpeed
}
if (this.y < 0) {
this.ySpeed = -this.ySpeed
}
};
Ball.prototype.checkCollisionPlayer = function () {
if (this.x === Player.x || this.y === player.y) {
this.ySpeed = -this.ySpeed
this.xSpeed = -this.xSpeed
}
}
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
setInterval(function () {
ctx.clearRect(0, 0, 400, 400);
player.draw();
player.move();
ball.draw();
ball.move();
ball.checkCollision();
ball.checkCollisionPlayer();
}, 40);
var ball = new Ball();
Thanks for your support. :)
I've added a simple box collision and update the classes to have the box dimensions of the ball and player. Remember that the ball box has to adjust for radius offset.
update
The kind of collision detection needed for the boxes you have to know side or corner that was hit. I updated the example as a starting point for this but it's needs to have the corners added and I also don't know the optimal detection. The blocks are setup for testing. I hope this helps.
var width = 400
var height = 400
function Brick(x, y, w, h, color) {
this.x = x;
this.y = y;
this.color = color;
this.w = w;
this.h = h;
this.hits = 0;
}
Brick.prototype.draw = function() {
ctx.save();
ctx.fillStyle = this.color;
ctx.fillRect(this.x, this.y, this.w, this.h);
ctx.fillStyle = "white";
ctx.fillText(this.hits, this.x + 2, this.y + 10);
ctx.restore();
};
var bricks = [
new Brick(80, 120, 15, 15, 'red'),
new Brick(220, 90, 15, 15, 'blue'),
new Brick(340, 100, 50, 20, 'green')
];
// The Ball constructor
var Player = function() {
this.x = 395
this.y = 395
this.xSpeed = 5;
this.ySpeed = 0;
this.w = 30;
this.h = 5;
};
// Update the ball's position based on its speed
Player.prototype.move = function() {
this.x += this.xSpeed;
this.y += this.ySpeed;
if (this.x < 0) {
this.x = width;
} else if (this.x > width) {
this.x = 0;
} else if (this.y < 0) {
this.y = height;
} else if (this.y > height) {
this.y = 0;
}
};
// Draw the ball at its current position
Player.prototype.draw = function() {
ctx.fillRect(this.x, this.y, this.w, this.h);
};
// Set the ball's direction based on a string
Player.prototype.setDirection = function(direction) {
if (direction === "left") {
this.xSpeed = -5;
this.ySpeed = 0;
} else if (direction === "right") {
this.xSpeed = 5;
this.ySpeed = 0;
} else if (direction === "stop") {
this.xSpeed = 0;
this.ySpeed = 0;
}
};
// Create the ball object
var player = new Player();
// An object to convert keycodes into action names
var keyActions = {
32: "stop",
37: "left",
38: "up",
39: "right",
40: "down"
};
// The keydown handler that will be called for every keypress
$("html").keydown(function(event) {
var direction = keyActions[event.keyCode];
player.setDirection(direction);
});
var Ball = function() {
this.x = 100;
this.y = 100;
this.xSpeed = -2
this.ySpeed = 3;
this.radius = 3;
};
var circle = function(x, y, radius, fillCircle) {
ctx.beginPath();
ctx.arc(x, y, radius, 0, Math.PI * 2, false)
if (fillCircle) {
ctx.fill();
} else {
ctx.stroke();
}
}
Ball.prototype.move = function() {
this.x += this.xSpeed
this.y += this.ySpeed
if ((this.y + this.radius) > ctx.canvas.height) {
// floor to ceiling
this.y = 0;
}
};
Ball.prototype.draw = function() {
circle(this.x, this.y, this.radius, true);
};
Ball.prototype.getBox = function() {
return {
x: this.x - this.radius,
y: this.y - this.radius,
w: this.radius * 2,
h: this.radius * 2
};
};
Ball.prototype.checkCollision = function() {
if (this.x < 0 || this.x > 400) {
this.xSpeed = -this.xSpeed
}
if (this.y < 0) {
this.ySpeed = -this.ySpeed
} else {
var boxA = this.getBox();
switch (boxCollide(boxA, player)) {
case 1:
case 3:
this.ySpeed = -this.ySpeed;
break;
case 2:
case 4:
this.xSpeed = -this.xSpeed;
break;
}
}
};
// does box a collide with box b
// box = {x:num,y:num,w:num,h:num}
function boxCollide(a, b) {
var ax2 = a.x + a.w;
var ay2 = a.y + a.h;
var bx2 = b.x + b.w;
var by2 = b.y + b.h;
// simple hit true, false
//if (ax2 < b.x || a.x > bx2 || ay2 < b.y || a.y > by2) return false;
// return true
var xInRange = (a.x >= b.x && a.x <= bx2 || ax2 >= b.x && ax2 <= bx2);
var yInRange = (a.y >= b.y && a.y <= by2 || ay2 >= b.y && ay2 <= by2);
// Clockwise hit from top 1,2,3,4 or -1
if (ay2 > b.y && a.y < by2 && xInRange) return 1; // A hit the top of B
if (a.x < bx2 && ax2 > b.x && yInRange) return 2; // A hit the right of B
if (a.y < by2 && ay2 > b.y && xInRange) return 3; // A hit the bottom of B
if (ax2 > b.x && a.x < bx2 && yInRange) return 4; // A hit the right of B
return -1; // nohit
}
Ball.prototype.checkCollisionPlayer = function() {
if (this.x === Player.x || this.y === player.y) {
this.ySpeed = -this.ySpeed
this.xSpeed = -this.xSpeed
}
}
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
setInterval(function() {
ctx.clearRect(0, 0, 400, 400);
player.draw();
player.move();
ball.draw();
ball.move();
ball.checkCollision();
ball.checkCollisionPlayer();
var boxA = ball.getBox();
for (var i = 0; i < bricks.length; i++) {
switch (boxCollide(boxA, bricks[i])) {
case 1:
ball.y = bricks[i].y - ball.radius - 1;
ball.ySpeed = -ball.ySpeed;
bricks[i].hits++;
break;
case 3:
ball.y = bricks[i].y + ball.radius + bricks[i].h + 1;
ball.ySpeed = -ball.ySpeed;
bricks[i].hits++;
break;
case 2:
ball.x = bricks[i].x + ball.radius + bricks[i].w + 1;
ball.xSpeed = -ball.xSpeed;
bricks[i].hits++;
break;
case 4:
ball.x = bricks[i].x - ball.radius - 1;
ball.xSpeed = -ball.xSpeed;
bricks[i].hits++;
break;
}
bricks[i].draw();
}
},
40);
var ball = new Ball();
#canvas {
border: 1px solid black
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas" width="400" height="400"></canvas>
Hi I try to create an animation with a circle. The function drawRandom(drawFunctions) should pic one of the three drawcircle functions and should bring it on the canvas. Now the problem is that this function become executed every second (main loop) and the circle change his colour. How can I fix that?
window.onload = window.onresize = function() {
var C = 1; // canvas width to viewport width ratio
var el = document.getElementById("myCanvas");
var viewportWidth = window.innerWidth;
var viewportHeight = window.innerHeight;
var canvasWidth = viewportWidth * C;
var canvasHeight = viewportHeight;
el.style.position = "fixed";
el.setAttribute("width", canvasWidth);
el.setAttribute("height", canvasHeight);
var x = canvasWidth / 100;
var y = canvasHeight / 100;
var ballx = canvasWidth / 100;
var n;
window.ctx = el.getContext("2d");
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
// draw triangles
function init() {
ballx;
return setInterval(main_loop, 1000);
}
function drawcircle1()
{
var radius = x * 5;
ctx.beginPath();
ctx.arc(ballx * 108, canvasHeight / 2, radius, 0, 2 * Math.PI, false);
ctx.fillStyle = 'yellow';
ctx.fill();
}
function drawcircle2()
{
var radius = x * 5;
ctx.beginPath();
ctx.arc(ballx * 108, canvasHeight / 2, radius, 0, 2 * Math.PI, false);
ctx.fillStyle = 'blue';
ctx.fill();
}
function drawcircle3()
{
var radius = x * 5;
ctx.beginPath();
ctx.arc(ballx * 105, canvasHeight / 2, radius, 0, 2 * Math.PI, false);
ctx.fillStyle = 'orange';
ctx.fill();
}
function draw() {
var counterClockwise = false;
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
//first halfarc
ctx.beginPath();
ctx.arc(x * 80, y * 80, y * 10, 0 * Math.PI, 1 * Math.PI, counterClockwise);
ctx.lineWidth = y * 1;
ctx.strokeStyle = 'black';
ctx.stroke();
// draw stop button
ctx.beginPath();
ctx.moveTo(x * 87, y * 2);
ctx.lineTo(x * 87, y * 10);
ctx.lineWidth = x;
ctx.stroke();
ctx.beginPath();
ctx.moveTo(x * 95, y * 2);
ctx.lineTo(x * 95, y * 10);
ctx.lineWidth = x;
ctx.stroke();
function drawRandom(drawFunctions){
//generate a random index
var randomIndex = Math.floor(Math.random() * drawFunctions.length);
//call the function
drawFunctions[randomIndex]();
}
drawRandom([drawcircle1, drawcircle2, drawcircle3]);
}
function update() {
ballx -= 0.1;
if (ballx < 0) {
ballx = -radius;
}
}
function main_loop() {
draw();
update();
collisiondetection();
}
init();
function initi() {
console.log('init');
// Get a reference to our touch-sensitive element
var touchzone = document.getElementById("myCanvas");
// Add an event handler for the touchstart event
touchzone.addEventListener("mousedown", touchHandler, false);
}
function touchHandler(event) {
// Get a reference to our coordinates div
var can = document.getElementById("myCanvas");
// Write the coordinates of the touch to the div
if (event.pageX < x * 50 && event.pageY > y * 10) {
ballx += 1;
} else if (event.pageX > x * 50 && event.pageY > y * 10 ) {
ballx -= 1;
}
console.log(event, x, ballx);
draw();
}
initi();
draw();
}
Take a look at my code that I wrote:
var lastTime = 0;
function requestMyAnimationFrame(callback, time)
{
var t = time || 16;
var currTime = new Date().getTime();
var timeToCall = Math.max(0, t - (currTime - lastTime));
var id = window.setTimeout(function(){ callback(currTime + timeToCall); }, timeToCall);
lastTime = currTime + timeToCall;
return id;
}
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
canvas.width = window.innerWidth - 20;
canvas.height = window.innerHeight - 20;
canvas.style.width = canvas.width + "px";
canvas.style.height = canvas.height + "px";
var circles = [];
var mouse =
{
x: 0,
y: 0
}
function getCoordinates(x, y)
{
return "(" + x + ", " + y + ")";
}
function getRatio(n, d)
{
// prevent division by 0
if (d === 0 || n === 0)
{
return 0;
}
else
{
return n/d;
}
}
function Circle(x,y,d,b,s,c)
{
this.x = x;
this.y = y;
this.diameter = Math.round(d);
this.radius = Math.round(d/2);
this.bounciness = b;
this.speed = s;
this.color = c;
this.deltaX = 0;
this.deltaY = 0;
this.drawnPosition = "";
this.fill = function()
{
context.beginPath();
context.arc(this.x+this.radius,this.y+this.radius,this.radius,0,Math.PI*2,false);
context.closePath();
context.fill();
}
this.clear = function()
{
context.fillStyle = "#ffffff";
this.fill();
}
this.draw = function()
{
if (this.drawnPosition !== getCoordinates(this.x, this.y))
{
context.fillStyle = this.color;
// if commented, the circle will be drawn if it is in the same position
//this.drawnPosition = getCoordinates(this.x, this.y);
this.fill();
}
}
this.keepInBounds = function()
{
if (this.x < 0)
{
this.x = 0;
this.deltaX *= -1 * this.bounciness;
}
else if (this.x + this.diameter > canvas.width)
{
this.x = canvas.width - this.diameter;
this.deltaX *= -1 * this.bounciness;
}
if (this.y < 0)
{
this.y = 0;
this.deltaY *= -1 * this.bounciness;
}
else if (this.y+this.diameter > canvas.height)
{
this.y = canvas.height - this.diameter;
this.deltaY *= -1 * this.bounciness;
}
}
this.followMouse = function()
{
// deltaX/deltaY will currently cause the circles to "orbit" around the cursor forever unless it hits a wall
var centerX = Math.round(this.x + this.radius);
var centerY = Math.round(this.y + this.radius);
if (centerX < mouse.x)
{
// circle is to the left of the mouse, so move the circle to the right
this.deltaX += this.speed;
}
else if (centerX > mouse.x)
{
// circle is to the right of the mouse, so move the circle to the left
this.deltaX -= this.speed;
}
else
{
//this.deltaX = 0;
}
if (centerY < mouse.y)
{
// circle is above the mouse, so move the circle downwards
this.deltaY += this.speed;
}
else if (centerY > mouse.y)
{
// circle is under the mouse, so move the circle upwards
this.deltaY -= this.speed;
}
else
{
//this.deltaY = 0;
}
this.x += this.deltaX;
this.y += this.deltaY;
this.x = Math.round(this.x);
this.y = Math.round(this.y);
}
}
function getRandomDecimal(min, max)
{
return Math.random() * (max-min) + min;
}
function getRoundedNum(min, max)
{
return Math.round(getRandomDecimal(min, max));
}
function getRandomColor()
{
// array of three colors
var colors = [];
// go through loop and add three integers between 0 and 255 (min and max color values)
for (var i = 0; i < 3; i++)
{
colors[i] = getRoundedNum(0, 255);
}
// return rgb value (RED, GREEN, BLUE)
return "rgb(" + colors[0] + "," + colors[1] + ", " + colors[2] + ")";
}
function createCircle(i)
{
// diameter of circle
var minDiameter = 25;
var maxDiameter = 50;
// bounciness of circle (changes speed if it hits a wall)
var minBounciness = 0.2;
var maxBounciness = 0.65;
// speed of circle (how fast it moves)
var minSpeed = 0.3;
var maxSpeed = 0.45;
// getRoundedNum returns a random integer and getRandomDecimal returns a random decimal
var x = getRoundedNum(0, canvas.width);
var y = getRoundedNum(0, canvas.height);
var d = getRoundedNum(minDiameter, maxDiameter);
var c = getRandomColor();
var b = getRandomDecimal(minBounciness, maxBounciness);
var s = getRandomDecimal(minSpeed, maxSpeed);
// create the circle with x, y, diameter, bounciness, speed, and color
circles[i] = new Circle(x,y,d,b,s,c);
}
function makeCircles()
{
var maxCircles = getRoundedNum(2, 5);
for (var i = 0; i < maxCircles; i++)
{
createCircle(i);
}
}
function drawCircles()
{
var ii = 0;
for (var i = 0; ii < circles.length; i++)
{
if (circles[i])
{
circles[i].draw();
ii++;
}
}
}
function clearCircles()
{
var ii = 0;
for (var i = 0; ii < circles.length; i++)
{
if (circles[i])
{
circles[i].clear();
ii++;
}
}
}
function updateCircles()
{
var ii = 0;
for (var i = 0; ii < circles.length; i++)
{
if (circles[i])
{
circles[i].keepInBounds();
circles[i].followMouse();
ii++;
}
}
}
function update()
{
requestMyAnimationFrame(update,10);
updateCircles();
}
function draw()
{
requestMyAnimationFrame(draw,1000/60);
context.clearRect(0,0,canvas.width,canvas.height);
drawCircles();
}
window.addEventListener("load", function()
{
window.addEventListener("mousemove", function(e)
{
mouse.x = e.layerX || e.offsetX;
mouse.y = e.layerY || e.offsetY;
});
makeCircles();
update();
draw();
});
I found a pong game online and wanted to change it around a bit. I want to put a dashed line in the middle of the screen.
if I take out the dashed line the game works. It will work in Chrome but locks up on the Firefox OS simulator.
****Question: Why would this be the case?"****
Code:
function drawDashedLine() {
ctx.beginPath();
ctx.fillStyle = '#eee';
ctx.setLineDash([1,2]);
ctx.moveTo(0,H/2);
ctx.lineTo(320,H/2);
ctx.closePath();
ctx.stroke();
}
HTML:
<html>
<head>
<title>Firefox OS</title>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
// RequestAnimFrame: a browser API for getting smooth animations
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function( callback ){
return window.setTimeout(callback, 1000 / 60);
};
})();
window.cancelRequestAnimFrame = ( function() {
return window.cancelAnimationFrame ||
window.webkitCancelRequestAnimationFrame ||
window.mozCancelRequestAnimationFrame ||
window.oCancelRequestAnimationFrame ||
window.msCancelRequestAnimationFrame ||
clearTimeout
} )();
//all global variables
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d"); // Create canvas context
//W = window.innerWidth, // Window's width
//H = window.innerHeight, // Window's height
var W = 310;
var H = 440;
var particles = []; // Array containing particles
var ball = {}; // Ball object
var paddles = [2]; // Array containing two paddles
var mouse = {}; // Mouse object to store it's current position
var points = 0; // Varialbe to store points
var fps = 60; // Max FPS (frames per second)
var flag = 0; // Flag variable which is changed on collision
var particlePos = {}; // Object to contain the position of collision
var multipler = 1; // Varialbe to control the direction of sparks
var startBtn = {}; // Start button object
var restartBtn = {}; // Restart button object
var over = 0; // flag varialbe, cahnged when the game is over
var init; // variable to initialize animation
var paddleHit;
// Add mousemove and mousedown events to the canvas
canvas.addEventListener("mousemove", trackPosition, true);
canvas.addEventListener("mousedown", btnClick, true);
// Set the canvas's height and width to full screen
canvas.width = W;
canvas.height = H;
// Ball object
ball = {
x: 50,
y: 50,
r: 5,
c: "red",
vx: 3,
vy: 7,
// Function for drawing ball on canvas
draw: function() {
ctx.beginPath();
ctx.fillStyle = this.c;
ctx.arc(this.x, this.y, this.r, 0, Math.PI*2, false);
ctx.fill();
}
};
// Start Button object
startBtn = {
w: 100,
h: 50,
x: W/2 - 50,
y: H/2 - 25,
draw: function() {
ctx.strokeStyle = "white";
ctx.lineWidth = "2";
ctx.strokeRect(this.x, this.y, this.w, this.h);
ctx.font = "18px Arial, sans-serif";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStlye = "white";
ctx.fillText("Start", W/2, H/2 );
}
};
// Restart Button object
restartBtn = {
w: 100,
h: 50,
x: W/2 - 50,
y: H/2 - 50,
draw: function() {
ctx.strokeStyle = "white";
ctx.font = "18px Arial, sans-serif";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("Tap Center Screen To Play Again!", W/2, H/2 - 25 );
}
};
// Function to paint canvas
function paintCanvas() {
ctx.fillStyle = "black";
ctx.fillRect(0, 0, 310, 440);
}
// Function for creating paddles
function Paddle(pos) {
// Height and width
this.h = 8;
this.w = 55;
// Paddle's position
this.x = W/2 - this.w/2;
this.y = (pos == "top") ? 0 : H - this.h;
}
function draw() {
paintCanvas();
for(var i = 0; i < paddles.length; i++) {
p = paddles[i];
ctx.fillStyle = "white";
ctx.fillRect(p.x, p.y, p.w, p.h);
}
ball.draw();
update();
}
function increaseSpd() {
if(points % 2 == 33) {
if(Math.abs(ball.vx) < 15) {
ball.vx += (ball.vx < 0) ? -1 : 1;
ball.vy += (ball.vy < 0) ? -2 : 2;
}
}
}
function trackPosition(e) {
mouse.x = e.pageX;
mouse.y = e.pageY;
}
function movePaddles() {
if(mouse.x && mouse.y) {
for(var i = 1; i < paddles.length; i++) {
p = paddles[i];
p.x = mouse.x - p.w/2;
}
}
}
function collisions() {
if(collides(ball, p1)) {
collideAction(ball, p1);
}
else if(collides(ball, p2)) {
collideAction(ball, p2);
} else {
// Collide with walls, If the ball hits the top/bottom,
// walls, run gameOver() function
if(ball.y + ball.r > H) {
ball.y = H - ball.r;
gameOver(); //the game is over
} else if(ball.y < 0) {
ball.y = ball.r;
gameOver(); //the game is over
}
if(ball.x + ball.r > W) {
ball.vx = -ball.vx;
ball.x = W - ball.r;
} else if(ball.x -ball.r < 0) {
ball.vx = -ball.vx;
ball.x = ball.r;
}
}
}
function drawDashedLine() {
ctx.beginPath();
ctx.fillStyle = '#eee';
ctx.setLineDash([1,2]);
ctx.moveTo(0,H/2);
ctx.lineTo(320,H/2);
ctx.closePath();
ctx.stroke();
}
function update() {
updateScore();
movePaddles();
drawDashedLine()
ball.x += ball.vx;
ball.y += ball.vy;
p1 = paddles[1];
p2 = paddles[2];
collisions();
flag = 0;
}
function collides(b, p) {
if(b.x + ball.r >= p.x &&
b.x - ball.r <=p.x + p.w) {
if(b.y >= (p.y - p.h) && p.y > 0){
paddleHit = 1;
return true;
} else if(b.y <= p.h && p.y == 0) {
paddleHit = 2;
return true;
} else {
return false;
}
}
}
function collideAction(ball, p) {
ball.vy = -ball.vy;
if(paddleHit == 1) {
ball.y = p.y - p.h;
particlePos.y = ball.y + ball.r;
multiplier = -1;
} else if(paddleHit == 2) {
ball.y = p.h + ball.r;
particlePos.y = ball.y - ball.r;
multiplier = 1;
}
points++;
if(collision) {
if(points > 0) {
collision.pause();
}
collision.currentTime = 0;
collision.play();
}
particlePos.x = ball.x;
flag = 1;
}
// Function for updating score
function updateScore() {
ctx.fillStlye = "green";
ctx.font = "20px Arial, sans-serif";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText(points, 20, 20 );
}
// Function to run when the game overs
function gameOver() {
ctx.fillStlye = "white";
ctx.font = "20px Arial, sans-serif";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("Game Over! ("+points+")", W/2, H/2 + 25 );
cancelRequestAnimFrame(init); //stops the animation frame
over = 1;
restartBtn.draw(); //This will allow the user to restart the game
}
// Function for running the whole animation
function animloop() {
init = requestAnimFrame(animloop);
draw();
}
// Function to execute at startup
function startScreen() {
draw();
startBtn.draw();
}
// On button click (Restart and start)
function btnClick(e) {
var mx = e.pageX;
var my = e.pageY;
if(mx >= startBtn.x && mx <= startBtn.x + startBtn.w) {
animloop();
startBtn = {};
}
// If the game is over, and the restart button is clicked
if(over == 1) {
if(mx >= restartBtn.x && mx <= restartBtn.x + restartBtn.w) {
ball.x = 20;
ball.y = 20;
points = 0;
ball.vx = 4;
ball.vy = 8;
animloop();
over = 0;
}
}
}
paddles.push(new Paddle("bottom"));
paddles.push(new Paddle("top"));
startScreen();
</script>
</body>
</html>