JSFiddle - React, Tailwind, and code Playground
by raxxla
HTML
<canvas id="canvas" width="800" height="600" style='border:1px solid;'></canvas>
JavaScript
var context = document.getElementById('canvas').getContext('2d');
var ball = [], n=150, v=1, fps=60;
var m, dt=1, mfps=fps, ms=1000/fps, sms=ms;
for (var i=0; i<n; i++){
var r = 3+6*Math.random();
ball[i] = {};
ball[i].x = Math.random()*(canvas.width-2*r)+r;
ball[i].y = Math.random()*(canvas.height-2*r)+r;
ball[i].r = r;
ball[i].vx = v*Math.random()*Math.pow(-1, Math.round(Math.random()+1));
ball[i].vy = v*Math.random()*Math.pow(-1, Math.round(Math.random()+1));
ball[i].m = r*r;
}
setInterval(draw, sms);
function draw() {
var date = new Date();
findCollisions();
context.clearRect(0, 0, canvas.width, canvas.height);
context.font = "12px Arial";
for (var i=0; i<ball.length; i++) {
motion(i, dt);
context.beginPath();
context.arc(ball[i].x, ball[i].y, ball[i].r, 0, 2*Math.PI);
context.stroke();
}
dt=1;
var mms = new Date() - date;
sms=ms-mms;
if (sms<0) sms=0;
fps=Math.round(1000/(sms + mms));
if (fps<mfps) mfps=fps;
context.fillText(fps + " fps", 4, 13);
context.fillText(mfps + " min", 4, 26);
}
function findCollisions() {
var t, tc, q, w;
for (var i=0; i<ball.length; i++) {
for (var j=0; j<ball.length; j++) {
if (i != j && (i!=m || j!=n) && (i!=n || j!=m)) {
var a=Math.pow(ball[i].vx-ball[j].vx, 2)+Math.pow(ball[i].vy-ball[j].vy, 2);
var b=2*((ball[i].x-ball[j].x)*(ball[i].vx-ball[j].vx)+(ball[i].y-ball[j].y)*(ball[i].vy-ball[j].vy));
var c=Math.pow(ball[i].x-ball[j].x, 2)+Math.pow(ball[i].y-ball[j].y, 2)-Math.pow(ball[i].r+ball[j].r, 2);
var d=b*b-4*a*c;
if (d>0) {
d=Math.sqrt(d);
var t1=+(-b+d)/2/a;
var t2=+(-b-d)/2/a;
if (t1>t2) t1=t2;
if (t1>0) tc=t1;
}
if (t) {
if (tc<t) t=tc, q=i, w=j;
}
else t=tc, q=i, w=j;
}
}
}
if (t) if (t<dt) {
t=+t.toFixed(10);
n = q, m = w;
for (var i=0; i<ball.length; i++) {
motion(i, t);
}
dt=+(dt-t).toFixed(10);
...