Ultimamente eu tenho trabalhado num joguinho de tiro top down em rede, em que os personagens são nada mais nada menos que círculos. Como não tenho muito tempo livre, e o pouco tempo que tenho divido entre vários projetos malucos diferentes (quem sabe um dia falo deles aqui), este provavelmente vai demorar muito tempo pra ficar pronto.

A moral da história é que pra implementar a parte do tiro no jogo (lembrando que a bala é uma bola, assim como o jogador), precisei descobrir como detectar a colisão entre dois círculos. Depois de quebrar a cabeça por algum tempo, resolvi dar uma pesquisada na internet e fiquei impressionado com a simplicidade da solução.
Vejamos o exemplos abaixo:

Aqui temos dois círculos num plano bidimensional. Lembrando que a coordenada y costuma “subir pra baixo” em sistemas de coordenadas de engines de jogos, canvas, etc. Ou seja, quanto maior o valor y, mais para baixo na tela o elemento fica posicionado, o que é o oposto do que acontece no plano cartesiano que utilizamos para desenhar gráficos de funções.
O centro do círculo 1 está na posição (3,3) do plano, e seu raio é igual a 2. O centro do círculo 2 está na posição (6,5) e seu raio é igual 3. Mesmo nessa imagem torta é possível perceber que elas estão colidindo (leia-se, se sobrepondo), agora precisamos fazer com que o computador saiba disso também.
Calculando as distâncias vertical e horizontal
O primeiro passo para detectar esse tipo de colisão é calcular a distância entre os centros dos dois círculos. Para isso, primeiro precisamos calcular a distância horizontal (dh) e vertical (dv) entre os centros deles. Isso é muito simples:
dh = x2-x1
dv = y2-y1
A distância horizontal é a diferença entre a coordenada x dos centros de cada círculo. Já a distância vertical é a diferença entre a coordenada y dos mesmos. No nosso caso, dh = 6 -3 = 3, e dv = 5-3 = 2.
Talvez você tenha percebido que é possível que dh ou dv sejam números negativos, dependendo da posição dos círculos, e não faz muito sentido falar em distâncias negativas, então o mais apropriado seria calcular o módulo (o valor absoluto) da subtração de uma coordenada pela outra. Mas para os nossos objetivos, isso não é necessário, e você verá o motivo daqui há pouco.

Perceba que fazendo um tracejado com o valor das distâncias vertical e horizontal a partir dos centros dos círculos obtemos um ângulo reto. Para que os centros dos dois círculos se toquem, basta que uma delas se mova 3 pontos para um lado e 2 pontos para cima ou para baixo (dependendo de qual seja a esfera que se move).
Calculando a distância euclidiana entre os dois pontos
Para calcular a distância propriamente dita, isto é, a distância euclidiana no plano bidimensional entre esses dois pontos, precisamos descobrir o valor da diagonal formada pelos lados que formam esse ângulo.

Se depois de ver a imagem, seu coração bateu mais forte e você quase pulou da cadeira gritando “PITÁGORAS!”, você acertou! A distância (d) entre o centro dos dois círculos corresponde à hipotenusa (h) do triângulo retângulo formado ligando os centros dos círculos ao seu “ponto de encontro”. As distâncias vertical e horizontal são então os catetos desse triângulo. E sabemos que h2=a2+b2(o quadrado da hipotenusa é igual à soma dos quadrados dos catetos). Então, para calcular a distância, d2 = dv2+dh2. Em nosso caso,
d2 = 22+32
= 4 + 9
= 13
Logo:
d = √13 ≈ 3,6.
Como as distâncias vertical e horizontal são elevadas ao quadrado, o sinal delas não importa, pois o resultado será sempre positivo.
Finalmente calculando a colisão entre dois círculos
Agora que temos a distância do centro de um círculo à outro, para sabermos se eles estão se tocando ou se sobrepondo, precisamos apenas somar o valor dos raios dos dois círculos. Se esse valor for maior que a distância entre os centros, então eles estão se sobrepondo, se os dois valores forem iguais, então os círculos estão apenas se tocando, e se o valor for menor, então eles não estão colidindo.
No nosso caso, como já imaginávamos, os dois círculos estão se sobrepondo, porque R1+R2 = 5 e d = 3,6.
Para finalizar, trago um exemplo em Python de como podemos implementar um algoritmo de detecção de colisão entre círculos. Supondo a existência de uma classe do tipo Circulo, com atributos x, y e rad (raio):
import math def check_collision(circulo1, circulo2): dist_x = circulo1.x - circulo2.x dist_y = circulo1.y - circulo2.y distance = math.sqrt((dist_x * dist_x) + (dist_y * dist_y)) if distance <= circulo.rad + circulo.rad: #tem uma colisão! return True return False
Espero que tenha gostado do texto, até a próxima!