Comment détecter si deux <div>
éléments sont entrés en collision ?
Les deux divs sont de simples boîtes de couleur se déplaçant perpendiculairement l'une à l'autre, donc pas de formes ou d'angles compliqués.
Comment détecter si deux <div>
éléments sont entrés en collision ?
Les deux divs sont de simples boîtes de couleur se déplaçant perpendiculairement l'une à l'autre, donc pas de formes ou d'angles compliqués.
var overlaps = (function () {
function getPositions( elem ) {
var pos, width, height;
pos = $( elem ).position();
width = $( elem ).width();
height = $( elem ).height();
return [ [ pos.left, pos.left + width ], [ pos.top, pos.top + height ] ];
}
function comparePositions( p1, p2 ) {
var r1, r2;
r1 = p1[0] < p2[0] ? p1 : p2;
r2 = p1[0] < p2[0] ? p2 : p1;
return r1[1] > r2[0] || r1[0] === r2[0];
}
return function ( a, b ) {
var pos1 = getPositions( a ),
pos2 = getPositions( b );
return comparePositions( pos1[0], pos2[0] ) && comparePositions( pos1[1], pos2[1] );
};
})();
$(function () {
var area = $( '#area' )[0],
box = $( '#box0' )[0],
html;
html = $( area ).children().not( box ).map( function ( i ) {
return '<p>Red box + Box ' + ( i + 1 ) + ' = ' + overlaps( box, this ) + '</p>';
}).get().join( '' );
$( 'body' ).append( html );
});
body {
padding: 30px;
color: #444;
font-family: Arial, sans-serif;
}
h1 {
font-size: 24px;
margin-bottom: 20px;
}
#area {
border: 2px solid gray;
width: 500px;
height: 400px;
position: relative;
}
#area > div {
background-color: rgba(122, 122, 122, 0.3);
position: absolute;
text-align: center;
font-size: 50px;
width: 60px;
height: 60px;
}
#box0 {
background-color: rgba(255, 0, 0, 0.5) !important;
top: 150px;
left: 150px;
}
#box1 {
top: 260px;
left: 50px;
}
#box2 {
top: 110px;
left: 160px;
}
#box3 {
top: 200px;
left: 200px;
}
#box4 {
top: 50px;
left: 400px;
}
p {
margin: 5px 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<h1>Detect overlapping with JavaScript</h1>
<div id="area">
<div id="box0"></div>
<div id="box1">1</div>
<div id="box2">2</div>
<div id="box3">3</div>
<div id="box4">4</div>
</div>
Idée générale - vous obtenez le décalage et la dimension des boîtes et vous vérifiez si elles se chevauchent.
Si vous voulez qu'il soit mis à jour, vous pouvez utiliser setInterval
:
function detectOverlapping() {
// code that detects if the box overlaps with a moving box
setInterval(detectOverlapping, 25);
}
detectOverlapping();
Notez également que vous pouvez optimiser la fonction pour votre exemple spécifique.
vous n'avez pas besoin de lire les dimensions de la boîte à plusieurs reprises (comme je le fais dans mon code) puisqu'elles sont fixes. Vous pouvez les lire au chargement de la page (dans une variable) et ensuite simplement lire la variable
la position horizontale de la petite boîte ne change pas (sauf si l'utilisateur redimensionne la fenêtre). La position verticale des cases de la voiture ne change pas. Par conséquent, ces valeurs ne doivent pas non plus être lues de manière répétée, mais peuvent être stockées dans des variables.
il n'est pas nécessaire de vérifier à tout moment si la petite boîte chevauche toutes les boîtes de voiture. Vous pouvez, en vous basant sur sa position verticale, déterminer dans quelle voie se trouve actuellement la boîte et ne tester que la boîte de voiture spécifique de cette voie.
Ça a l'air génial, j'essaie de le tester sur mon échantillon maintenant... comment faire pour qu'il soit mis à jour à chaque image ?
Hmm... La position du joueur est de (649, 75) à (674, 100) et la position de la voiture est de (649, 50) à (749, 100), donc elles se chevauchent, mais la correspondance est retournée comme fausse, une idée de la raison ?
@Chris Oui, je viens de réaliser que je n'ai pris en compte que 2 des 9 scénarios de chevauchement. Mais il devrait être facile d'incorporer les 9 scénarios. Donnez-moi une seconde.
Je crois que c'est le moyen le plus simple : https://plugins.jquery.com/overlaps/
En voici un autre, en allemand : http://www.48design.de/news/2009/11/20/kollisionsabfrage-per-jquery-plugin-update-v11-8/
Je vais les essayer.
--UPDATE--
Je ne peux pas vraiment y consacrer du temps pour le moment, mais je le ferai quand je rentrerai à la maison si personne ne répond, mais tu ferais quelque chose comme.. :
setInterval(function(){
//First step would be to get the offset of item 1 and item 2
//Second would be to get the width of each
//Third would be to check if the offset+width ever overlaps
//the offset+width of the 2nd
//Fourth would be, if so, do X or set a class...
},10);
Merci ! Avec le système de collision, dois-je faire en sorte que les objets puissent être déplacés pour que cela fonctionne ?
Merde, vous savez quoi, je pense que c'est le cas, CEPENDANT... vous pourriez éventuellement le configurer pour qu'il puisse être traîné avec jQuery UI (ce que je pense que c'est ce qu'il utilise) mais ensuite mettre return false aux événements de clic sur l'objet le rendant non cliquable (donc non traînable) mais la collision fonctionnerait.
Il est un peu tard pour le dire, mais je pense que vous pourriez utiliser cette approche que j'ai essayée lorsque j'ai été confronté à une situation similaire. L'avantage est qu'il n'y a pas de plugins ou de scripts supplémentaires et qu'il n'est pas non plus nécessaire d'introduire des sondages gourmands en performances. Cette technique utilise les méthodes et événements intégrés que le droppable de Jquery a à offrir.
Ok, assez parlé, voici la technique de la solution : Disons que si vous avez deux éléments (des images dans mon cas) et que vous ne voulez pas qu'ils se chevauchent ou qu'ils détectent quand ils le font, faites des deux éléments un dropable et faites en sorte qu'ils s'acceptent l'un l'autre :
$([div1, div2]).droppable(CONFIG_COLLISSION_PREVENTION_DROPPABLE);
La "CONFIG_COLLISSION_PREVENTION_DROPPABLE" ressemble à ceci :
var originatingOffset = null;
CONFIG_COLLISSION_PREVENTION_DROPPABLE = {
tolerance: "touch",
activate : function (event, ui) {
// note the initial position/offset when drag starts
// will be usedful in drop handler to check if the move
// occurred and in cae overlap occurred, restore the original positions.
originatingOffset = ui.offset;
},
drop : function (event, ui) {
// If this callback gets invoked, the overlap has occurred.
// Use this method to either generate a custom event etc.
// Here, i used it to nullify the move and resetting the dragged element's
// position back to it's original position/offset
// (which was captured in the 'activate' handler)
$(ui.draggable).animate({
top: originatingOffset.top + "px",
left: originatingOffset.left + "px"
}, 300);
}
}
Les gestionnaires "activate" et "drop" font référence aux événements "dropactivate" et "drop" du plugin "droppable".
Ici, la clé est le rappel "drop". Chaque fois que l'un des deux éléments se chevauche et qu'ils sont déposés l'un sur l'autre, la fonction "drop" est appelée. C'est l'endroit pour détecter et prendre des mesures, que ce soit l'envoi d'événements personnalisés ou l'appel d'autres actions (ici, j'ai choisi de ramener les positions des éléments qui se chevauchent à la position initiale lorsque le déplacement a commencé, ce qui a été capturé dans le callback 'activate').
C'est ça. Pas de sondage, pas de plugins, juste les événements intégrés.
Il peut y avoir d'autres optimisations/extensions, c'était simplement la première idée qui me venait à l'esprit et qui fonctionnait :)
Vous pouvez également utiliser les événements "dropover" et "dropout" pour signaler et créer un retour visuel à l'utilisateur que deux éléments se chevauchent, alors qu'ils sont encore en mouvement.
var CLASS_INVALID = "invalid";
// .invalid { border: 1px solid red; }
...
$.extend(CONFIG_COLLISSION_PREVENTION_DROPPABLE, {
over : function (event, ui) {
// When an element is over another, it gets detected here;
// while it may still be moved.
// the draggable element becomes 'invalid' and so apply the class here
$(ui.draggable).addClass(CLASS_INVALID);
},
out : function(event, ui) {
// the element has exited the overlapped droppable now
// So element is valid now and so remove the invalid class from it
$(ui.draggable).removeClass(CLASS_INVALID);
}
});
J'espère que cela vous aidera !
EDIT : J'ai écrit un billet de blog sur mon site web. Voici un lien vers celui-ci. http://area36.nl/2014/12/creating-your-own-collision-detection-function-in-javascript/
J'ai eu le même problème mais grâce à la réponse d'Oscar Godson j'ai obtenu une fonction qui fonctionne. J'ai utilisé Jquery pour faciliter le codage et parce que je suis paresseux ;p. J'ai mis la fonction dans une autre fonction qui est déclenchée toutes les secondes, donc gardez cela à l'esprit.
function collidesWith (element1, element2) {
var Element1 = {};
var Element2 = {};
Element1.top = $(element1).offset().top;
Element1.left = $(element1).offset().left;
Element1.right = Number($(element1).offset().left) + Number($(element1).width());
Element1.bottom = Number($(element1).offset().top) + Number($(element1).height());
Element2.top = $(element2).offset().top;
Element2.left = $(element2).offset().left;
Element2.right = Number($(element2).offset().left) + Number($(element2).width());
Element2.bottom = Number($(element2).offset().top) + Number($(element2).height());
if (Element1.right > Element2.left && Element1.left < Element2.right && Element1.top < Element2.bottom && Element1.bottom > Element2.top) {
// Do your stuff here
}
}
Ce qu'il fait, c'est qu'il récupère toutes les valeurs de element1
et ensuite obtenir toutes les valeurs de element2
. Ensuite, à l'aide de quelques calculs, il détermine toutes les valeurs. Ensuite, dans le if
il compare le carré de element1
au carré de element2
. Si les valeurs de element1
sont entre les valeurs gauche, droite, supérieure et inférieure de element2
. Si c'est vrai, le code en bas est exécuté.
J'ai moi-même rencontré ce problème généralisé et j'ai donc créé un plugin pour y remédier. Pour de simples requêtes de collision sur des objets statiques, essayez ceci :
http://sourceforge.net/projects/jquerycollision/
Ce qui vous permet d'obtenir une liste des boîtes de collision qui se chevauchent (ou aucune s'il n'y a pas de collision) :
hits = $("#collider").collision(".obstacles");
Ou pour obtenir un événement de collision pendant le "dragging", utilisez ceci :
http://sourceforge.net/apps/mediawiki/jquidragcollide/?source=navbar#collision
Ce qui vous donne un événement "collision" auquel vous pouvez vous connecter. (Ou un événement "protrusion", pour voir si une div échappe à une autre div qui la contient actuellement).
$(draggable).bind(
"collision",
function(event,ui) {
...
}
);
Si vous vérifiez les collisions pendant un mouvement autre que le glissement, appelez simplement l'original à plusieurs reprises, c'est assez rapide. Remarque : la fonction de déplacement ne fonctionne pas bien avec le redimensionnement.
Bonjour, avez-vous un exemple avec la collision fonctionnant sur le drag ? Je n'ai pas réussi à l'utiliser pour faire en sorte qu'une div s'arrête lorsqu'elle touche une autre div sans la chevaucher. Lors de la protrusion, je fais un mouseup, ce qui fait que je ne peux plus la faire glisser vers l'extérieur - je dois faire un mouseup avant la protrusion.
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.
0 votes
Wow, quelle belle page web. Et les animations sont du pur CSS. :)
0 votes
Merci, c'est un peu brut pour l'instant, mais vous voyez l'idée. Je l'améliorerai quand j'aurai réussi à faire fonctionner les bases. Il s'avère que CSS est fantastique pour la conception de niveaux... les classes sont un moyen très facile de superposer les comportements. Je vais essayer votre exemple de code maintenant, merci
4 votes
Attention, la page plante FireFox 12. Le JavaScript se bloque et il ne demande jamais d'arrêter le script.
0 votes
Comme astuce pour votre jeu, vous pouvez désactiver la page suivante et la barre de défilement.
0 votes
Duplicata possible de Javascript : Détection des collisions
0 votes
C'est drôle, une question comme celle-ci serait fermée dans le stackoverflow actuel.