Reputation: 1
So for a project I'm working on, I would like four different sized canvases with four balls bouncing off the walls at the same speed. The code works fine when all the canvases are the same size, but as soon as I try and adjust the canvases heights and widths, the ball continues to bounce in an area the size of the first canvas. I'm not sure what I'm doing wrong, and I would really appreciate some help. I'm fairly new to javascript.
Here is the HTML:
<canvas id="canvas1" width="200" height="200"></canvas>
<canvas id="canvas2" width="200" height="400"></canvas>
<canvas id="canvas3" width="400" height="200"></canvas>
<canvas id="canvas4" width="200" height="200"></canvas>
And here is the Javascript:
var canvas = document.getElementById("canvas1");
var ctx = canvas.getContext("2d");
var x = canvas.width/2;
var y = canvas.height-30;
var dx = -2;
var dy = 2;
var ballRadius = 10;
var canvas2 = document.getElementById("canvas2");
var ctx2 = canvas2.getContext("2d");
var x2 = canvas2.width/2;
var y2 = canvas2.height-30;
var canvas3 = document.getElementById("canvas3");
var ctx3 = canvas3.getContext("2d");
var x3 = canvas3.width/2;
var y3 = canvas3.height-30;
var canvas4 = document.getElementById("canvas4");
var ctx4 = canvas4.getContext("2d");
var x4 = canvas4.width/2;
var y4 = canvas4.height-30;
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
ctx2.beginPath();
ctx2.arc(x2, y2, ballRadius, 0, Math.PI*2);
ctx2.fillStyle = "#0095DD";
ctx2.fill();
ctx2.closePath();
ctx3.beginPath();
ctx3.arc(x3, y3, ballRadius, 0, Math.PI*2);
ctx3.fillStyle = "#0095DD";
ctx3.fill();
ctx3.closePath();
ctx4.beginPath();
ctx4.arc(x4, y4, ballRadius, 0, Math.PI*2);
ctx4.fillStyle = "#0095DD";
ctx4.fill();
ctx4.closePath();
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx2.clearRect(0, 0, canvas2.width, canvas2.height);
ctx3.clearRect(0, 0, canvas3.width, canvas3.height);
ctx4.clearRect(0, 0, canvas4.width, canvas4.height);
drawBall();
x += dx;
y += dy;
x2 += dx;
y2 += dy;
x3 += dx;
y3 += dy;
x4 += dx;
y4 += dy;
if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
dy = -dy; }
if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
dx = -dx; }
if(y2 + dy > canvas2.height-ballRadius || y2 + dy < ballRadius) {
dy = -dy; }
if(x2 + dx > canvas2.width-ballRadius || x2 + dx < ballRadius) {
dx = -dx; }
if(y3 + dy > canvas3.height-ballRadius || y3 + dy < ballRadius) {
dy = -dy; }
if(x3 + dx > canvas3.width-ballRadius || x3 + dx < ballRadius) {
dx = -dx; }
if(y4 + dy > canvas4.height-ballRadius || y4 + dy < ballRadius) {
dy = -dy; }
if(x4 + dx > canvas4.width-ballRadius || x4 + dx < ballRadius) {
dx = -dx; }
}
setInterval(draw, 10);
Upvotes: 0
Views: 147
Reputation: 2925
In your code the balls share the same velocity values (dx,dy) which will result in all balls behaving the same way.
One way of solving your issue and make your code cleaner (/scalable) is to create a class for handling the drawing, and different instances of that class for each canvas, ensuring canvas x,y, velocity and other variables are separate
I forked a fiddle from @JupeP where I create a base class and new instances for each canvas by passing the individual Canvas id.
http://jsfiddle.net/jtjpv2bf/1/
<canvas id="myCanvas" width="800" height="400" style="border:1px solid #000000;"></canvas>
<canvas id="myCanvas1" width="400" height="400" style="border:1px solid #000000;"></canvas>
<canvas id="myCanvas2" width="200" height="200" style="border:1px solid #000000;"></canvas>
<canvas id="myCanvas3" width="600" height="300" style="border:1px solid #000000;"></canvas>
window.requestAnimFrame =
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
AnimationHandler = function(canvasId) {
var canvas, WIDTH, HEIGHT,
ctx, dx, dy, x, y;
function init() {
// find the <canvas> element
canvas = document.getElementById(canvasId);
WIDTH = canvas.width;
HEIGHT = canvas.height;
// get canvas context
ctx = canvas.getContext("2d");
(...)
}
AnimationHandler.prototype = {}
AnimationHandler.prototype.constructor = init;
...
return init();
};
new AnimationHandler("myCanvas");
new AnimationHandler("myCanvas1");
new AnimationHandler("myCanvas2");
new AnimationHandler("myCanvas3");
RequestAnimationFrame
Also, consider using requestAnimationFrame instead of setInterval. It's an optimized API that browsers use for concurrent animations and will pause if not in an active tab (saves battery/ improves perfomance).
Paul Irish explains it here
Upvotes: 2
Reputation: 69
EDIT
my code doesn't work, but you can still take the idea of proportions with the values and use a different variable for each dx and dy
Instead of using dx and dy for the speed of each ball, use corresponding numbers for canvas and ball:
// dx1, dx2, dx3, dx4, dy1, dy2, dy3, dy4 instead of dx, dy
// also you can use proportions to keep them bouncing at the same time
// see below
var canvas = document.getElementById("canvas1");
var ctx = canvas.getContext("2d");
var x = canvas.width/2;
var y = canvas.height/2;
/*var dx = -2;
var dy = 2;*/
var ballRadius = 10;
var canvas2 = document.getElementById("canvas2");
var ctx2 = canvas2.getContext("2d");
var x2 = canvas2.width/2;
var y2 = canvas2.height/2;
var canvas3 = document.getElementById("canvas3");
var ctx3 = canvas3.getContext("2d");
var x3 = canvas3.width/2;
var y3 = canvas3.height/2;
var canvas4 = document.getElementById("canvas4");
var ctx4 = canvas4.getContext("2d");
var x4 = canvas4.width/2;
var y4 = canvas4.height/2;
/***********************************************/
/***********************************************/
/***********************************************/
/***********************************************/
/***********************************************/
var dx1 = 2, dx2 = dx1*canvas2.width/canvas.width, dx3 = dx1*canvas3.width/canvas.width, dx4 = dx1*canvas4.width/canvas.width;
var dy1 = 2, dy2 = dy1*canvas2.height/canvas.height, dy3 = dy1*canvas3.height/canvas.height, dy4 = dy1*canvas4.height/canvas.height;
function drawBalls() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
ctx2.beginPath();
ctx2.arc(x2, y2, ballRadius, 0, Math.PI*2);
ctx2.fillStyle = "#0095DD";
ctx2.fill();
ctx2.closePath();
ctx3.beginPath();
ctx3.arc(x3, y3, ballRadius, 0, Math.PI*2);
ctx3.fillStyle = "#0095DD";
ctx3.fill();
ctx3.closePath();
ctx4.beginPath();
ctx4.arc(x4, y4, ballRadius, 0, Math.PI*2);
ctx4.fillStyle = "#0095DD";
ctx4.fill();
ctx4.closePath();
}
function clearCanvases() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx2.clearRect(0, 0, canvas2.width, canvas2.height);
ctx3.clearRect(0, 0, canvas3.width, canvas3.height);
ctx4.clearRect(0, 0, canvas4.width, canvas4.height);
}
function changeSpeeds() {
x += dx1;
y += dy1;
x2 += dx2;
y2 += dy2;
x3 += dx3;
y3 += dy3;
x4 += dx4;
y4 += dy4;
}
function what(a, b, c, r)
{
if (a + b > c - r || a + b < r)
{
b = -b;
}
}
function checkForCollisions() {
what(y, dy1, canvas.height, ballRadius);
what(x, dx1, canvas.width, ballRadius);
what(y2, dy2, canvas2.height, ballRadius);
what(x2, dx2, canvas2.width, ballRadius);
what(y3, dy3, canvas3.height, ballRadius);
what(x3, dx3, canvas3.width, ballRadius);
what(y4, dy4, canvas4.height, ballRadius);
what(x4, dx4, canvas4.width, ballRadius);
}
// I split the draw function into four functions, named bounceBalls
function bounceBalls()
{
clearCanvases(); // context.clearRect for each of the four canvases...
drawBalls(); // drawBall in your code
changeSpeeds();
checkForCollisions(); // bouncing against sides
}
var FPS = 60;
window.setInterval(bounceBalls, 1000/FPS);
Upvotes: 0
Reputation: 126
The problem is that all of the balls share the same velocity (dx,dy), so when one of the balls hits a wall it causes all of them to bounce. To fix it you'd need to have a velocity for each individual ball (dx2,dy2,etc)
Upvotes: 2