<div>
元素是否发生碰撞?两个div是简单的彩色框,彼此垂直移动,因此没有复杂的形状或角度。
#1 楼
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();
此外,请注意,您可以针对特定示例优化功能。
您无需阅读框尺寸是重复的(就像我在代码中一样),因为它们是固定的。您可以在页面加载时读取它们(将其读取到变量中),然后只需读取变量
,小盒子的水平位置就不会改变(除非用户调整窗口大小)。轿厢的垂直位置不变。因此,这些值也不必重复读取,而是也可以存储到变量中。
您不必测试小盒子是否始终与所有汽车盒子重叠。您可以-基于其垂直位置-确定当前箱子在哪个车道上,并仅测试该车道上的特定汽车箱子。
评论
看起来不错,现在尝试在我的样本上对其进行测试...我将如何更新每个框架?
–克里斯·阿姆斯特朗(Chris Armstrong)
10 Nov 20'3:30
嗯...玩家的位置是(649,75)至(674,100),汽车的位置是(649,50)至(749,100),所以它们是重叠的,但比赛返回为错误,为什么会这样?
–克里斯·阿姆斯特朗(Chris Armstrong)
2010-11-20在3:52
@Chris Yea,我刚刚意识到我只考虑了9种重叠场景中的2种。但是,合并所有9个方案应该很容易。等我一下。
–Šime Vidas
10 Nov 20 '13:18
@Chris专注于根据“玩家”的垂直位置来检测要测试的“汽车”。您有15辆赛车,每次测试所有15辆赛车的速度比仅测试可能与玩家重叠的一辆赛车慢15倍。
–Šime Vidas
2010-11-20 14:38
这是一个非常不错的小提琴,但是您认为在第4行上使用$ .offset()而不是$ .position()更好吗?这样,它应该可以检查DOM中所有元素的冲突,而不仅仅是处理同级元素。
–陆even
2012-09-19 15:04
#2 楼
我相信这是最简单的方法:http://plugins.jquery.com/project/collidable
这是另一种德语版本:
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);
评论
谢谢!对于那个可碰撞的物体,我是否必须使这些物体可拖动才能工作?
–克里斯·阿姆斯特朗(Chris Armstrong)
2010年11月19日在22:46
废话,你知道我想怎么做,但是...您可以使用jQuery UI将其设置为可拖动(我认为它正在使用),然后将return false设置为对象上的click事件,使其不可单击(因此无法拖动),但碰撞会起作用。
–奥斯卡·戈德森(Oscar Godson)
2010-11-19 22:49
您知道...也可以(而且可能会更容易)...即时更新我的答案。
–奥斯卡·戈德森(Oscar Godson)
2010-11-19 22:50
#3 楼
这有点晚了,但是我想您可以使用在遇到类似情况时尝试的这种方法。这样做的好处是,它不需要任何其他插件或脚本,也不需要在其中引入性能饥饿的轮询。该技术使用了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);
}
}
“激活”和“放置”处理程序是指“可放置”插件的“放置激活”和“放置”事件。
这里的关键是“放置”回调。每当这两个元素中的任何一个重叠并且彼此重叠时,就会调用“ drop”。在这里可以检测并采取措施,可能是发出自定义事件或调用其他措施(我在这里选择将拖动开始时将重叠元素的位置还原为初始位置,这是在“激活”回调中捕获的)。 br />
就这样。没有轮询,没有插件,只有内置事件。
好吧,还可以进行其他优化/扩展,这只是我头脑中的第一招:)
您还可以使用'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);
}
});
希望有帮助!
评论
重要提示:另外请注意,应首先将两个div设为“可拖动”。
– Murtaza H
2012年4月1日14:14
我正在寻找这样的东西!为了避免出现游戏循环,我不想将轮询引入方程式(就像您提到的那样)。谢谢!
–克里斯·海豚(Chris Dolphin)
15年3月9日在9:09
#4 楼
编辑:我已经在我的网站上写了一个博客文章。这里是指向它的链接。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
的左,右,上和下值之间。如果是这样,则执行底部的代码。评论
你能举个例子吗?也许是JS小提琴?
–安迪
2014年11月28日下午4:05
#5 楼
我自己遇到了这个普遍性的问题,所以(完整披露)我为此做了一个插件。对于有关静态对象的简单碰撞查询,请尝试以下操作:http://sourceforge.net/projects/jquerycollision/
允许您获取重叠碰撞盒的列表(如果没有碰撞,则不显示):
hits = $("#collider").collision(".obstacles");
或在“拖动”期间获取碰撞事件,请使用以下命令:
http: //sourceforge.net/apps/mediawiki/jquidragcollide/?source=navbar#collision
这会给您一个“碰撞”事件以进行连接。 (或“突出”事件,以查看div是否转义了当前包含该div的另一个div。)
$(draggable).bind(
"collision",
function(event,ui) {
...
}
);
如果要检查运动过程中的拖动而不是拖动,只需反复调用原始文件即可,速度非常快。注意:拖动鼠标不能很好地调整大小。
评论
嗨,您有碰撞发生在拖动上的示例吗?当它接触另一个而不重叠它们时,我没有设法使用它使一个div停止。在突出时,我会进行mounseup,因此我将无法再将其拖到外部-我需要在突出前进行mouseup。
–alex蟾蜍
2015年1月1日19:27
#6 楼
帖子过旧,可能对您有所帮助...function CheckDiv()
{
var ediv1 = document.getElementById('DIV1');
var ediv2 = document.getElementById('DIV2');
ediv1.top = $(ediv1).offset().top;
ediv1.left = $(ediv1).offset().left;
ediv1.right = Number($(ediv1).offset().left) + Number($(ediv1).width());
ediv1.bottom = Number($(ediv1).offset().top) + Number($(ediv1).height());
ediv2.top = $(ediv2).offset().top;
ediv2.left = $(ediv2).offset().left;
ediv2.right = Number($(ediv2).offset().left) + Number($(ediv2).width());
ediv2.bottom = Number($(ediv2).offset().top) + Number($(ediv2).height());
if (ediv1.right > ediv2.left && ediv1.left < ediv2.right && ediv1.top < ediv2.bottom && ediv1.bottom > ediv2.top)
{
alert("hi");
}
if (ediv1.left > ediv2.left && ediv1.top > ediv2.top && ediv1.right < ediv2.right && ediv1.bottom < ediv2.bottom)
{
alert("hello");
}
}
#7 楼
您可以使用getBoundingClientRect()function isOverlapping(div1, div2){
const div1 = div1.getBoundingClientRect();
const div2 = div2.getBoundingClientRect();
return (div1.right > div2.left &&
div1.left < div2.right &&
div1.bottom > div2.top &&
div1.top < div2.bottom)
}
完成此操作
评论
哇,网页真好。动画是纯CSS。 :)谢谢,目前还很粗糙,但是您知道了。当我掌握了基础知识后,我会把它弄好。事实证明CSS对于关卡设计来说是很棒的...类是分层行为的真正简便方法。现在要尝试您的示例代码,谢谢
警告,页面使FireFox 12崩溃。JavaScript挂起,并且从不要求停止脚本。
作为游戏的提示,您可能需要禁用向下翻页和滚动条。
Javascript的可能重复项:碰撞检测