My previous example involved a single ball bouncing off walls. This example is much more complex, with 200 balls bouncing and colliding with walls and each other. It does the following, in this order:

1. Create a temporary ball and place it in a random location, with a random angle and velocity.
2. Check if the temporary ball’s location is the same location as another ball. If so, then move it and check again. If not, then add the ball to the balls array.
3. After each ball has been placed, draw each moving ball according to a set interval.
4. Check if a ball is about to collide with a wall. If so, account for a collision.
5. Check if a ball is about to collide with another ball. If so, account for a collision.
6. Repeat steps 3-5.

## The JavaScript

```\$(document).ready(function() {
// Uses Modernizr.js to check for canvas support
function canvasSupport() {
return Modernizr.canvas;
}

canvasApp();

function canvasApp() {
// Check for canvas support
if (!canvasSupport()) {
return;
} else {
// Grab the canvas and set the context to 2d
var theCanvas = document.getElementById('canvasOne');
var context = theCanvas.getContext("2d");
}

// Variables
var numBalls = 200;  // number of balls
var maxSize = 15;
var minSize = 5;
var maxSpeed = maxSize + 5;
var balls = new Array();
var tempBall;
var tempX;
var tempY;
var tempSpeed;
var tempAngle;
var tempVelocityX;
var tempVelocityY;

// Find spots to place each ball so none start on top of each other
for (var i = 0; i < numBalls; i += 1) {
var placeOK = false;
while (!placeOK) {
tempX = tempRadius * 3 + (Math.floor(Math.random() * theCanvas.width) - tempRadius * 3);
tempY = tempRadius * 3 + (Math.floor(Math.random() * theCanvas.height) - tempRadius * 3);
tempSpeed = 4;
tempAngle = Math.floor(Math.random() * 360);

tempBall = {
x: tempX,
y: tempY,
nextX: tempX,
nextY: tempY,
speed: tempSpeed,
angle: tempAngle,
velocityX: tempVelocityX,
velocityY: tempVelocityY,
};
placeOK = canStartHere(tempBall);
}
balls.push(tempBall);
}

// Drawing interval
setInterval(drawScreen, 33);

// Functions
// Returns true if a ball can start at given location, otherwise returns false
function canStartHere(ball) {
var retVal = true;
for (var i = 0; i < balls.length; i += 1) {
if (hitTestCircle(ball, balls[i])) {
retVal = false;
}
}
return retVal;
}

// Circle collision test to see if two balls are touching
// Uses nextX and nextY to test for collision before it occurs
function hitTestCircle(ball1, ball2) {
var retVal = false;
var dx = ball1.nextX - ball2.nextX;
var dy = ball1.nextY - ball2.nextY;
var distance = (dx * dx + dy * dy);
retVal = true;
}
return retVal;
}

// Loops through all the balls in the balls array and updates the nextX and nextY properties
// with current x and y velocities for each ball
function update() {
for (var i = 0; i < balls.length; i += 1) {
ball = balls[i];
ball.nextX = (ball.x += ball.velocityX);
ball.nextY = (ball.y += ball.velocityY);
}
}

// We track balls by their center, so we test for all collision by adding or subtracting
// each ball's radius before testing for wall collision
function testWalls() {
var ball;
var testBall;

for (var i = 0; i < balls.length; i += 1) {
ball = balls[i];

if (ball.nextX + ball.radius > theCanvas.width) { // right wall
ball.velocityX = ball.velocityX * (-1);

} else if (ball.nextX - ball.radius < 0) { // top wall
ball.velocityX = ball.velocityX * (-1);

} else if (ball.nextY + ball.radius > theCanvas.height) { // bottom wall
ball.velocityY = ball.velocityY * (-1);

} else if (ball.nextY - ball.radius < 0) { // left wall
ball.velocityY = ball.velocityY * (-1);
}
}
}

// Tests whether any balls have hit each other.
// Uses two next loops to iterate through the balls array and test each ball against every other ball.
function collide() {
var ball;
var testBall;
for (var i = 0; i < balls.length; i += 1) {
ball = balls[i];
for (var j = i + 1; j < balls.length; j += 1) {
testBall = balls[j];
if (hitTestCircle(ball, testBall)) {
collideBalls(ball, testBall);
}
}
}
}

// Updates properties of colliding balls so they appear to bounce off each other.
// Uses nextX and nextY properties because we don't want to change where they are at the moment.
function collideBalls(ball1, ball2) {
var dx = ball1.nextX - ball2.nextX;
var dy = ball1.nextY - ball2.nextY;
var collisionAngle = Math.atan2(dy, dx);

// Get velocities of each ball before collision
var speed1 = Math.sqrt(ball1.velocityX * ball1.velocityX + ball1.velocityY * ball1.velocityY);
var speed2 = Math.sqrt(ball2.velocityX * ball2.velocityX + ball2.velocityY * ball2.velocityY);

// Get angles (in radians) for each ball, given current velocities
var direction1 = Math.atan2(ball1.velocityY, ball1.velocityX);
var direction2 = Math.atan2(ball2.velocityY, ball2.velocityX);

// Rotate velocity vectors so we can plug into equation for conservation of momentum
var rotatedVelocityX1 = speed1 * Math.cos(direction1 - collisionAngle);
var rotatedVelocityY1 = speed1 * Math.sin(direction1 - collisionAngle);
var rotatedVelocityX2 = speed2 * Math.cos(direction2 - collisionAngle);
var rotatedVelocityY2 = speed2 * Math.sin(direction2 - collisionAngle);

// Update actual velocities using conservation of momentum
/* Uses the following formulas:
velocity1 = ((mass1 - mass2) * velocity1 + 2*mass2 * velocity2) / (mass1 + mass2)
velocity2 = ((mass2 - mass1) * velocity2 + 2*mass1 * velocity1) / (mass1 + mass2)
*/
var finalVelocityX1 = ((ball1.mass - ball2.mass) * rotatedVelocityX1 + (ball2.mass + ball2.mass) * rotatedVelocityX2)
/ (ball1.mass + ball2.mass);
var finalVelocityX2 = ((ball1.mass + ball1.mass) * rotatedVelocityX1 + (ball2.mass - ball1.mass) * rotatedVelocityX2)
/ (ball1.mass + ball2.mass);

// Y velocities remain constant
var finalVelocityY1 = rotatedVelocityY1;
var finalVelocityY2 = rotatedVelocityY2;

// Rotate angles back again so the collision angle is preserved
ball1.velocityX = Math.cos(collisionAngle) * finalVelocityX1 + Math.cos(collisionAngle + Math.PI/2) * finalVelocityY1;
ball1.velocityY = Math.sin(collisionAngle) * finalVelocityX1 + Math.sin(collisionAngle + Math.PI/2) * finalVelocityY1;
ball2.velocityX = Math.cos(collisionAngle) * finalVelocityX2 + Math.cos(collisionAngle + Math.PI/2) * finalVelocityY2;
ball2.velocityY = Math.sin(collisionAngle) * finalVelocityX2 + Math.sin(collisionAngle + Math.PI/2) * finalVelocityY2;

// Update nextX and nextY for both balls so we can use them in render() or another collision
ball1.nextX += ball1.velocityX;
ball1.nextY += ball1.velocityY;
ball2.nextX += ball2.velocityX;
ball2.nextY += ball2.velocityY;
}

// Draws and updates each ball
function render() {
var ball;
context.fillStyle = "#000000";
for (var i = 0; i < balls.length; i += 1) {
ball = balls[i];
ball.x = ball.nextX;
ball.y = ball.nextY;

context.beginPath();
context.arc(ball.x, ball.y, ball.radius, 0, Math.PI *2, true);
context.closePath();
context.fill();
}
}

function drawScreen() {
// Reset canvas
context.fillStyle = "#EEEEEE";
context.fillRect(0, 0, theCanvas.width, theCanvas.height);

// Outside border
context.strokeStyle = "#000000";
context.strokeRect(1, 1, theCanvas.width - 2, theCanvas.height - 2);

update();
testWalls();
collide();
render();
}
}

});```

## The Example

You can find a live version of the demo here: https://www.zesix.com/html5/multipleBallsBouncingAndColliding/