碰撞检测算法

时间:2013-10-21 17:36:38

标签: javascript algorithm collision-detection

我有一个问题我正在尝试解决,我有一个点我正在尝试检查碰撞的列表,我有一般的想法可能使用一些pytagoras,但我的主要问题是效率的算法,因为我需要检查是否只有一个轴的矩形相交,假设我有一个矩形点(0,100),其他点(300,100),两者都在y = 100,所以我的应用程序我决定他们碰撞了,现在我怎么检查其中任何一个是否与其他任何一个碰撞?

我的第一次尝试是对我添加的每个矩形进行循环检查,如果新的矩形与其余的冲突,但我认为是错误的,因为如果我有100个rects,我将需要检查第一次碰撞其他99,如果他们与其他人发生碰撞,他们每个人都会。

我很确定循环会以指数方式增加,所以有人可以指出我正确的方向如何才能成为最有效的检查方式,谢谢!

编辑22-oct-13 使用@John Phu Nguyen函数

var events = [ {start: 30, end: 150}, {start: 540, end: 600}, {start: 560, end: 620}, {start: 610, end: 670} ];
//each start and end props are y coordinates, basically where the rect start and ends
function layOutDay(events) {
    //console.log(events);

    var events_container = document.querySelector('.events-col');
    var frag = document.createDocumentFragment();
    for(var i=0; i<events.length; i++){
        //console.log(events[i].start);
        var top = events[i].start;
        var bottom = events[i].end-events[i].start;

        var event = createEventDOM();
        var gutter = event.querySelector('.gutter');

        event.style.top = top + 'px';
        event.style.height = gutter.style.height = bottom + 'px';

        if(y_coords.indexOf(top) === -1 && y_coords.indexOf(bottom) === -1){
            y_coords.push(top);
            y_coords.push(bottom);

            y_coords.sort();

            event.style.left = '10px';
            console.log('NO collision', top, bottom);
        }else{
            console.log('collision', top, bottom);
            event.style.width = '250px';
            event.style.left = '220px';
        }

        frag.appendChild(event);
    }

    events_container.appendChild(frag);
}

所以运行我得到的函数有2个碰撞,但是有3个不是2,我需要知道谁在x轴上相互移动了相互作用的人!

Here is a screenshot of what I'm trying to do

可能是一个调整,但我找不到它,任何帮助都非常感谢,谢谢!

2 个答案:

答案 0 :(得分:2)

循环不会以指数方式增加,而是以二次方式增加,这可能仍然很糟糕。

有几种解决方案,具体取决于移动的矩形数量以及固定的矩形数量。

非常简单的解决方案是

  • 构建一个NxN单元网格,其中每个单元格可以包含一个接触单元格的矩形列表
  • 在矩形上循环,并为每个矩形将矩形放在他们触摸的每个单元格的列表中。这样做时,您还可以检查矩形是否与单元格列表中的其他矩形发生碰撞。

移动矩形时,此网格数据结构很容易维护更新:只需将其从当前列表中删除,然后将其插入新位置列表中即可。

什么是最佳N实际取决于应用程序。

答案 1 :(得分:1)

如果您只想检查沿轴的各个点,则排序列表可以正常工作。

在Javascript中:

//Existing points:
var x_coords = [0, 20, 310, 400];
var y_coords = [0, 50, 100, 500];

//New point
x_new = 300;
y_new = 100;

//Check for collision
if(x_cords.indexOf(300) == -1 && y_cords.indexOf(100) == -1) 
{
    //No collision, add to list
    //Add another point
    x_coords.push(300);
    x_coords.push(100);

    //Sort list, complexity should be low if sorted after every insert
    x_coords.sort();
    y_coords.sort();
}

如果您正在寻找范围内的碰撞,

x_cords.indexOf( 100 )
x_cords.indexOf( 200 )

将为您提供值100和200的索引。该范围内的任何内容都将出现在排序列表中的这两个索引之间。


其他信息:

'bottom'目前是元素高度,而不是底部。 if语句应该是:

if(y_coords.indexOf(top) === -1 && y_coords.indexOf(end) === -1)

但是,这仍然不会产生任何结果,因为indexOf()函数专门查找某个值,而不是某些值之间存在值。

为此,您可以使用列表理解:

elements_between_y100_and_y300 = [i for i in y_cords if (i >= 100 && i <=300)]

如果列表返回空,则表示没有冲突。

为了找出碰撞的元素,您很可能必须保留一个单独的列表,例如: element_at[200] = 2