Detecção de colisão: o que realmente funciona na prática
O assunto aparece todo dia em fóruns de desenvolvimento. Pessoas perguntando qual sistema usar, qual library instalar, e normalmente partem do pressuposto errado. Vamos começar pelo básico sem enrolação.
podemos definir colisões como o momento em que dois objetos ocupam o mesmo espaço simultaneamente
Essa é a definição ingênua. A definição que funciona no mundo real é diferente. Colisão é um problema de interseção geométrica entre volumes, resolvido dentro de uma janela de tempo finita e com precisão controlada. Isso significa que você não está detectando apenas sobreposição estática, mas projetando trajetórias e calculando quando elas se cruzam entre dois frames de simulação. Na minha primeira vez implementando detecção de colisão pra um jogo de tiro 2D, usei AABB puro com chegue por frame. Funcionou até o jogador alcançar velocidade maior que a largura de um sprite por frame. Aí ele simplesmente atravessava paredes. O problema não era o código, era a premissa: teste discret por frame ignora movimento contínuo completamente.
A solução imediata foi mudar para CCD, Continuous Collision Detection. Em vez de verificar se há interseção no estado atual, você calcula o tempo exato de impacto dentro do intervalo do frame. Para esferas contra AABB isso é simples. Para polígonos genéricos, precisa do teorema dos eixos separadores — SAT, Separating Axis Theorem. Se existir pelo menos um eixo onde as projeções dos dois polígonos não se sobrepõem, não há colisão. Achei isso contra-intuitivo no começo porque a intuição diz "verificar interseção direta seria mais fácil", mas na prática o SAT reduz complexidade de O(n²) para O(n) em relação ao número de arestas. Outro detalhe que ninguém explica bem: a ordem dos testes importa demais. Sempre verifique colisão esfera-esfera primeiro, depois AABB-AABB, e só então polígono contra polígono. O motivo é puramente financeiro. Uma operação de distância ao quadrado custa uma fração do que um teste de SAT completo. Em cenas com centenas de objetos, pular essa hierarquia pode triplicar o tempo de física sem aviso prévio.
👉 Clique no botão abaixo para saber mais sobre o assunto!
existe ainda o problema do tunneling em objetos pequenos e rápidos. CCD resolve até certo ponto, mas introduz outro defeito: falsa positiva em cantos. Quando uma esfera rápida passa raspando um vértice, o cálculo de interseção swept pode reportar colisão mesmo quando visualmente o objeto nem pertence à zona de perigo. Minha workaround foi adicionar um margin de slop de 0.001 unidades e rejeitar impactos cuja normal forma ângulo superior a 85 graus com a direção de movimento. Funciona em 99% dos casos. Os 1% restantes geralmente são bugs de level design de qualquer forma. Se você está começando agora, esqueça engine complexa no início. Implemente primeiro colisão círculos-círculos. Depois círculos-retângulos. Só então vá para polígonos convexos com SAT. Polígonos côncavos são outro patamar — precisam de decomposição em convexos, tipicamente com ear clipping ou BSP. GILPP e V-HACD são libraries maduras pra isso, mas cada uma tem tradeoff entre velocidade e qualidade de decomposição. GILPP é mais rápida, V-HACD produz meshes mais limpos. Teste ambas no seu caso específico antes de decidir.
Limitação importante que merece ser dita: nenhum sistema de colisão escala linearmente. O problema geral de detecção de colisão é O(n²). Spatial partitioning — quadtree, octree, BVH, grid uniforme — reduz isso drasticamente na prática, mas cada estrutura tem seu ponto de ruptura. Quadtree quebra quando objetos estão extremamente desbalanceados em densidade. Grid uniforme quebra quando a célula precisa ser menor que o menor objeto do cenário. BVH é o mais flexível, mas requer rebuild periódico. Se seus objetos se movem muito a cada frame, rebuild a cada frame. Se são estáticos ou quase estáticos, rebuild apenas quando necessário. O custo de rebuild mal estimado é a causa número um de stutter em jogos de física. Para quem quer implementar do zero, comece com este fluxo mínimo: broad phase com grid uniforme, narrow phase com SAT pra convexos, resolver com impulse-based response e aplicar correção de posição pós-detecção. Isso cobre a maioria dos casos. Broad phase com sweep and prune também é sólido e mais fácil de entender que BVH pra iniciantes.
Referência técnica direta: o Paper "Real-Time Collision Detection" de Christer Ericson, da Morgan Kaufmann, é a bible do setor. Nada substitui. A segunda edição tem capítulos completos sobre CCD, Broad Phase optimization, e técnicas de GPU accelerated broad phase que valem a leitura mesmo pra quem não trabalha com graphics.