Javascript: Detecção de colisão

Alguém poderia me ajudar a entender como funciona a detecção de colisão no JS? Eu não posso usar jQuery ou gameQuery – já usando protótipo – então, estou procurando algo muito simples. Não pedindo solução completa, apenas me aponte para a direção certa.

Vamos dizer que há:

and

Agora a bola está se movendo (qualquer direção). “Someobject” (0-X) já está pré-definido e há 20-60 deles aleatoriamente posicionados assim:

 #someobject {position: absolute; top: RNDpx; left: RNDpx;} 

Eu posso criar uma matriz com posições “someobject (X)” e testar a colisão enquanto a “bola” está se movendo … Algo como:

 for(var c=0; c<objposArray.length; c++){ ........ and code to check ball's current position vs all objects one by one.... } 

Mas eu acho que isso seria uma solução “noob” e parece muito lento. Existe coisa melhor?

   

A primeira coisa a ter é a function real que irá detectar se você tem uma colisão entre a bola e o object.

Por causa do desempenho, será ótimo implementar alguma técnica crua de detecção de colisão, por exemplo, retângulos delimitantes , e uma mais precisa, se necessário, caso você tenha detectado colisão, para que sua function seja executada um pouco mais rápida, mas usando exatamente mesmo ciclo.

Outra opção que pode ajudar a aumentar o desempenho é fazer um pré-processamento com os objects que você possui. Por exemplo, você pode dividir a área inteira em células como uma tabela genérica e armazenar o object apropriado contido nas células específicas. Portanto, para detectar a colisão, você está detectando as células ocupadas pela bola, obtém os objects dessas células e usa sua function de detecção de colisão.

Para acelerar ainda mais, você pode implementar 2d-tree , quadtree ou R-tree .

Aqui está uma rotina de retângulo de limites muito simples. Espera que b sejam objects com propriedades x , y , width e height :

 function isCollide(a, b) { return !( ((ay + a.height) < (by)) || (ay > (by + b.height)) || ((ax + a.width) < bx) || (ax > (bx + b.width)) ); } 

Para ver esta function em ação, aqui está um codepen graciosamente feito por @MixerOID .

Você pode tentar jquery-colisão . Divulgação completa: eu acabei de escrever isso e divulguei. Não encontrei uma solução, então eu mesmo escrevi.

Permite que você faça:

 var hit_list = $("#ball").collision("#someobject0"); 

que retornará todos os “#obobject0” que se sobrepõem ao “#ball”.

Uma versão sem jQuery, com HTMLElements como inputs

Essa é uma abordagem melhor que verifica a posição real dos elementos conforme eles estão sendo mostrados na viewport, mesmo que sejam absolutos, relativos ou tenham sido manipulados por meio de transformações:

 function isCollide(a, b) { var aRect = a.getBoundingClientRect(); var bRect = b.getBoundingClientRect(); return !( ((aRect.top + aRect.height) < (bRect.top)) || (aRect.top > (bRect.top + bRect.height)) || ((aRect.left + aRect.width) < bRect.left) || (aRect.left > (bRect.left + bRect.width)) ); } 

A resposta de “bcm”, que tem 0 votos no momento, é na verdade uma resposta ótima e subestimada. Ele usa o bom e velho Pitágoras para detectar quando os objects estão mais próximos do que seus círculos delimitadores combinados. Detecção de colisão simples geralmente usa detecção de colisão retangular, o que é bom se seus sprites tendem a ser, bem, retangulares. Se forem circulares (ou de outra forma menos que retangulares), como uma bola, um asteróide ou qualquer outra forma em que os cantos extremos sejam geralmente transparentes, você poderá achar essa rotina eficiente a mais precisa.

Mas para maior clareza, aqui está uma versão mais completa do código:

 function doCollide(x1, y1, w1, x2, y2, w2) { var xd = x1 - x2; var yd = y1 - y2; var wt = w2 + w1; return (xd * xd + yd * yd < = wt * wt); } 

Onde os parâmetros para passar são os valores de x, y e largura de dois objects sprites diferentes

 //Off the cuff, Prototype style. //Note, this is not optimal; there should be some basic partitioning and caching going on. (function () { var elements = []; Element.register = function (element) { for (var i=0; i1) for (var i=0; i=e2.left && e1.left< =(e2.left+e2.width) && (e1.top+e1.height)>=e2.top && e1.top< =(e2.top+e2.height) ) { $(elements[inner]).fire(':collision', {element: $(elements[outer])}); $(elements[outer]).fire(':collision', {element: $(elements[inner])}); } } } }; })(); //Usage: Element.register(myElementA); Element.register(myElementB); $(myElementA).observe(':collision', function (ev) { console.log('Damn, '+ev.memo.element+', that hurt!'); }); //detect collisions every 100ms setInterval(Element.collide, 100); 

Esta é uma solução leve que eu já vi –

 function E() { // check collision S = X - x; D = Y - y; F = w + W; return (S * S + D * D < = F * F) } 

As variables ​​grandes e pequenas são de 2 objects (x coord, y coord e w width)

Daqui

A Mozilla tem um bom artigo sobre isso, com o código mostrado abaixo

https://developer.mozilla.org/pt-BR/docs/Games/Techniques/2D_collision_detection

Colisão retângulo

 if (rect1.x < rect2.x + rect2.width && rect1.x + rect1.width > rect2.x && rect1.y < rect2.y + rect2.height && rect1.height + rect1.y > rect2.y) { // collision detected! } 

Colisão circular

 if (distance < circle1.radius + circle2.radius) { // collision detected! } 

Esta é uma maneira simples que é ineficiente, mas é bastante razoável quando você não precisa de nada muito complexo ou você não tem muitos objects.

Caso contrário, existem muitos algoritmos diferentes, mas a maioria deles é bastante complexa de implementar.

Por exemplo, você pode usar uma abordagem divide et impera na qual você agrupa objects hierarquicamente de acordo com a distância deles e fornece a cada cluster uma checkbox delimitadora que contém todos os itens do cluster.Então você pode verificar quais clusters colidem e evitar a verificação de pares de clusters. object que pertence a clusters que não estão colidindo / sobrepostos.

Caso contrário, você pode descobrir um algoritmo de particionamento de espaço genérico para dividir de maneira semelhante os objects para evitar verificações inúteis. Esses tipos de algoritmos dividem a detecção de colisão em duas fases: uma grosseira na qual você vê quais objects podem estar colidindo e uma boa em que você efetivamente verifica objects únicos. Por exemplo, você pode usar um wikipedia da QuadTree para treinar uma solução fácil.

Dê uma olhada na página da Wikipédia, pode dar-lhe algumas dicas.

hittest.js; detectar duas colisões de imagem png transparente (pixel). Demonstração e link de download

Código HTML;

   

Função de boot;

 var pngObject1Element = document.getElementById( "png-object-1" ); var pngObject2Element = document.getElementById( "png-object-2" ); var object1HitTest = new HitTest( pngObject1Element ); 

Uso básico;

 if( object1HitTest.toObject( pngObject2Element ) ) { //Collision detected }