Colisão Bidirecional
1. Revisão

1.1. Lei dos Senos e Cossenos
Esta regra vale para qualquer triângulo



1.2. Soma de Vetores
Usa-se a regra do paralelogramo e a lei dos cossenos.
Regra do Paralelogramo

- os lados opostos são paralelos e iguais.
- os ângulos opostos são iguais.
- os ângulos adjacentes são suplementares (soma igual a 180º).
- a diagonal é também bissetriz do ângulo interrno respectivo.


1.3. Estudo dos Sinas das Velocidades e Acelerações
1.3.1. Deslocamento Vertical e Horizontal
Pode-se padronizar o sitema de coordenadas e trabalhar com os valores no sistema de coordenadas cartesiano ou senão usar o sistema de coordenadas da tela, o importante é entender o que se está fazendo.
Aceleração significa soma de velocidade, aceleração positiva significa soma de velocidade positiva, aceleração negativa significa soma de velocidade negativa, essa dedução é fácil de interpretar observando a fórmula: v = vo + a.t, vo e a.t tem a mesma grandeza.
Deslocamento horizontal
v = ∆x/∆t
∆x = x - xo
deslocamento para esquerda:
x < xo ⇒ v < 0
se a > 0: |v| diminui, pára e vai para direita
se a < 0: |v|  aumenta e continua para esquerda
deslocamento para direita:
x > xo ⇒ v > 0
se a > 0: v aumenta e continua para direita
se a < 0: v diminui, pára e vai para esquerda
Obs: considera-se para análise do deslocamento o módulo da velocidade, |-80| Km/h > 10 Km/h, quando fala-se que a velocidade diminuiu quer dizer que seu módulo diminuiu, não teria sentido dizer que uma velocidade de -80 Km/h é menor que 10 Km/h só porque se desloca no sentido contrário ao ponto de origem do deslocamento.
Deslocamento vertical
v = ∆y/∆t
∆y = y - yo


deslocamento para cima:
 y < yo ⇒ v < 0
se a > 0: |v| diminui, pára e vai para baixo
se a < 0: |v|  aumenta e continua para cima
deslocamento para baixo:
  y> yo ⇒ v > 0
se a > 0: v aumenta e continua para baixo
se a < 0: v diminui, pára e vai para cima

1.3.2. Movimento Retilíneo Uniformemente Variado

Velocidade Média
É a taxa média de variação do deslocamento em função da variação de tempo.
Δx = x - xo
Δt = t - to
v = Δx/Δt

v = (vo + v)/2

Substituindo v = vo + at na fórmla anterior, tem-se:
v =  vo +  ½ at

Velocidade Instantânea
É o limite da taxa média de variação do deslocamento em função da variação de tempo que tende a zero. Também pode-se expressar a velocidade instantânea como a derivada do deslocamento em função do tempo.
v = limitΔt→0Δx/Δt
v = dx/dt

Aceleração Média
É a taxa média de variação da velocidade em função da variação de tempo.
a = Δv/Δt
Δv = v - vo
Δt = t - to

Aceleração Instantânea
É o limite da taxa média de variação da velocidade em função da variação de tempo que tende a zero. Também pode-se expressar a aceleração instantânea como a derivada da velocidade em função do tempo.
a = limitΔt→0Δv/Δt
a = dv/dt

Aceleração Constante
Quando a aceleração é constante a aceleração média e a aceleração instantânea são iguais.
a = Δv/Δt
to = 0 ⇒ vo
a = (v - vo)/(t-0)
v = vo + at

Deslocamento
Com a fórmula da velocidade média e da aceleração chega-se a fórmula do deslocamento.
v = vo + at      (I)

v = Δx/Δt
Δx = x - xo
Δt = t - to
to = 0 ⇒ xo
x = xo + vt  (II)

v = (vo + v)/2    (III)

v = ½ (vo + v) = ½ (vo + vo + at)  (I)  e  (II)
v = (x - xo)/t = vo + ½ at   
x = xo + vot + ½ at²

Equação de Torricelli
v = vo + at  ⇒ t = (v -vo)/a    (I)
x = xo + vot + ½ at²    (II)
x - xo = vot + ½ at²     (II)
Substituindo o tempo em (II) tem-se:
v² = vo² + 2a(x - xo)

Grandezas Envolvidas
Para facilitar a escolha da fórmula a tabela abaixo relaciona a grandeza faltante, são seis as grandezas: v, vo, x, xo, t, a.
Na na primeira coluna da tabela abaixo estão relacionados as fórmulas para o movimento retilíneo uniformemente variado e na segunda coluna estão as grandezas faltantes.
Relação
Grandeza que Falta
v = vo +at x - xo
x = xo + vot + at²/2 v
 v² = vo² + 2a(x - xo) t (equação de torricelli)
x - xo = vt - ½ at²
vo
x - xo = ½ (vo + v)t
a

1.4. Impulso
É a grandeza física vetorial relacionada com a força aplicada em um corpo durante um intervalo de tempo. O impulso é dado pela expressão:
I = F.Δt
I: impulso (N.s)
F: força (N)
Δt: tempo de atuação da força F (s)
O Impulso é uma grandeza vetorial que possui a mesma direção e sentido da força aplicada.

Nas armas de fogo quanto mais comprido o cano mais os gases produzidos com a explosão da pólvora da munição ficam em contado com o projétil, com isso, maior será o impulso e maior será o alcance do projétil.

Quando a força aplicada não for constante ao longo do tempo, a intensidade do impulso pode ser calculada através da Área do gráfico I(t) = Ft:
I = F.dt

1.5. Quantidade de Movimento
Todos nós sabemos que é muito mais difícil parar um caminhão pesado do que um carro que esteja se movendo com a mesma rapidez.
Isso se deve ao fato do caminhão ter mais inércia em movimento, ou seja, quantidade de movimento.
É a grandeza física vetorial relacionada com a massa de um corpo e sua velocidade. A quantidade de movimento, ou momento linear, é dada pela expressão:
Q = m.V

2. Colisão Elástica em Duas Dimensões

Uma colisão entre dois corpos pode ser classificada considerando-se a energia cinética total antes e depois da colisão. Se a energia cinética se conserva, a colisão é chamada totalmente elástica; se parte da energia cinética se transforma em outra forma de energia, a colisão é inelástica. Quando os dois corpos permanecem unidos após a colisão, esta é dita totalmente inelástica.
Diferença entre Elático e Elasticidade
A elasticidade é uma propriedade dos materiais muito importante para o coeficiente de restituição, não deve ser confundido com o mesmo, a elasticidade é a capacidade do material de se deformar e voltar a forma original. Por exemplo, um cubo de silicone, se jogado ao chão, não haverá restituição de velocidade e mesmo assim tem mais elasticidade que uma bola de ferro que pode dar um salto.

2.1. Colisão Bidirecional

A colisão bidirecional é realizada na direção do eixo-x e na direção do eixo-y, pode-se utilizar tanto bolas como discos para representar a simulação da colisão.
Na colisão entre dois discos tem-se inicialmente o disco 1 com massa igual a m1, raio igual a r1 e velocidade u1 inicial diferente de zero e o disco 2 tem massa igual a m2, raio igual a r2 e velocidade inicial u2 diferente de zero. Despreza-se o atrito.
b: é a distância  entre a reta que passa pelo centro do disco 1 com mesma direção da velocidade u1 e a reta paralela que passa pelo centro do disco 2.
Foi adotado o sistema de eixos cartesianos, eixo-x e eixo-y, pois as fórmulas para encontrar as velocidades finais são as mesmas para o sistema da tela do monitor (eixo-y positivo para baixo).
O ângulo positivo é no sentido anti-horário, é importante saber isso para o cálculo dos ângulos na programação.

Disco 1
Disco 2
m1: massa
u1: velocidade inicial
u1 = v1x + v1y
v1: velocidade final, após o choque
m2: massa
u2: velocidade inicial
u2 = v2x + v2y
v2: velocidade final, após o choque
Tome cuidado com as letras, as componentes de u foram representadas pela letra v pelo fato das coordenadas do eixo-y' de u1 e v1 serem iguais, assim como u2 e v2. Não foram utilizados apóstrofes nas letras que representam as coordenadas dos eixo-x' e eixo-y'.

2.1.1. Interpretação
O objetivo é encontrar o valor de v1 e v2 usando apenas os ângulos θ1 + θ2.
θ2 < 0, o eixo-x' e eixo-y' foram construídos rotacionando o eixo-x e o eixo-y para a direita em θ2 graus, ou seja, o eixo-x e o eixo-y continuam como  referência para o desenho que simula a colisão.
u1 = v1x + v1y
v1y: é a compontente no eixo-y' de v1 e u1.
v2y: é a compontente no eixo-y' de v2 e u2.
Pode-se trabalhar com as propriedades dos eixos-xy e eixos-x'y' ao mesmo tempo, porque tais propriedades são verdadeiras.

Representação Esquemática
O disco1 encontra-se inicialmente se deslocando pela esquerda e o disco2 vindo pela direita, após o choque o disco 1 se deloca na direção emergente (v1) e o disco 2 na direção de v2.
1º) no ponto de contato entre os dois discos na colisão traça-se o eixo-x' que passa pelo centro dos dois discos, o eixo-x' servirá como reta auxiliar.
2º) traça-se a reta t tangente aos dois disco pelo ponto de contato entre as duas, ou seja, é perpendicular ao eixo-x'.
3º) traça-se o eixo-y' paralelo a t passando pelo centro do disco 1.


φ: ângulo de espalhamento, desvio ou saída.
θ1: ângulo de entrada, velocidade u1.
θ: é o ângulo de recuo.
b = (r1 + r2).senθ, é o parâmetro de choque ou colisão.
t // ao eixo-y'
Como não há transferência de massa, ocorre uma transferência de velocidade que inclui: módulo, direção e sentido. O valor do ângulo   θ = θ1 + θ2 , é o ângulos de saída da esferas após a colisão que dependem do parâmetro de choque (b), que é a distância entre os centros de ambos os discos.

Na fase de colisão a força que o disco (1) aplica no disco (2) terá a direção da linha que une os centros das esferas, pois não há atrito, pela 3ª lei de Newton, a força que o disco (2) aplicará sobre o disco (1) também terá essa direção).
Após a colisão as esferas se movem com velocidades v1  e v2 que fazem ângulos φ e θ com a direção original do disco de massa m1 .

Se b = 0, a colisão é unidimensional, ou seja, ocorre frontalmente e o ângulo de desvio será φ =180º e θ = 0º.
Se b for maior que a soma dos raios dos discos, então não ocorrerá colisão.
Se b = 0 ou b < r1 + r2, haverá uma colisão bidimensional.
Se m1 = m2, então φ + θ  = 90º

Pelo Teorema de Pitágoras
dx² + dy² = (r1 + r2)²

2.1.2. Quantidade de Movimento
O momento linear é constante, a soma do momento linear inicial é igual a soma do momento linear final.
Qantes = Qapós

Particularmente se u2 = 0 e m1 = m2, semelhante a bola de bilhar, então:
Q12  = Q1f2 + Q2f2
E pela Lei dos cossenos:
Q12 = Q1f2 + Q2f2 + 2.Q1f .Q2f.cosθ
Repare que u1 = v1 - v2

Usando a conservação da energia cinética total do choque de duas bolas de bilhar, tem-se:
½ m1u1² = ½ m1v1² + ½ m2v2²

2.1.3. Cálculo das Variáveis Faltantes
Dados os parâmetros m1 , m2 , u1 e θ1 tem-se três equações para calcular os valores das incógnitas v1 , v2 e θ .

Escrevendo essa equação vetorial na direção do eixo-x', temos :
(1)

Escrevendo essa equação vetorial na direção do eixo-y', temos :
          (2)

Cálculo do coeficiente de restituição:
É calculado com base no eixo-x'.
e = velocidade afastamento/velocidade aproximação
        (3)

Para resolver o problema de colisão em duas dimensões, precisamos encontrar os ângulos e , bem como as velocidades v1 e v2. Para tanto, vamos trabalhar com as equações (1), (2) e (3) acima:

Da equação (3), temos :

Multiplicando ambos os lados por m2, temos :

          (4)

Da equação (1), temos :

         (5)

Substituindo a equação (5) na equação (4), temos :

     (6)

Da equação (2), temos :

Dividindo a equação (2) pela equação (6), temos :

   (7)

A equação (7) estabelece a relação entre os ângulos e .

Vamos agora calcular o módulo da velocidade v2.

Da equação (1), temos :

Da equação (3), temos :

Substituindo essa expressão na equação (1), temos :

  (8)

A equação (8), permite calcular a velocidade v2 em função dos dados do problema.

Da equação (2), temos :

  (9)

A equação (9), permite calcular a velocidade v1 em função dos dados do problema.

Conclusão
Colisão é uma troca de energia realizada durante uma interação de duas ou mais partículas e que envolve forças internas de curta duração denominadas forças de colisão.
Numa colisão só há a ação de forças internas e por natureza, forças internas mantêm a quantidade de movimento linear constante. Somente forças externas são capazes de alterar tal grandeza. Como a quantidade de movimento linear é uma grandeza vetorial, o fato dela se manter constante implica que todas as suas componentes vetoriais também se mantenham.
Sabemos também que todo movimento bidimensional pode ser decomposto em dois movimentos lineares simultâneos.
Concluímos enfim, que uma colisão bidimensional, assim como outros fenômenos na qual podemos fazer a decomposição de um vetor em componentes ortogonais, se comporta como se fossem duas colisões unidimensionais simultâneas, com a conservação da quantidade de movimento linear e da energia cinética quando tal colisão for perfeitamente elástica.

Exemplo
Vamos considerar uma colisão oblíqua, perfeitamente elástica entre duas partículas de massas iguais, estando uma delas inicialmente parada.
Veja na demonstração que, após a colisão, as partículas se movem em direções perpendiculares (θ = 90°).

I) Através da conservação da quantidade de movimento, no momento da colisão, temos:



II) Através da conservação da energia mecânica, no momento da colisão, temos:


Fazendo a comparação entre (I) e (II), temos:
2V'A  V'B cos θ = 0

Visto que VA VB são diferentes de zero, temos:
cos θ = 0 e θ=90°

Portanto o ângulo- APENAS NO CASO EM QUE AS MASSAS SÃO IGUAIS – entre as velocidades finais numa colisão elástica em que o alvo está em repouso é 90º.

2.1 Código JavaScript
Código 1
Este código não tem nada de diferente, possue apenas o script que definem o contexto do canvas dentro da função start() que será executada com a inicialização do próprio código (onLoad)

<html>
<head>
<title>Bouncing Balls</title>
<script>
var cvs1;
var cvs;

function start() {
cvs1 = document.getElementById("cvs");
cvs = cvs1.getContext("2d");
}
</script>
</head>
<body onLoad="start();">
<canvas id="cvs" width=500 height=300> </canvas>
</body>
</html>

Código 2
Este código trabalha com deslocamento em função do tempo e velocidade.
- balls: é um array com elementos do tipo objeto com propriedades x e y que definem a posição no eixo-x e eixo-y, r define o raio, m a massa, vx a velocidade na direção do eixo-x e vy a velocidade na direção do eixo-y.
- setInterval(draw, 10) esta função executa a função draw a cada 10 milissegundos.
Função draw(): cria os arcos a cada execução
a: é o indice do array balls
cvs.arc(balls[a].x, balls[a].y, balls[a].r, 0, Math.PI*2, true), é o elemento arc do contexto cvs, possui os parâmetros:
coordenada eixo-x: balls[a].x
coordenada eixo-y: balls[a].y
raio: r
início arco: 0 em radianos
fim do arco: Math.PI*2 em radianos
anti-horário: true

Posições em Função da Velocidade
A função setInterval() será executada a cada 10 milissegundos, com isso, as coordenadas (x,y) serão acrescidas do valor de sua respectiva velocidade. A direção será invertida quando a bola sair das dimensões do canvas. A aceleração é constante.
- Direção:
if (balls[a].x <= balls[a].r) balls[a].vx *= -1;
se coordenada-x <= raio velocidade-x*= -1, ou seja, quando a bola encostar na borda da esquerda, a velocidade na direção x é invetida.
if (balls[a].y <= balls[a].r) balls[a].vy *= -1; // bounce ball off of top boundary
se coordenada-y <= raio velocidade-y*= -1, ou seja, quando a bola encostar na borda superior, a velocidade na direção y é invetida.
if (balls[a].x >= cvs1.width - balls[a].r) balls[a].vx *= -1; // bounce ball off of right boundary
se coordenada-x >= larguraCanvas - raio vx *= -1, ou seja, quando a coordenada-x for maior ou igual a diferença entra a lagura do canvas e o raio, a velocidade-x é invertida.
if (balls[a].y >= cvs1.height - balls[a].r) balls[a].vy *= -1;
se coordenada-y >= alturaCanvas - raio vy *= -1, ou seja, quando a coordenada-y for maior ou igual a diferença entra a altura do canvas e o raio, a velocidade-y é invertida.
- Valor:
x = xo + vx.t
xo = 0
A função setInterval(draw, 10) será executada a cada 10 milissegundos, com isso, a variável tempo não entra na fórmula do deslocamento.
x = x + vx
Para vx = 1 significa que a cada 10 milissegundos (0,01 segundos) x é aumentado em 1.
Para vy = 1,5 significa que a cada 10 milissegundos (0,01 segundos) y é aumentado em 1,5.

Mesmo raciocínio para o deslocamento vertical.
y = yo + vy.t
yo = 0
y = y + vy
Que em programação fica:
balls[a].x += balls[a].vx;
balls[a].y += balls[a].vy;

<html>
<head>
<title>Bouncing Balls</title>
<script>
var cvs1;
var cvs;
var balls = [
{x:50, y:50, r:20, m:1, vx:1, vy:1.5},
{x:200, y:150, r:30, m:2, vx:-1, vy:0.3},
{x:450, y:250, r:15, m:0.75, vx:-0.5, vy:3}
];

function start() {
cvs1 = document.getElementById("cvs");
cvs = cvs1.getContext("2d");
setInterval(draw, 10); // this will run 100 times per second, every 10 milliseconds
}

function draw() {
cvs.clearRect(0, 0, cvs1.width, cvs1.height);
for (var a = 0; a < balls.length; a ++) {
cvs.beginPath();
cvs.arc(balls[a].x, balls[a].y, balls[a].r, 0, Math.PI*2, true);
cvs.fill();
cvs.closePath();
if (balls[a].x <= balls[a].r) balls[a].vx *= -1; // bounce ball off of left boundary
if (balls[a].y <= balls[a].r) balls[a].vy *= -1; // bounce ball off of top boundary
if (balls[a].x >= cvs1.width - balls[a].r) balls[a].vx *= -1; // bounce ball off of right boundary
if (balls[a].y >= cvs1.height - balls[a].r) balls[a].vy *= -1; // bounce ball off of bottom boundary 
balls[a].x += balls[a].vx;
balls[a].y += balls[a].vy;
}
}
</script>
</head>
<body onLoad="start();">
<canvas id="cvs" width=500 height=300> </canvas>
</body>
</html>
Link para o código acima

Código 3
Será demostrado nas duas figuras abaixo o posicionamento de duas bolas quando as mesmas se colidem. A bola A tem raio ra e centro no ponto (ax,ay). A bola B tem raio rb e centro no ponto (bx,by).

A distância entre os centros das bolas A e B quando as mesmas se colidem forma um triângulo retângulo conforme figura abaixo.

dist² = (ax - bx)² + (ay - by)²
dist = ra + rb

Determinação do Choque entre duas Bola:

for (var a = 0; a < balls.length; a ++) {
for (var b = 0; b < balls.length; b ++) {
if (a != b) {
Se indice a ≠ b
var distToBalls = Math.sqrt(Math.pow(balls[a].x - balls[b].x, 2) + Math.pow(balls[a].y - balls[b].y, 2));
dist = (ax - bx)² + (ay - by)²
if (distToBalls <= balls[a].r + balls[b].r) {
se dist <= ra + rb
var newVel = getBallCollision(balls[a], balls[b]); // sends colliding balls to function to calculate new velocities

O código abaixo difere do anterior pela implementação da detecção do choque
<html>
<head>
<title>Bouncing Balls</title>
<script>
var cvs1;
var cvs;
var balls = [
{x:50, y:50, r:20, m:1, vx:1, vy:1.5},
{x:200, y:150, r:30, m:2, vx:-1, vy:0.3},
{x:450, y:250, r:15, m:0.75, vx:-0.5, vy:3}
];

function start() {
cvs1 = document.getElementById("cvs");
cvs = cvs1.getContext("2d");
cvs.strokeStyle = "red";
cvs.lineWidth = 3;
setInterval(draw, 10); // this will run 100 times per second, every 10 milliseconds
}

function draw() {
    cvs.clearRect(0, 0, cvs1.width, cvs1.height);
    for (var a = 0; a < balls.length; a ++) {
         for (var b = 0; b < balls.length; b ++) {
               if (a != b) { // make sure both balls being tested are not the same
               var distToBalls = Math.sqrt(Math.pow(balls[a].x - balls[b].x, 2) + Math.pow(balls[a].y - balls[b].y, 2));
                      if (distToBalls <= balls[a].r + balls[b].r) {
                      var newVel = getBallCollision(balls[a], balls[b]); // sends colliding balls to function to calculate new velocities
                      }
               }
         }
    }
    for (var a = 0; a < balls.length; a ++) {
    cvs.beginPath();
    cvs.arc(balls[a].x, balls[a].y, balls[a].r, 0, Math.PI*2, true);
    cvs.fill();
    cvs.closePath();
    if (balls[a].x <= balls[a].r) balls[a].vx *= -1; // bounce ball off of left boundary
    if (balls[a].y <= balls[a].r) balls[a].vy *= -1; // bounce ball off of top boundary
    if (balls[a].x >= cvs1.width - balls[a].r) balls[a].vx *= -1; // bounce ball off of right boundary
    if (balls[a].y >= cvs1.height - balls[a].r) balls[a].vy *= -1; // bounce ball off of bottom boundary
    balls[a].x += balls[a].vx;
    balls[a].y += balls[a].vy;
   }
}
function getBallCollision(b1, b2) {
// we arn't going to calculate the new velocities just yet, this is just to show you that the test correctly detects collisions 
cvs.beginPath();
cvs.arc(b1.x, b1.y, b1.r, 0, Math.PI*2, true);
cvs.arc(b2.x, b2.y, b2.r, 0, Math.PI*2, true);
cvs.stroke();
cvs.closePath();
}
</script>
</head>
<body onLoad="start();">
<canvas id="cvs" width=500 height=300> </canvas>
</body>
</html>

Link para o código acima

Código 4
Implementa a colisão propriamente dita. Repare no no esquema da figura anterior tem-se:
dir1 = θ1
colAng = θ2. Lembre-se que θ2 < 0.
sp1 = u1
dir1 - colAng = θ
vx1 = v1x e vy1 = v1y
Etc...

var vx1 = sp1 * Math.cos(dir1 - colAng);
var vy1 = sp1 * Math.sin(dir1 - colAng);
var vx2 = sp2 * Math.cos(dir2 - colAng);
var vy2 = sp2 * Math.sin(dir2 - colAng);
var fvx1 = ((b1.m - b2.m) * vx1 + (2 * b2.m) * vx2) / (b1.m + b2.m);
var fvx2 = ((2 * b1.m) * vx1 + (b2.m - b1.m) * vx2) / (b1.m + b2.m);
var fvy1 = vy1;
var fvy2 = vy2;

Resultante no eixo-x para o disco 1
b1.vx = Math.cos(colAng) * fvx1 + Math.cos(colAng + Math.PI/2) * fvy1;
Resultante no eixo-y para o disco 1
b1.vy = Math.sin(colAng) * fvx1 + Math.sin(colAng + Math.PI/2) * fvy1;
Resultante no eixo-x para o disco 2
b2.vx = Math.cos(colAng) * fvx2 + Math.cos(colAng + Math.PI/2) * fvy2;
Resultante no eixo-y para o disco 2
b2.vy = Math.sin(colAng) * fvx2 + Math.sin(colAng + Math.PI/2) * fvy2;

<html>
<head>
<title>Bouncing Balls</title>
<script>
var cvs1;
var cvs;
var balls = [
{x:50, y:50, r:20, m:1, vx:1, vy:1.5},
{x:200, y:150, r:30, m:2, vx:-1, vy:0.3},
{x:450, y:250, r:15, m:0.75, vx:-0.5, vy:3}
];

function start() {
cvs1 = document.getElementById("cvs");
cvs = cvs1.getContext("2d");
cvs.strokeStyle = "red";
cvs.lineWidth = 3;
setInterval(draw, 10); // this will run 100 times per second, every 10 milliseconds
}

function draw() {
cvs.clearRect(0, 0, cvs1.width, cvs1.height);
for (var a = 0; a < balls.length; a ++) {
for (var b = 0; b < balls.length; b ++) {
if (a != b) { // make sure both balls being tested are not the same
var distToBalls = Math.sqrt(Math.pow(balls[a].x - balls[b].x, 2) + Math.pow(balls[a].y - balls[b].y, 2));
if (distToBalls <= balls[a].r + balls[b].r) {
var newVel = getBallCollision(balls[a], balls[b]); // sends colliding balls to function to calculate new velocities 
balls[a].vx = newVel.ball1.vx;
balls[a].vy = newVel.ball1.vy;
balls[b].vx = newVel.ball2.vx;
balls[b].vy = newVel.ball2.vy;
balls[a].x += balls[a].vx;
balls[a].y += balls[a].vy;
balls[b].x += balls[b].vx;
balls[b].y += balls[b].vy;
}
}
}
}
for (var a = 0; a < balls.length; a ++) {
cvs.beginPath();
cvs.arc(balls[a].x, balls[a].y, balls[a].r, 0, Math.PI*2, true);
cvs.fill();
cvs.closePath();
if (balls[a].x <= balls[a].r) balls[a].vx *= -1; // bounce ball off of left boundary
if (balls[a].y <= balls[a].r) balls[a].vy *= -1; // bounce ball off of top boundary
if (balls[a].x >= cvs1.width - balls[a].r) balls[a].vx *= -1; // bounce ball off of right boundary
if (balls[a].y >= cvs1.height - balls[a].r) balls[a].vy *= -1; // bounce ball off of bottom boundary
balls[a].x += balls[a].vx;
balls[a].y += balls[a].vy;
}
}
function getBallCollision(b1, b2) {
// let's get started!
var dx = b1.x - b2.x;
var dy = b1.y - b2.y;
var dist = Math.sqrt(dx*dx + dy*dy);
if (Math.abs(dy) + Math.abs(dx) != 0 && dist <= b1.r + b2.r) {
var colAng = Math.atan2(dy, dx);
var sp1 = Math.sqrt(b1.vx*b1.vx + b1.vy*b1.vy);
var sp2 = Math.sqrt(b2.vx*b2.vx + b2.vy*b2.vy);
var dir1 = Math.atan2(b1.vy, b1.vx);
var dir2 = Math.atan2(b2.vy, b2.vx);
var vx1 = sp1 * Math.cos(dir1 - colAng);
var vy1 = sp1 * Math.sin(dir1 - colAng);
var vx2 = sp2 * Math.cos(dir2 - colAng);
var vy2 = sp2 * Math.sin(dir2 - colAng);
var fvx1 = ((b1.m - b2.m) * vx1 + (2 * b2.m) * vx2) / (b1.m + b2.m);
var fvx2 = ((2 * b1.m) * vx1 + (b2.m - b1.m) * vx2) / (b1.m + b2.m);
var fvy1 = vy1;
var fvy2 = vy2;
b1.vx = Math.cos(colAng) * fvx1 + Math.cos(colAng + Math.PI/2) * fvy1;
b1.vy = Math.sin(colAng) * fvx1 + Math.sin(colAng + Math.PI/2) * fvy1;
b2.vx = Math.cos(colAng) * fvx2 + Math.cos(colAng + Math.PI/2) * fvy2;
b2.vy = Math.sin(colAng) * fvx2 + Math.sin(colAng + Math.PI/2) * fvy2;
return { ball1:b1, ball2:b2 }; // return the balls with new velocities
}
else return false;
}
</script>
</head>
<body onLoad="start();">
<canvas id="cvs" width=500 height=300> </canvas>
</body>
</html>

Link para o código acima

Now the explanation:
var dx = b1.x - b2.x;
var dy = b1.y - b2.y;
var dist = Math.sqrt(dx*dx + dy*dy);
The first 3 lines make use of the Pythagorean Theorem a2 + b2 = c2 to find the distance between the balls.

if (Math.abs(dy) + Math.abs(dx) != 0 && dist <= b1.r + b2.r) {
This if statement is a check to make sure that the balls are not the same and a collision is taking place because the sum of the radii is either equal to or less than the distance between the balls.

var colAng = Math.atan2(dy, dx);
By using the atan2() function, we can get the angle between the center points of the balls.

var sp1 = Math.sqrt(b1.vx*b1.vx + b1.vy*b1.vy);
var sp2 = Math.sqrt(b2.vx*b2.vx + b2.vy*b2.vy);
These lines of code use Pythagorean Theorem to determine the overall magnitude of each ball's velocity.

var dir1 = Math.atan2(b1.vy, b1.vx);
var dir2 = Math.atan2(b2.vy, b2.vx);
Find the original direction each ball is moving.

var vx1 = sp1 * Math.cos(dir1 - colAng);
var vy1 = sp1 * Math.sin(dir1 - colAng);
var vx2 = sp2 * Math.cos(dir2 - colAng);
var vy2 = sp2 * Math.sin(dir2 - colAng);
Find the new speeds of the balls without taking masses into account. This calculation rotates the x and y speeds so that they are in relation to a line through the ball radii.

var fvx1 = ((b1.m - b2.m) * vx1 + (2 * b2.m) * vx2) / (b1.m + b2.m);
var fvx2 = ((2 * b1.m) * vx1 + (b2.m - b1.m) * vx2) / (b1.m + b2.m);
var fvy1 = vy1;
var fvy2 = vy2;

Calculate the final velocities of the balls when mass is taken into account.

b1.vx = Math.cos(colAng) * fvx1 + Math.cos(colAng + Math.PI/2) * fvy1;
b1.vy = Math.sin(colAng) * fvx1 + Math.sin(colAng + Math.PI/2) * fvy1;
b2.vx = Math.cos(colAng) * fvx2 + Math.cos(colAng + Math.PI/2) * fvy2;
b2.vy = Math.sin(colAng) * fvx2 + Math.sin(colAng + Math.PI/2) * fvy2;
Rotates the speeds back so they are in relation to the regular axises.