【问题标题】:jQuery/JavaScript collision detectionjQuery/JavaScript 碰撞检测
【发布时间】:2023-03-18 18:37:01
【问题描述】:

如何检测两个<div>元素是否碰撞?

这两个 div 是简单的彩色框,相互垂直,因此没有复杂的形状或角度。

【问题讨论】:

  • 哇,多么好的网页啊。动画是纯CSS。 :)
  • 谢谢,现在一切都很粗糙,但你明白了。当我得到基本的工作时,我会很漂亮。事实证明,CSS 非常适合关卡设计……类是一种非常简单的分层行为方式。现在就试试你的示例代码谢谢
  • 警告,页面崩溃 FireFox 12。JavaScript 挂起,它从不要求停止脚本。
  • 作为游戏提示,您可能希望禁用向下翻页和滚动条。

标签: javascript jquery html collision-detection


【解决方案1】:

我相信这是最简单的方法: 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 UI 将它设置为可拖动(我认为这是它正在使用的),但然后将 return false 设置为单击事件在对象上使其不可点击(因此不可拖动)但碰撞会起作用。
  • 你知道......你也可以(而且可能更容易)......我正在更新我的答案。
【解决方案2】:

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

另外,请注意,您可以针对特定示例优化该功能。

  • 您不必重复阅读框尺寸(就像我在代码中所做的那样),因为它们是固定的。您可以在页面加载时读取它们(到变量中),然后只需读取变量

  • 小盒子的水平位置不会改变(除非用户调整窗口大小)。车厢的垂直位置不变。因此,这些值也不必重复读取,也可以存储到变量中。

  • 您不必一直测试小盒子是否与所有汽车盒子重叠。您可以 - 根据其垂直位置 - 确定盒子当前在哪个车道上,并仅测试该车道上的特定车厢。

【讨论】:

  • 看起来不错,现在正尝试在我的样本上进行测试......我如何让它更新每一帧?
  • 嗯...玩家的位置是从 (649, 75) 到 (674, 100),而汽车的位置是从 (649, 50) 到 (749, 100),所以他们是重叠,但匹配返回为假,知道为什么会这样吗?
  • @Chris 是的,我刚刚意识到我只考虑了 9 个重叠场景中的 2 个。但是应该很容易合并所有 9 个场景。给我一点时间。
  • @Chris 专注于根据“玩家”的垂直位置检测要测试的“汽车”。您有 15 辆汽车,每次测试全部 15 辆汽车比只测试可能与玩家重叠的一辆汽车慢 15 倍。
  • 这是一个非常棒的小提琴,但您不认为在第 4 行使用 $.offset() 而不是 $.position() 更好吗?这样,它应该可以检查 DOM 中所有元素的冲突,而不仅仅是处理兄弟元素。
【解决方案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);
     }
}

'activate' 和 'drop' 处理程序是指 "droppable" 插件的 'dropactivate' 和 'drop' 事件

这里的关键是“drop”回调。每当这两个元素中的任何一个重叠并且它们彼此重叠时,都会调用“drop”。这是检测和采取行动的地方,可能是发送自定义事件或调用其他操作(我这里选择在拖动开始时将重叠元素的位置恢复到初始位置,这是在“激活”回调中捕获的)。

就是这样。没有投票,没有插件,只有内置事件。

好吧,可以对其进行其他优化/扩展,这只是我脑海中的第一枪:)

您还可以使用“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 应首先设为“可拖动”。
  • 我正在寻找这样的东西!试图避免出现游戏循环,我不想在等式中引入轮询(就像你提到的那样)。谢谢!
【解决方案4】:

我自己遇到了这个普遍问题,所以(完全披露)我为它制作了一个插件。对于静态对象的简单碰撞查询,试试这个:

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

如果您在运动过程中检查碰撞而不是拖动,只需重复调用原始对象,这非常快。注意:拖动不适合调整大小。

【讨论】:

  • 您好,请问您有关于拖动碰撞的示例吗?当一个 div 在不重叠的情况下接触另一个 div 时,我没有设法使用它来停止它。在突出时我会做 mounseup 所以我不能再把它拖到外面 - 我需要在突出之前做 mouseup。
【解决方案5】:

编辑:我在我的网站上写了一篇博文。这里有一个链接。 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 小提琴?
【解决方案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)
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-22
      • 2011-07-03
      相关资源
      最近更新 更多