Javascript: détection de Collision

quelqu'un pourrait-il m'aider à comprendre comment la détection de collision fonctionne en JS? Je ne peux pas utiliser jQuery ou gameQuery - j'utilise déjà un prototype - donc, je cherche quelque chose de très simple. Ne demande pas une solution complète, juste m'indiquer la bonne direction.

disons qu'il y a:

<div id="ball"></div>
and 
<div id="someobject0"></div>

maintenant la balle se déplace (dans n'importe quelle direction). "Someobject" (0-X) est déjà prédéfini et il y en a 20-60 positionnés au hasard comme ceci:

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

je peut créer un tableau avec les positions "someobject(X)" et tester la collision pendant que la "boule" se déplace... Quelque chose comme:

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

mais je suppose que ce serait une solution "noob" et ça a l'air plutôt lent. Est-il rien de mieux?

38
demandé sur Jack 2010-03-14 01:57:39

10 réponses

La première chose à avoir est la fonction qui permet de détecter si vous avez une collision entre la balle et l'objet.

pour des raisons de performance, ce sera génial de mettre en œuvre une technique rudimentaire de détection de collision, par exemple, bordant les rectangles, et un plus précis si nécessaire dans le cas où vous avez une collision détectée, de sorte que votre fonction fonctionnera un peu plus rapidement mais en utilisant exactement la même boucle.

une autre option qui peut aider pour augmenter les performances effectuer un pré-traitement avec les objets que vous avez. Par exemple, vous pouvez diviser la zone entière en cellules comme une table générique et stocker l'objet approprié qui sont contenus dans les cellules particulières. Par conséquent, pour détecter la collision, vous détectez les cellules occupées par la balle, récupérez les objets de ces cellules et utilisez votre fonction de détection de collision.

Pour l'accélérer encore plus, vous pouvez appliquer 2d-arbre, quadtree ou R-tree.

28
répondu Li0liQ 2016-09-25 04:40:01

Voici une routine rectangulaire très simple. Il prévoit à la fois a et b objets x,y,width et height propriétés:

function isCollide(a, b) {
    return !(
        ((a.y + a.height) < (b.y)) ||
        (a.y > (b.y + b.height)) ||
        ((a.x + a.width) < b.x) ||
        (a.x > (b.x + b.width))
    );
}

Pour voir cette fonction dans l'action, voici un codepen gracieusement fabriqué par @MixerOID.

52
répondu Husky 2017-05-23 12:34:47

Vous pouvez essayer jQuery-collision. Divulgation complète: je viens d'écrire ceci et l'ai publié. Je n'ai pas trouvé de solution, alors je l'ai écrite moi-même.

Il permet de faire:

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

qui renvoie tous les " # someobject0 "qui se chevauchent avec"#ball".

20
répondu eruciform 2011-05-18 23:30:41

une Version sans jQuery, avec htmlelements comme entrées

c'est une meilleure approche qui vérifie la position réelle des éléments tels qu'ils sont affichés sur le viewport, même s'ils sont absolus, relatifs ou ont été manipulés via des transformations:

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))
    );
}
9
répondu Àlex Garcés 2016-12-21 14:22:58

"bcm" réponse, qui a 0 vote à cette époque, est en fait une belle, sous-estimé la réponse. Il utilise de bons vieux Pythagore pour détecter quand les objets sont plus proches que leurs cercles de limite combinés. La détection de collision Simple utilise souvent la détection de collision rectangulaire, ce qui est très bien si vos sprites ont tendance à être, bien, rectangulaire. S'ils sont circulaires (ou autrement moins que rectangulaire), comme une boule, un astéroïde, ou toute autre forme où les coins extrêmes sont habituellement transparents, vous peut-être que cette routine efficace est la plus précise.

mais pour plus de clarté, voici une version plus complète du code:

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);
} 

où les paramètres à passer sont les valeurs x, y et width de deux objets sprite différents

6
répondu J Sprague 2014-01-11 06:32:41
//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; i<elements.length; i++) { 
            if (elements[i]==element) break; 
        } 
        elements.push(element); 
        if (arguments.length>1)  
            for (var i=0; i<arguments.length; i++)  
                Element.register(arguments[i]); 
    }; 
    Element.collide = function () { 
        for (var outer=0; outer < elements.length; outer++) { 
            var e1 = Object.extend( 
                $(elements[outer]).positionedOffset(), 
                $(elements[outer]).getDimensions() 
            ); 
            for (var inner=outer; inner<elements.length; innter++) { 
                var e2 = Object.extend( 
                    $(elements[inner]).positionedOffset(), 
                    $(elements[inner]).getDimensions() 
                ); 
                if (     
                    (e1.left+e1.width)>=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);
4
répondu Fordi 2010-08-31 07:15:38

C'est une solution légère et je suis venu à travers -

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

Les grandes et petites variables sont de 2 objets, (x coord, y coord, and W width)

ici

4
répondu bcm 2011-03-30 00:32:47

Mozilla a un bon article à ce sujet, avec le code ci-dessous

https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection

collision de Rectangle

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!
}

collision en cercle

if (distance < circle1.radius + circle2.radius) {
    // collision detected!
}
4
répondu B M 2015-06-28 22:42:47

C'est un moyen simple qui est inefficace mais il est tout à fait raisonnable quand vous n'avez pas besoin de quelque chose de trop complexe ou vous n'avez pas beaucoup d'objets.

sinon il y a beaucoup d'algorithmes différents, mais la plupart d'entre eux sont assez complexes à mettre en oeuvre.

Par exemple, vous pouvez utiliser un divide et impera approche dans laquelle vous regroupez hiérarchiquement les objets en fonction de leur distance et vous donnez à chaque groupe une boîte de délimitation qui contient tous les éléments de la cluster.Ensuite, vous pouvez vérifier quels amas entrent en collision et éviter de vérifier les paires d'objets qui appartiennent à des amas qui ne sont pas en collision/se chevauchent.

sinon vous pouvez calculer un algorithme générique de partitionnement de l'espace pour diviser de la même manière les objets pour éviter les vérifications inutiles. Ces algorithmes diviser la détection de collision en deux phases: une grossier un dans lequel vous voyez quels objets peuvent entrer en collision et un fine une dans laquelle vous avez effectivement vérifiez chaque objet. Par exemple, vous pouvez utiliser un QuadTreewikipédia pour trouver une solution facile..

jetez un coup d'oeil à wikipedia page, il peut vous donner des conseils.

3
répondu Jack 2010-03-13 23:16:15

hittest.js; détecter deux collisions d'image png transparente (pixel). Démo et le lien de téléchargement

code HTML;

<img id="png-object-1" src="images/object1.png" />
<img id="png-object-2" src="images/object2.png" />

fonction Init;

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

var object1HitTest = new HitTest( pngObject1Element );

utilisation de Base;

if( object1HitTest.toObject( pngObject2Element ) ) {
    //Collision detected
}
1
répondu bugra ozden 2013-08-23 04:47:00