Ball interactions in physics respects the law of conservation of momentum which is Newton's third law.
To do this, we will take the x and y velocities of two colliding balls, and draw a "line of action" between their centers.
To calculate conservation of momentum, we need to add a new property: mass.
To do a circle/circle collision-detection, we can calculate the distance between two centers of the circles.
Then check if the distance is smaller than the sum of the radius.
<!doctype html> <html lang="en"> <head> <script type="text/javascript"> window.addEventListener('load', eventWindowLoaded, false); function eventWindowLoaded() {//from ww w . j av a 2s . c o m canvasApp(); } function canvasApp() { function drawScreen () { context.fillStyle = '#EEEEEE'; context.fillRect(0, 0, theCanvas.width, theCanvas.height); //Box context.strokeStyle = '#000000'; context.strokeRect(1, 1, theCanvas.width-2, theCanvas.height-2); update(); testWalls(); collide(); render(); } function update() { for (let i =0; i <balls.length; i++) { ball = balls[i]; ball.nextx = (ball.x += ball.velocityx); ball.nexty = (ball.y += ball.velocityy); } } function testWalls() { let ball; let testBall; for (let i =0; i <balls.length; i++) { ball = balls[i]; if (ball.nextx+ball.radius > theCanvas.width) { ball.velocityx = ball.velocityx*-1; ball.nextx = theCanvas.width - ball.radius; } else if (ball.nextx-ball.radius < 0 ) { ball.velocityx = ball.velocityx*-1; ball.nextx = ball.radius; } else if (ball.nexty+ball.radius > theCanvas.height ) { ball.velocityy = ball.velocityy*-1; ball.nexty = theCanvas.height - ball.radius; } else if(ball.nexty-ball.radius < 0) { ball.velocityy = ball.velocityy*-1; ball.nexty = ball.radius; } } } function render() { let ball; context.fillStyle = "#000000"; for (let i =0; i <balls.length; i++) { 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 collide() { let ball; let testBall; for (let i =0; i <balls.length; i++) { ball = balls[i]; for (let j = i+1; j < balls.length; j++) { testBall = balls[j]; if (hitTestCircle(ball,testBall)) { collideBalls(ball,testBall); } } } } function hitTestCircle(ball1,ball2) { let retval = false; let dx = ball1.nextx - ball2.nextx; let dy = ball1.nexty - ball2.nexty; let distance = (dx * dx + dy * dy); if (distance <= (ball1.radius + ball2.radius) * (ball1.radius + ball2.radius) ) { retval = true; } return retval; } function collideBalls(ball1,ball2) { let dx = ball1.nextx - ball2.nextx; let dy = ball1.nexty - ball2.nexty; let collisionAngle = Math.atan2(dy, dx); let speed1 = Math.sqrt(ball1.velocityx * ball1.velocityx + ball1.velocityy * ball1.velocityy); let speed2 = Math.sqrt(ball2.velocityx * ball2.velocityx + ball2.velocityy * ball2.velocityy); let direction1 = Math.atan2(ball1.velocityy, ball1.velocityx); let direction2 = Math.atan2(ball2.velocityy, ball2.velocityx); let velocityx_1 = speed1 * Math.cos(direction1 - collisionAngle); let velocityy_1 = speed1 * Math.sin(direction1 - collisionAngle); let velocityx_2 = speed2 * Math.cos(direction2 - collisionAngle); let velocityy_2 = speed2 * Math.sin(direction2 - collisionAngle); let final_velocityx_1 = ((ball1.mass - ball2.mass) * velocityx_1 + (ball2.mass + ball2.mass) * velocityx_2)/(ball1.mass + ball2.mass); let final_velocityx_2 = ((ball1.mass + ball1.mass) * velocityx_1 + (ball2.mass - ball1.mass) * velocityx_2)/(ball1.mass + ball2.mass); let final_velocityy_1 = velocityy_1; let final_velocityy_2 = velocityy_2; ball1.velocityx = Math.cos(collisionAngle) * final_velocityx_1 + Math.cos(collisionAngle + Math.PI/2) * final_velocityy_1; ball1.velocityy = Math.sin(collisionAngle) * final_velocityx_1 + Math.sin(collisionAngle + Math.PI/2) * final_velocityy_1; ball2.velocityx = Math.cos(collisionAngle) * final_velocityx_2 + Math.cos(collisionAngle + Math.PI/2) * final_velocityy_2; ball2.velocityy = Math.sin(collisionAngle) * final_velocityx_2 + Math.sin(collisionAngle + Math.PI/2) * final_velocityy_2; ball1.nextx = (ball1.nextx += ball1.velocityx); ball1.nexty = (ball1.nexty += ball1.velocityy); ball2.nextx = (ball2.nextx += ball2.velocityx); ball2.nexty = (ball2.nexty += ball2.velocityy); } let numBalls = 200 ; let maxSize = 15; let minSize = 5; let maxSpeed = maxSize+5; let balls = new Array(); let tempBall; let tempX; let tempY; let tempSpeed; let tempAngle; let tempRadius; let tempRadians; let tempvelocityx; let tempvelocityy; theCanvas = document.getElementById('canvasOne'); context = theCanvas.getContext('2d'); for (let i = 0; i < numBalls; i++) { tempRadius = 5; let 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); tempRadians = tempAngle * Math.PI/ 180; tempvelocityx = Math.cos(tempRadians) * tempSpeed; tempvelocityy = Math.sin(tempRadians) * tempSpeed; tempBall = {x:tempX,y:tempY, nextX: tempX, nextY: tempY, radius:tempRadius, speed:tempSpeed, angle:tempAngle, velocityx:tempvelocityx, velocityy:tempvelocityy, mass:tempRadius}; placeOK = canStartHere(tempBall); } balls.push(tempBall); } function canStartHere(ball) { let retval = true; for (let i =0; i <balls.length; i++) { if (hitTestCircle(ball, balls[i])) { retval = false; } } return retval; } function gameLoop() { window.setTimeout(gameLoop, 20); drawScreen() } gameLoop(); } </script> </head> <body> <div style="position: absolute; top: 50px; left: 50px;"> <canvas id="canvasOne" width="500" height="500"> Your browser does not support the HTML 5 Canvas. </canvas> </div> </body> </html>