Simulates the collision of 700 balls with conservation of momentum. The ball's mass is relative to its radius.
g=window,u=Math,v=u.sqrt,h=u.random,f=document.getElementById("c"),i=f.getContext("2d"),j=g.innerWidth,k=g.innerHeight,w=[],C=(new Date).getTime();f.width=j;f.height=k;i.fillStyle="rgb(122,0,25)";for(n=0;n<700;n++){f=-0.075+2*h()*0.075;g=v(0.005625-f*f);w[n]={a:1+h()*10,d:h()*j,e:h()*k,b:f,c:-g+2*h()*g}}window.setInterval(function(){x=(new Date).getTime()-C;C+=x;i.clearRect(0,0,j,k);for(n=0;n<700;n++){y=x;a=w[n];a.d+=a.b*y;a.e+=a.c*y;if(a.d<a.a||a.d>j-a.a){a.b=-a.b;a.d=a.d<a.a?a.a:j-a.a}if(a.e<a.a||a.e>k-a.a){a.c=-a.c;a.e=a.e<a.a?a.a:k-a.a}for(m=n+1;m<700;m++){b=w[m];D=a.a+b.a;p=b.d-a.d;q=b.e-a.e;E=p*p+q*q;r=v(E);if(r<D){c=p/r;d=q/r;l=a.b*c+a.c*d;z=a.c*c-a.b*d;s=b.b*c+b.c*d;A=b.c*c-b.b*d;e=b.a/a.a;o=(l+e*s)/(1+e);t=o-v(o*o-((1-e)*l+2*e*s)*l/(1+e));B=l/e+s-t/e;a.b=t*c-z*d;a.c=z*c+t*d;b.b=B*c-A*d;b.c=A*c+B*d}}i.beginPath();i.arc(a.d,a.e,a.a,0,2*u.PI,true);i.fill()}},33)
Zz13aW5kb3csdT1NYXRoLHY9dS5zcXJ0LGg9dS5yYW5kb20sZj1kb2N1bWVudC5nZXRFbGVtZW50QnlJZCgiYyIpLGk9Zi5nZXRDb250ZXh0KCIyZCIpLGo9Zy5pbm5lcldpZHRoLGs9Zy5pbm5lckhlaWdodCx3PVtdLEM9KG5ldyBEYXRlKS5nZXRUaW1lKCk7Zi53aWR0aD1qO2YuaGVpZ2h0PWs7aS5maWxsU3R5bGU9InJnYigxMjIsMCwyNSkiO2ZvcihuPTA7bjw3MDA7bisrKXtmPS0wLjA3NSsyKmgoKSowLjA3NTtnPXYoMC4wMDU2MjUtZipmKTt3W25dPXthOjEraCgpKjEwLGQ6aCgpKmosZTpoKCkqayxiOmYsYzotZysyKmgoKSpnfX13aW5kb3cuc2V0SW50ZXJ2YWwoZnVuY3Rpb24oKXt4PShuZXcgRGF0ZSkuZ2V0VGltZSgpLUM7Qys9eDtpLmNsZWFyUmVjdCgwLDAsaixrKTtmb3Iobj0wO248NzAwO24rKyl7eT14O2E9d1tuXTthLmQrPWEuYip5O2EuZSs9YS5jKnk7aWYoYS5kPGEuYXx8YS5kPmotYS5hKXthLmI9LWEuYjthLmQ9YS5kPGEuYT9hLmE6ai1hLmF9aWYoYS5lPGEuYXx8YS5lPmstYS5hKXthLmM9LWEuYzthLmU9YS5lPGEuYT9hLmE6ay1hLmF9Zm9yKG09bisxO208NzAwO20rKyl7Yj13W21dO0Q9YS5hK2IuYTtwPWIuZC1hLmQ7cT1iLmUtYS5lO0U9cCpwK3EqcTtyPXYoRSk7aWYocjxEKXtjPXAvcjtkPXEvcjtsPWEuYipjK2EuYypkO3o9YS5jKmMtYS5iKmQ7cz1iLmIqYytiLmMqZDtBPWIuYypjLWIuYipkO2U9Yi5hL2EuYTtvPShsK2UqcykvKDErZSk7dD1vLXYobypvLSgoMS1lKSpsKzIqZSpzKSpsLygxK2UpKTtCPWwvZStzLXQvZTthLmI9dCpjLXoqZDthLmM9eipjK3QqZDtiLmI9QipjLUEqZDtiLmM9QSpjK0IqZH19aS5iZWdpblBhdGgoKTtpLmFyYyhhLmQsYS5lLGEuYSwwLDIqdS5QSSx0cnVlKTtpLmZpbGwoKX19LDMzKQ==
(function() { // Removed after compression
var win = window,
math = Math, // My shortcut globals:
s = math.sqrt,
r = math.random,
c = document.getElementById("c"),
cx = c.getContext("2d"),
w = win.innerWidth,
h = win.innerHeight,
MAX_PARTICLES = 700, // Application globals
MAX_VELOCITY = 75/1000, //(px/ms)
states = [],
time = new Date().getTime(),
vv,vx,dt,tt,V,p1, // For compressor tool
p2,R,dx,dy,dd,d,dvx,dvy,dvdv,cos1,
sin1,dv_para,t,cos2,sin2,
v1x_,v1y_,v2x_,v2y_,v1x,v1y,v2x,v2y,
mr,v1x_prime,v2x_prime;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Initialization: //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
c.width = w;
c.height = h;
cx.fillStyle = "rgb(122,0,25)";
for(n=0; n<MAX_PARTICLES; n++) {
vx = -MAX_VELOCITY + 2*r()*MAX_VELOCITY;
vv = s(MAX_VELOCITY*MAX_VELOCITY - vx*vx);
states[n] = {
r: 1+r()*10,
px: r()*w,
py: r()*h,
vx: vx,
vy: -vv+2*r()*vv
};
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// The main loop: //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
window.setInterval(function() {
dt = new Date().getTime() - time;
time += dt; // Ha-ha! #Desperation [time + dt = time + new time - time = new time]
cx.clearRect(0, 0, w, h);
for(n=0; n<MAX_PARTICLES; n++) {
tt = dt;
p1 = states[n];
p1.px += p1.vx*tt;
p1.py += p1.vy*tt;
// Check boundaries first
if(p1.px<p1.r||p1.px>w-p1.r){p1.vx=-p1.vx;p1.px=p1.px<p1.r?p1.r:w-p1.r;}
if(p1.py<p1.r||p1.py>h-p1.r){p1.vy=-p1.vy;p1.py=p1.py<p1.r?p1.r:h-p1.r;}
// Could it hit another particle?
for(m=n+1; m<MAX_PARTICLES; m++) {
p2 = states[m];
R = p1.r+p2.r;
dx = p2.px-p1.px;
dy = p2.py-p1.py;
dd = dx*dx+dy*dy;
d = s(dd);
// Removed a lot of unnecessary checks here to make this smaller but less accurate.
if(d<R) {
dvx = p2.vx-p1.vx;
dvy = p2.vy-p1.vy;
dvdv = dvx*dvx+dvy*dvy;
cos1 = dx/d;
sin1 = dy/d;
dv_para = dvx*cos1+dvy*sin1;
v1x = p1.vx*cos1+p1.vy*sin1;
v1y = p1.vy*cos1-p1.vx*sin1;
v2x = p2.vx*cos1+p2.vy*sin1;
v2y = p2.vy*cos1-p2.vx*sin1;
mr = p2.r/p1.r;
V = (v1x+mr*v2x)/(1+mr);
v1x_prime = V-s(V*V-((1-mr)*v1x+2*mr*v2x)*v1x/(1+mr));
v2x_prime = v1x/mr+v2x-v1x_prime/mr;
p1.vx = v1x_prime*cos1-v1y*sin1;
p1.vy = v1y*cos1+v1x_prime*sin1;
p2.vx = v2x_prime*cos1-v2y*sin1;
p2.vy = v2y*cos1+v2x_prime*sin1;
}
}
// New all time low: draw inside collision method! >ugh<
cx.beginPath();
cx.arc(p1.px, p1.py, p1.r, 0, 2*math.PI, true);
cx.fill();
}
}, 33);
})();