Javascript:碰撞检测

时间:2010-03-13 22:57:40

标签: javascript collision-detection

有人可以帮我理解碰撞检测在JS中的工作原理吗?我不能使用jQuery或gameQuery - 已经使用原型 - 所以,我正在寻找一些非常简单的东西。不要求完整的解决方案,只需指出正确的方向。

让我们说:

<div id="ball"></div>
and 
<div id="someobject0"></div>

现在球正在移动(任何方向)。 “Someobject”(0-X)已经预先定义,其中有20-60个随机定位如下:

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

我可以创建一个带有“someobject(X)”位置的数组,并在“ball”移动时测试碰撞...类似于:

for(var c=0; c<objposArray.length; c++){
........ and code to check ball's current position vs all objects one by one....
}

但我想这将是一个“noob”解决方案,它看起来很慢。 还有什么更好的吗?

10 个答案:

答案 0 :(得分:62)

这是一个非常简单的边界矩形例程。它希望ab都是xywidthheight属性的对象:

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

要查看此功能,here's a codepen@MixerOID慷慨地制作。

答案 1 :(得分:29)

首先要做的是检测球与物体之间是否发生碰撞的实际功能。

为了提高性能,实现一些粗略的碰撞检测技术(例如bounding rectangles)会更好,如果需要检测到碰撞,则更准确一个,这样你的功能就会运行一点比较快,但使用完全相同的循环。

另一个有助于提高性能的选项是使用您拥有的对象进行一些预处理。例如,您可以将整个区域分解为像通用表格一样的单元格,并存储特定单元格中包含的相应对象。因此,要检测碰撞,您将检测球所占据的细胞,从这些细胞中获取物体并使用碰撞检测功能。

为了加快速度,您可以实施2d-treequadtreeR-tree

答案 2 :(得分:21)

您可以尝试jquery-collision。完全披露:我刚刚写了这个并发布了它。没有找到解决方案,所以我自己写了。

它允许你这样做:

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

将返回与“#ball”重叠的所有“#someobject0”。

答案 3 :(得分:14)

没有jQuery的版本,HTMLElements作为输入

这是一种更好的方法,可以检查元素在视口中显示时的实际位置,即使它们是绝对的,相对的或者是通过转换操纵的:

function isCollide(a, b) {
    var aRect = a.getBoundingClientRect();
    var bRect = b.getBoundingClientRect();

    return !(
        ((aRect.top + aRect.height) < (bRect.top)) ||
        (aRect.top > (bRect.top + bRect.height)) ||
        ((aRect.left + aRect.width) < bRect.left) ||
        (aRect.left > (bRect.left + bRect.width))
    );
}

答案 4 :(得分:7)

“bcm的”答案,此时有0票,实际上是一个很好的,不被重视的答案。它使用好旧的毕达哥拉斯来检测物体何时比它们组合的边界圆更近。简单的碰撞检测通常使用矩形碰撞检测,如果你的精灵往往是矩形的,那就很好了。如果它们是圆形(或小于矩形),例如球,小行星或任何其他形状,其中极端角通常是透明的,您可能会发现这种有效的例程是最准确的。

但为了清楚起见,这里是一个更完全实现的代码版本:

function doCollide(x1, y1, w1, x2, y2, w2) {
    var xd = x1 - x2;
    var yd = y1 - y2;
    var wt = w2 + w1;
    return (xd * xd + yd * yd <= wt * wt);
} 

传入的参数是两个不同精灵对象的x,y和width值

答案 5 :(得分:5)

这是我遇到的轻量级解决方案 -

function E() { // check collision
            S = X - x;
            D = Y - y;
            F = w + W;
            return (S * S + D * D <= F * F)
        }

大变量和小变量是2个对象,(x coord,y coord和w width)

来自here

答案 6 :(得分:5)

Mozilla有一篇很好的文章,代码如下所示

https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection

矩形碰撞

if (rect1.x < rect2.x + rect2.width &&
   rect1.x + rect1.width > rect2.x &&
   rect1.y < rect2.y + rect2.height &&
   rect1.height + rect1.y > rect2.y) {
    // collision detected!
}

圆圈碰撞

if (distance < circle1.radius + circle2.radius) {
    // collision detected!
}

答案 7 :(得分:4)

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

答案 8 :(得分:3)

这是一种效率低下的简单方法,但是当你不需要任何太复杂的东西或者你没有很多物体时,它是非常合理的。

否则有许多不同的算法,但大多数算法实现起来都很复杂。

例如,您可以使用 divide et impera 方法,在该方法中,根据距离对层对象进行分层,并为每个群集提供包含群集中所有项目的边界框。然后,您可以检查哪些簇发生冲突,并避免检查属于未发生碰撞/重叠的簇的对象对。

否则,你可以找出一个通用的空间分区算法,以类似的方式拆分对象以避免无用的检查。这些算法将碰撞检测分为两个阶段:一个,其中您可以看到哪些对象可能发生碰撞,另一个精细可以有效地检查单个对象。 例如,您可以使用 QuadTree wikipedia来制作简单的解决方案..

看看维基百科page,它可以给你一些提示。

答案 9 :(得分:1)

hittest.js; 检测两个透明的png图像(像素)碰撞。 Demo and download link

HTML代码;

<img id="png-object-1" src="images/object1.png" />
<img id="png-object-2" src="images/object2.png" />

初始化功能;

var pngObject1Element = document.getElementById( "png-object-1" );
var pngObject2Element = document.getElementById( "png-object-2" );

var object1HitTest = new HitTest( pngObject1Element );

基本用法;

if( object1HitTest.toObject( pngObject2Element ) ) {
    //Collision detected
}