//Class definition - Start function Ball(x, y) { this.x = x; this.y = y; this.r = 10; this.vx = 0; //Math.random(10); this.vy = 0; //Math.random(10); this.ax = 0; this.ay = g; this.color_R = Math.round(Math.random() * 255); this.color_G = Math.round(Math.random() * 255); this.color_B = Math.round(Math.random() * 255); } Ball.prototype = { draw: function() { this.vx += this.ax; this.vy += this.ay; this.x += this.vx; this.y += this.vy; //if ball hit with border if (isTopWallCollision(this)) { this.y = this.r; this.vy *= -1 * restitutionCoefficient_of_border } if (isBottomWallCollision(this)) { this.y = canvas.height - this.r; this.vy *= -1 * restitutionCoefficient_of_border } if (isLeftWallCollision(this)) { this.x = this.r; this.vx *= -1 * restitutionCoefficient_of_border } if (isRightWallCollision(this)) { this.x = canvas.width - this.r; this.vx *= -1 * restitutionCoefficient_of_border } context.beginPath(); context.arc(this.x, this.y, this.r, 0, Math.PI * 2, false); context.fillStyle = 'rgba(' + this.color_R + ', ' + this.color_G + ', ' + this.color_B + ', 1)'; context.fill() } } //Class definition - End //Config - Start // var ballCount = 30; var ballList = []; var g = 0.1; var restitutionCoefficient_of_border = 0.9; var restitutionCoefficient_of_ball = 0.5; //Config - End // var canvas = document.querySelectorAll("canvas")[0]; var context = canvas.getContext("2d"); //Create balls for (var i = 0; i < ballCount; i++) { var isNewBallCollision = false; var newBall; do { newBall = new Ball(Math.random() * canvas.width, Math.random() * canvas.height); isNewBallCollision = isWallCollision(newBall); if (isNewBallCollision){ continue; } for (var j = 0; j < ballList.length; j++) { isNewBallCollision = isBallCollision(ballList[j], newBall); if (isNewBallCollision) { break; } } } while (isNewBallCollision); ballList.push(newBall); } draw(); canvas.addEventListener('click', function(e) { var x = event.clientX; var y = event.clientY; var rect = this.getBoundingClientRect(); //Recalculate mouse offsets to relative offsets x -= rect.left; y -= rect.top; //Also recalculate offsets of canvas is stretched //changes coordinates by ratio x *= this.width / this.clientWidth; y *= this.height / this.clientHeight; ballList.push(new Ball(x, y)); }) function draw() { context.clearRect(0, 0, canvas.width, canvas.height); for (var i = 0; i < ballList.length; i++) { ballList[i].draw(); for (var j = i + 1; j < ballList.length; j++) { if (isBallCollision(ballList[i], ballList[j])) { ballCollision(ballList[i], ballList[j]); } } } requestAnimationFrame(draw); } function isBallCollision(ball1, ball2) { return Math.pow(ball1.x - ball2.x, 2) + Math.pow(ball1.y - ball2.y, 2) <= Math.pow(ball1.r + ball2.r, 2) } //Wall Collision functions - Start function isWallCollision(ball) { return isTopWallCollision(ball) || isBottomWallCollision(ball) || isLeftWallCollision(ball) || isRightWallCollision(ball); } function isTopWallCollision(ball) { return (ball.y - ball.r) <= 0; } function isBottomWallCollision(ball) { return (ball.y + ball.r) >= canvas.height; } function isLeftWallCollision(ball) { return (ball.x - ball.r) <= 0; } function isRightWallCollision(ball) { return (ball.x + ball.r) >= canvas.width; } //Wall Collision functions - End function ballCollision(ball1, ball2) { var clooisionVectorLength = Math.sqrt(Math.pow((ball1.x - ball2.x), 2) + Math.pow((ball1.y - ball2.y), 2)); var collisionX = (ball1.x - ball2.x) / clooisionVectorLength; var collisionY = (ball1.y - ball2.y) / clooisionVectorLength; var collision_ball1_x = Math.pow(collisionX, 2) * ball1.vx + collisionX * collisionY * ball1.vy; var collision_ball1_y = collisionX * collisionY * ball1.vx + Math.pow(collisionY, 2) * ball1.vy; var collision_ball2_x = Math.pow(collisionX, 2) * ball2.vx + collisionX * collisionY * ball2.vy; var collision_ball2_y = collisionX * collisionY * ball2.vx + Math.pow(collisionY, 2) * ball2.vy; ball1.vx = collision_ball2_x + (ball1.vx - collision_ball1_x); ball1.vy = collision_ball2_y + (ball1.vy - collision_ball1_y); ball2.vx = collision_ball1_x + (ball2.vx - collision_ball2_x); ball2.vy = collision_ball1_y + (ball2.vy - collision_ball2_y); ball1.vx *= restitutionCoefficient_of_ball; ball1.vy *= restitutionCoefficient_of_ball; ball2.vx *= restitutionCoefficient_of_ball; ball2.vy *= restitutionCoefficient_of_ball; ball1.x += collisionX * (ball1.r + ball2.r - clooisionVectorLength); ball1.y += collisionY * (ball1.r + ball2.r - clooisionVectorLength); ball2.x += -1 * collisionX * (ball1.r + ball2.r - clooisionVectorLength); ball2.y += -1 * collisionY * (ball1.r + ball2.r - clooisionVectorLength); }
Click mouse to create more balls. <canvas></canvas>
canvas { display: block; width: 100%; height: 100%; border: 1px solid blue; }