53 votes

JavaScript : Détection des collisions

Comment fonctionne la détection des collisions en JavaScript ?

Je ne peux pas utiliser jQuery ou gameQuery - j'utilise déjà le prototype - donc, je cherche quelque chose de très simple. Je ne demande pas de solution complète, mais simplement de m'indiquer la bonne direction.

Disons qu'il y en 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 aléatoirement comme ceci :

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

Je peux créer un tableau avec les positions de "someobject(X)" et tester la collision pendant que la "balle" 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 de "débutant" et elle semble assez lente. Existe-t-il une meilleure solution ?

83voto

Husky Points 2221

Voici une routine très simple de rectangle de délimitation. Elle attend les deux a y b pour être des objets avec x , y , width y 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 en action, voici un codepen fait gracieusement par @MixerOID .

0 votes

Quelqu'un peut-il m'expliquer ce que je fais mal ? Elle renvoie toujours la réponse vraie, quelle que soit l'option "collision". jsbin.com/akeSeDI/2/edit

2 votes

@KryptoniteDove : malheureusement vous ne pouvez pas simplement entrer un élément DOM dans cette routine, vous avez besoin d'une sorte de conversion (par exemple en utilisant jQuery). En outre, vos divs devraient probablement utiliser position: absolute au lieu de relative . Voici un fork de votre version qui fonctionne : jsbin.com/akeSeDI/3/edit

5 votes

J'ai créé un GUI visuel pour cette merveilleuse fonction :) codepen.io/mixal_bl4/pen/qZYWOm Vous pouvez ajouter ceci à votre réponse :)

32voto

Li0liQ Points 8104

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

Pour des raisons de performance, il serait bon d'implémenter une technique de détection de collision rudimentaire, par exemple, rectangles de délimitation et une autre plus précise si nécessaire en cas de détection de collision, de sorte que votre fonction s'exécute un peu plus rapidement mais en utilisant exactement la même boucle.

Une autre option qui peut contribuer à améliorer les performances consiste à effectuer un prétraitement des objets dont vous disposez. Par exemple, vous pouvez diviser la zone entière en cellules, comme un tableau générique, et stocker les objets appropriés 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, vous récupérez les objets de ces cellules et vous utilisez votre fonction de détection de collision.

Pour accélérer encore plus le processus, vous pouvez mettre en œuvre 2d-arbre , Quadtree o R-tree .

22voto

eruciform Points 5176

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

Il vous permet de faire :

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

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

7 votes

L'OP dit qu'ils ne peuvent pas utiliser jQuery. C'est quand même bien, ça m'a aidé à trouver ma propre solution.

0 votes

@irwin - hmm, j'étais sur le point de dire "je ne peux pas utiliser jquery -- j'utilise prototype" comme dans, je suis presque sûr que vous pouvez les mélanger. je n'ai pas essayé, cependant, honnêtement. content que cela vous ait aidé ! essayez jquery-draggable-collision, aussi ! :-)

0 votes

@PeterAjtai : non, c'est sur sourceforge, pourquoi ?

5voto

sathishkumar Points 744

J'ai une fonctionnalité dans mon projet, que je trouve ici. http://jsbin.com/imofat/660

3voto

Fordi Points 917
//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);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X