如何检测两个<div>
元素是否发生碰撞?
这两个 div 是相互垂直的简单彩色盒子,因此没有复杂的形状或角度。
如何检测两个<div>
元素是否发生碰撞?
这两个 div 是相互垂直的简单彩色盒子,因此没有复杂的形状或角度。
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>
一般想法 - 您获得框的偏移量和尺寸并检查它们是否重叠。
如果您希望它更新,您可以使用setInterval
:
function detectOverlapping() {
// code that detects if the box overlaps with a moving box
setInterval(detectOverlapping, 25);
}
detectOverlapping();
另请注意,您可以针对特定示例优化该函数。
您不必重复阅读盒子尺寸(就像我在我的代码中所做的那样),因为它们是固定的。您可以在页面加载时读取它们(到变量中),然后只读取变量
小框的水平位置不会改变(除非用户调整窗口大小)。车箱的垂直位置不变。因此,这些值也不必重复读取,也可以存储到变量中。
您不必始终测试小盒子是否与所有汽车盒子重叠。您可以 - 根据其垂直位置 - 确定盒子当前位于哪个车道,并仅测试该车道上的特定汽车盒子。
我相信这是最简单的方法:https : //plugins.jquery.com/overlaps/
这是另一个,德语:http : //www.48design.de/news/2009/11/20/kollisionsabfrage-per-jquery-plugin-update-v11-8/
我会尝试一下。
- 更新 -
我现在真的不能在上面花任何时间,但是如果我回家后没有人回答你,我可以这样做;我可以做一些类似的事情:
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);
这有点晚了,但我想你可以使用我在面临类似情况时尝试过的这种方法。这里的优点是不涉及额外的插件或脚本,您也不必在其中引入性能饥渴的轮询。这种技术使用了 Jquery 的 droppable 必须提供的内置方法和事件。
好吧,说得够多了,这里是解决方案技术:假设你有两个元素(在我的例子中是图像)并且你不希望它们重叠或检测它们何时重叠,使这两个元素成为可放置的并使它们“接受”彼此:
$([div1, div2]).droppable(CONFIG_COLLISSION_PREVENTION_DROPPABLE);
'CONFIG_COLLISSION_PREVENTION_DROPPABLE' 看起来像这样:
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);
}
}
“activate”和“drop”处理程序指的是“droppable”插件的“dropactivate”和“drop”事件
在这里,关键是“drop”回调。每当两个元素中的任何一个重叠并且它们相互放置时,将调用“放置”。这是检测和执行动作的地方,可能是发送自定义事件或调用其他动作(我在这里选择将重叠元素的位置恢复到拖动开始时的初始位置,这是在 'activate' 回调中捕获的)。
而已。没有轮询,没有插件,只有内置事件。
好吧,可以对它进行其他优化/扩展,这只是我头脑中第一次成功:)
您还可以使用 'dropover' 和 'dropout' 事件向用户发出信号并创建视觉反馈,即两个元素正在重叠,而它们可能仍在移动中。
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);
}
});
希望这可以帮助!
编辑:我在我的网站上写了一篇博文。这是它的链接。 http://area36.nl/2014/12/creating-your-own-collision-detection-function-in-javascript/
好吧,我遇到了同样的问题,但感谢 Oscar Godson 的回答,我得到了一个有效的功能。我使用 Jquery 来轻松编码,因为我很懒;p。我把这个函数放在另一个每秒触发的函数中,所以请记住这一点。
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
}
}
它所做的基本上是获取 的所有值,element1
然后获取 的所有值element2
。然后在一些计算的帮助下它计算出所有值。然后在if
语句中,它将 的平方element1
与 的平方进行比较element2
。如果 的值element1
介于 的左侧、右侧、顶部和底部值之间element2
。如果这是真的,则执行底部的代码。
我自己遇到了这个普遍的问题,所以(完全披露)我为它制作了一个插件。对于关于静态对象的简单碰撞查询,试试这个:
http://sourceforge.net/projects/jquerycollision/
这允许您获得重叠碰撞框的列表(如果没有碰撞,则没有):
hits = $("#collider").collision(".obstacles");
或者要在“拖动”期间获得碰撞事件,请使用:
http://sourceforge.net/apps/mediawiki/jquidragcollide/?source=navbar#collision
这为您提供了要连接的“碰撞”事件。(或“突出”事件,以查看一个 div 是否逃脱了当前包含它的另一个 div。)
$(draggable).bind(
"collision",
function(event,ui) {
...
}
);
如果您在除拖动之外的运动过程中检查碰撞,只需重复调用原件,它会很快。注意:拖动一个不能很好地调整大小。