Javascript:碰撞检测
有人能帮我理解碰撞检测如何在JS中工作吗? 我不能使用jQuery或gameQuery – 已经使用原型 – 所以,我正在寻找一些非常简单的东西。 不要求完整的解决scheme,只要指向正确的方向。
假设有:
<div id="ball"></div> and <div id="someobject0"></div>
现在球正在移动(任何方向)。 “Someobject”(0-X)已经预先定义好了,其中有20-60个像这样随机定位:
#someobject {position: absolute; top: RNDpx; left: RNDpx;}
我可以用“someobject(X)”的位置创build一个数组,并在“球”正在移动时testing碰撞…类似于:
for(var c=0; c<objposArray.length; c++){ ........ and code to check ball's current position vs all objects one by one.... }
但我想这将是一个“noob”解决scheme,它看起来很慢。 有更好的吗?
首先要做的是能够检测球和物体之间是否有碰撞的实际function。
为了提高性能,实现一些原始的碰撞检测技术,例如边界矩形 ,以及在碰撞检测的情况下,如果需要,可以使用更精确的碰撞检测技术,这样你的函数可以运行得更快一些,同一回路。
另一个可以帮助提高性能的选项是用你所拥有的对象做一些预处理。 例如,您可以将整个区域分解为像通用表格一样的单元格,并存储包含在特定单元格内的适当对象。 因此,为了检测碰撞,您正在检测球所占据的单元格,从这些单元格中获取对象并使用您的碰撞检测function。
为了加快速度,可以实现2d树 , 四叉树或R树 。
这是一个非常简单的边界矩形例程。 它期望a
和b
都是具有x
, y
, width
和height
属性的对象:
function isCollide(a, b) { return !( ((ay + a.height) < (by)) || (ay > (by + b.height)) || ((ax + a.width) < bx) || (ax > (bx + b.width)) ); }
为了看到这个函数的作用, 这里是一个@MixerOID优雅的代码 。
你可以尝试jQuery碰撞 。 充分披露:我刚刚写了这个,并发布了它。 没有find解决scheme,所以我自己写了。
它可以让你做到:
var hit_list = $("#ball").collision("#someobject0");
这将返回所有与“#ball”重叠的“#someobject0”。
没有jQuery的版本,HTMLElements作为input
这是一个更好的方法,可以检查元素在视口上显示的真实位置,即使它们是绝对的,相对的或通过变换操作的:
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)) ); }
//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);
这是我遇到的一个轻量级解决scheme –
function E() { // check collision S = X - x; D = Y - y; F = w + W; return (S * S + D * D <= F * F) }
大小variables是2个对象(x坐标,y坐标和宽度)
从这里
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! }
这是一种效率低下的简单方法,但当您不需要任何太复杂或者没有太多对象的时候,这是非常合理的。
否则有很多不同的algorithm,但是其中大多数实现相当复杂。
例如,您可以使用分而治之的方法,在这种方法中,根据对象的距离对对象进行分组 ,然后向每个集群提供一个包含集群所有项的边界框。然后,可以检查哪些集群发生冲突,属于不碰撞/重叠的簇的对象。
否则,你可以找出一个通用的空间分割algorithm,以类似的方式拆分对象,以避免无用的检查。 这些algorithm将碰撞检测分为两个阶段:一个粗糙的阶段,您可以看到哪些对象可能发生碰撞,另一个阶段是您可以有效检查单个对象。 例如,您可以使用QuadTree 维基百科来锻炼一个简单的解决scheme。
看看维基百科页面 ,它可以给你一些提示。
“bcm的”答案,这个时候有0票,实际上是一个很好的,低估的答案。 它使用良好的旧毕达哥拉斯来检测对象比他们的组合边界更接近。 简单的碰撞检测通常使用矩形碰撞检测,如果你的精灵往往是矩形的,那就好了。 如果它们是圆形的(或者小于矩形的),比如球,小行星,或者任何其他的极端angular落通常都是透明的形状,你可能会发现这个高效的例程是最准确的。
但是为了清楚起见,这里是一个更完全实现的代码版本:
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和宽度值
hittest.js; 检测两个透明PNG图像(像素)的碰撞。 演示和下载链接
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 }