I really like @schteppe's answer above. I just want to tell you about this link here: http://www.paulirish.com/2011/requestanimationframe-for-smart-animating/
Check "Why should I use it?" section. It may seem that there are some hints to the answer to your question about what exactly is wrong with your code.
I also tried to get your code to work, by the way, but without significant result. You can check my fiddle (which I copied from you) here: http://jsfiddle.net/sukhmeetsd/joqpqp49/
var canvas = document.getElementById("canvas") var ctx = canvas.getContext("2d") var w = canvas.width var h = canvas.height var d = 5; //distance to move on collision var ball = [] var gravity = 0.3 var force = 0.2 var mouse = { d: false, x1: 0, y1: 0, x2: 0, y2: 0, } window.onmousedown = function (e) { mouse.d = true mouse.x1 = mouse.x2 = e.pageX - canvas.getBoundingClientRect().left mouse.y1 = mouse.y2 = e.pageY - canvas.getBoundingClientRect().top } window.onmousemove = function (e) { if (mouse.d) { mouse.x2 = e.pageX - canvas.getBoundingClientRect().left mouse.y2 = e.pageY - canvas.getBoundingClientRect().top } else { mouse.x1 = mouse.x2 = e.pageX - canvas.getBoundingClientRect().left mouse.y1 = mouse.y2 = e.pageY - canvas.getBoundingClientRect().top } } window.onmouseup = function () { if (mouse.d) { mouse.d = false var dx = (mouse.x1 - mouse.x2); var dy = (mouse.y1 - mouse.y2); var mag = Math.sqrt(dx * dx + dy * dy); ball.push({ x: mouse.x1, y: mouse.y1, r: Math.floor(Math.random() * 20) + 10, vx: dx / mag * -(mag * force), vy: dy / mag * -(mag * force), b: 0.7, }) } } function getRandomColor() { var letters = '0123456789ABCDEF'.split(''); var color = '#'; for (var i = 0; i < 6; i++ ) { color += letters[Math.floor(Math.random() * 16)]; } return color; } document.onselectstart = function () { return false } document.oncontextmenu = function () { return false } setInterval(update, 1000/60) function update() { ctx.clearRect(0, 0, w, h) ctx.beginPath() ctx.moveTo(mouse.x1, mouse.y1) ctx.lineTo(mouse.x2, mouse.y2) ctx.stroke() ctx.closePath() for (i = 0; i < ball.length; i++) { ball[i].vy += gravity ball[i].x += ball[i].vx ball[i].y += ball[i].vy if (ball[i].x > w - ball[i].r) { ball[i].x = w - ball[i].r ball[i].vx *= -ball[i].b } if (ball[i].x < ball[i].r) { ball[i].x = ball[i].r ball[i].vx *= -ball[i].b } if (ball[i].y > h - ball[i].r) { ball[i].y = h - ball[i].r ball[i].vy *= -ball[i].b } if (ball[i].y < ball[i].r) { ball[i].y = ball[i].r ball[i].vy *= -ball[i].b } for (j = i + 1; j < ball.length; j++) { var dx = ball[i].x - ball[j].x var dy = ball[i].y - ball[j].y var dist = Math.sqrt(dx * dx + dy * dy) if (Math.abs(dx) + Math.abs(dy) != 0 && dist <= ball[i].r + ball[j].r) { var angle = Math.atan2(dy, dx) var sp1 = Math.sqrt(ball[i].vx * ball[i].vx + ball[i].vy * ball[i].vy); var sp2 = Math.sqrt(ball[j].vx * ball[j].vx + ball[j].vy * ball[j].vy); var dir1 = Math.atan2(ball[i].vy, ball[i].vx); var dir2 = Math.atan2(ball[j].vy, ball[j].vx); d = Math.ceil(ball[i].r+ball[j].r-dist)/2; //moving them back ball[i].x = ball[i].x - Math.cos(dir1)*d-1; ball[i].y = ball[i].y - Math.sin(dir1)*d-1; ball[j].x = ball[j].x + Math.cos(dir2)*d+1; ball[j].y = ball[j].y + Math.sin(dir2)*d+1; //Checking for distance again /*dx = ball[i].x - ball[j].x; dy = ball[i].y - ball[j].y; dist = Math.sqrt(dx * dx + dy * dy); if (Math.abs(dx) + Math.abs(dy) != 0 && dist <= ball[i].r + ball[j].r){ ball[i].x = ball[i].x + Math.cos(dir1)*2*d; ball[i].y = ball[i].y + Math.sin(dir1)*d*2; ball[j].x = ball[j].x - Math.cos(dir2)*d*2; ball[j].y = ball[j].y - Math.sin(dir2)*d*2; }*/ var vx1 = sp1 * Math.cos(dir1 - angle); var vy1 = sp1 * Math.sin(dir1 - angle); var vx2 = sp2 * Math.cos(dir2 - angle); var vy2 = sp2 * Math.sin(dir2 - angle); var fvx1 = ((ball[i].r - ball[j].r) * vx1 + (2 * ball[j].r) * vx2) / (ball[i].r + ball[j].r); var fvx2 = ((2 * ball[i].r) * vx1 + (ball[j].r - ball[i].r) * vx2) / (ball[i].r + ball[j].r); var fvy1 = vy1; var fvy2 = vy2; ball[i].vx = Math.cos(angle) * fvx1 + Math.cos(angle + Math.PI / 2) * fvy1; ball[i].vy = Math.sin(angle) * fvx1 + Math.sin(angle + Math.PI / 2) * fvy1; ball[j].vx = Math.cos(angle) * fvx2 + Math.cos(angle + Math.PI / 2) * fvy2; ball[j].vy = Math.sin(angle) * fvx2 + Math.sin(angle + Math.PI / 2) * fvy2; } } ctx.beginPath() ctx.arc(ball[i].x, ball[i].y, ball[i].r, 0, Math.PI * 2, false) ctx.fillStyle = getRandomColor(); ctx.fill(); ctx.closePath(); } }
My code doesnβt let the balls go, but they are in a constant state of excitement. I was about to implement Hooke's law proposed by @schteppe, but then I heard about Box2d and its magic.
Sukhmeet singh
source share