Javascript:碰撞检测

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2440377/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 00:20:56  来源:igfitidea点击:

Javascript: Collision detection

javascriptcollision-detection

提问by Hyman moore

could someone please help me to understand how collision detection works in JS? I can't use jQuery or gameQuery - already using prototype - so, I'm looking for something very simple. Not asking for complete solution, just point me to the right direction.

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

Let's say there's:

假设有:

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

Now the ball is moving (any direction). "Someobject"(0-X) is already pre-defined and there's 20-60 of them randomly positioned like this:

现在球正在移动(任何方向)。"Someobject"(0-X) 已经预先定义好了,其中有 20-60 个随机放置,如下所示:

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

I can create an array with "someobject(X)" positions and test collision while the "ball" is moving... Something like:

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

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

But I guess this would be a "noob" solution and it looks pretty slow. Is there anything better?

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

采纳答案by Li0liQ

The first thing to have is the actual function that will detect whether you have a collision between the ball and the object.

首先需要的是实际功能,它会检测您是否在球和物体之间发生碰撞。

For the sake of performance it will be great to implement some crude collision detecting technique, e.g., bounding rectangles, and a more accurate one if needed in case you have collision detected, so that your function will run a little bit quicker but using exactly the same loop.

为了提高性能,最好实现一些粗略的碰撞检测技术,例如,边界矩形,如果需要,如果检测到碰撞,还可以使用更准确的技术,以便您的函数运行得更快一点,但恰好使用相同的循环。

Another option that can help to increase performance is to do some pre-processing with the objects you have. For example you can break the whole area into cells like a generic table and store the appropriate object that are contained within the particular cells. Therefore to detect the collision you are detecting the cells occupied by the ball, get the objects from those cells and use your collision-detecting function.

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

To speed it up even more you can implement 2d-tree, quadtreeor R-tree.

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

回答by Husky

Here's a very simple bounding rectangle routine. It expects both aand bto be objects with x, y, widthand heightproperties:

这是一个非常简单的边界矩形例程。该公司预计双方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))
    );
}

To see this function in action, here's a codepengraciously made by @MixerOID.

要查看此功能的实际效果,请使用 @MixerOID慷慨制作的代码笔

回答by eruciform

You can try jquery-collision. Full disclosure: I just wrote this and released it. Didn't find a solution so I wrote it myself.

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

It allows you to do:

它允许您执行以下操作:

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

which will return all the "#someobject0"'s that overlap with "#ball".

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

回答by àlex Garcés

A Version without jQuery, with HTMLElements as inputs

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

This is a better approach that checks the real position of the elements as they are being shown on the viewport, even if they're absolute, relative or have been manipulated via transformations:

这是一种更好的方法,可以检查元素在视口上显示时的真实位置,即使它们是绝对的、相对的或已通过转换进行操作:

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

回答by J Sprague

"bcm's" answer, which has 0 votes at this time, is actually a great, under-appreciated answer. It uses good old Pythagoras to detect when objects are closer than their combined bounding circles. Simple collision detection often uses rectangular collision detection, which is fine if your sprites tend to be, well, rectangular. If they are circular (or otherwise less than rectangular), such as a ball, an asteroid, or any other shape where the extreme corners are usually transparent, you may find this efficient routine to be the most accurate.

"bcm's" 的答案,此时有 0 票,实际上是一个很好的、被低估的答案。它使用古老的毕达哥拉斯来检测物体何时比它们的组合边界圆更近。简单的碰撞检测通常使用矩形碰撞检测,如果您的精灵倾向于是矩形,这很好。如果它们是圆形(或其他小于矩形的),例如球、小行星或任何其他极端角通常是透明的形状,您可能会发现这种高效的例程是最准确的。

But for clarity, here is a more fully realized version of the code:

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

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

Where the parameters to pass in are the x,y and width values of two different sprite objects

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

回答by B M

Mozilla has a good article on this, with the code shown below

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

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

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

Rectangle collision

矩形碰撞

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!
}

Circle collision

圆圈碰撞

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

回答by bcm

This is a lightweight solution I've come across -

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

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

The big and small variables are of 2 objects, (x coord, y coord, and w width)

big 和 small 变量有 2 个对象,(x 坐标、y 坐标和 w 宽度)

From here

这里

回答by Fordi

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

回答by Hyman

This is a simple way that is inefficient but it's quite reasonable when you don't need anything too complex or you don't have many objects.

这是一种效率低下的简单方法,但是当您不需要太复杂的东西或没有很多对象时,这是非常合理的。

Otherwise there are many different algorithms but most of them are quite complex to implement.

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

For example you can use a divide et imperaapproach in which you cluster objects hierarchically according to their distance and you give to every cluster a bounding box that contains all the items of the cluster.Then you can check which clusters collide and avoid checking pairs of object that belong to clusters that are not colliding/overlapped.

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

Otherwise you can figure out a generic space partitioning algorithm to split up in a similar way the objects to avoid useless checks. These kind of algorithms split the collision detection in two phases: a coarseone in which you see what objects maybe colliding and a fineone in which you effectively check single objects. For example you can use a QuadTreewikipediato workout an easy solution..

否则,您可以找出一个通用的空间分区算法,以类似的方式拆分对象以避免无用的检查。这些算法将碰撞检测分为两个阶段:粗略的阶段,您可以看到哪些对象可能发生碰撞,而精细的阶段,您可以有效地检查单个对象。例如,您可以使用QuadTree维基百科来锻炼一个简单的解决方案。

Take a look to wikipedia page, it can give you some hints.

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

回答by bugra ozden

hittest.js;detect two transparent png image (pixel) collision. Demo and download link

命中测试.js; 检测两个透明 png 图像(像素)碰撞。 演示和下载链接

HTML Code;

HTML代码;

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

Init function;

初始化函数;

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

var object1HitTest = new HitTest( pngObject1Element );

Basic usage;

基本用法;

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