圆形插入二维平面的快速碰撞检测

时间:2009-05-17 15:35:03

标签: algorithm collision-detection

我知道有很多关于碰撞检测的帖子,一般是关于在2D平面上移动的精灵,但我的问题略有不同。

我正在将圆圈插入2D平面。圆圈具有可变半径。我正在尝试优化我在平面内找到随机位置的方法,在那里我可以插入一个新的圆圈,而不会与平面上已有的任何其他圆相撞。现在我正在使用一种非“优化”的方法,只需在平面内生成一个随机点,然后将其与飞机上的所有其他圆圈进行对比。

有优化方法吗?对于这个特定的应用程序,平面的边界一次只能容纳20-25个圆圈,通常存在5-10个圆圈。正如您所期望的那样,当圆的数量接近可以适合的最大值时,您必须在找到有效点之前测试多个点。它变得非常慢。

注意:safeDistance是我想要添加到平面的圆的半径。

以下是代码:

- (CGPoint)getSafePosition:(float)safeDistance {
// Point must be far enough from edges
// Point must be far enough from other sprites

CGPoint thePoint;
BOOL pointIsSafe = NO;

int sd = ceil(safeDistance);

while(!pointIsSafe) {

    self.pointsTested++; // DEBUG

    // generate a random point inside the plane boundaries to test
    thePoint = CGPointMake((arc4random() % ((int)self.manager.gameView.frame.size.width - sd*2)) + sd, 
                           (arc4random() % ((int)self.manager.gameView.frame.size.height - sd*2)) + sd);

    if(self.manager.gameView.sprites.count > 0) {
        for(BasicSprite *theSprite in self.manager.gameView.sprites) {

            // get distance between test point and the sprite position
            float distance = [BasicSprite distanceBetweenPoints:thePoint b:theSprite.position];

            // check if distance is less than the sum of the min safe distances of the two entities
            if(distance < (safeDistance + [theSprite minSafeDistance])) {
                // point not safe
                pointIsSafe = NO;
                break;
            }

            // if we get here, the point did not collide with the last tested point
            pointIsSafe = YES;
        }
    }
    else {
        pointIsSafe = YES;
    }
}

return thePoint;
}

4 个答案:

答案 0 :(得分:3)

将您的窗口细分为wh块。您将按w h数组dist维护dist[x][y]dist[x][y]包含可以(x,y)居中的最大圆的大小。 (您可以将像素用作块,尽管我们将在放置每个圆的情况下更新整个阵列,因此您可能需要选择较大的块以提高速度,但会以略微降低的打包密度为代价。)

初始化

最初,将所有min(x, y, w - x, h - y)设置为(a, b)。这会对作为窗口的边界框给出的限制进行编码。

更新程序

每次向窗口添加一个圆圈时,假设一个圆圈位于r,半径为dist,则需要更新 (x, y)的所有元素。

每个职位dist[x][y] = min(dist[x][y], sqrt((x - a)^2 + (y - b)^2) - r); 所需的更新是:

^2

(显然,dist在这里意味着平方,而不是异或。)基本上,我们说:“将dist [x] [y]设置为刚放置的圆圈的最小距离,除非情况已经更糟比起那个来说。” <* 1}}刚刚放置的圆圈内的点数值为负值,但这并不重要。

查找下一个位置

然后,当您要插入下一个半径q的圆时,只需浏览dist,查找dist值&gt; = q的位置。 (如果要随机选择这样的位置,请找到有效位置的完整列表,然后随机选择一个。)

答案 1 :(得分:2)

老实说,只有20-25个圈子,你不会通过使用更高级的算法或数据结构(例如quadtreekd-tree)来提高速度。 Everything is fast for small n

您是否完全确定这是您应用程序的瓶颈?你介绍过吗?如果是,那么你要加快速度的方式是通过微优化,而不是通过高级算法。您是否在while循环中进行了大量迭代,因为大多数平面都不安全?

答案 2 :(得分:0)

您可以将平面分成许多小矩形(稍微quadtree - 相关)并保存哪个矩形被至少一个圆圈击中。 当你寻找一个插入点时,你只需要寻找一些“空”的(它不需要任何随机的跳跃,并且可以在恒定的时间内完成)。

矩形的数量和星座可以通过半径来计算。

答案 3 :(得分:0)

只是一个大纲,因为这个解决方案非常复杂。

如果您想保证在可能的情况下总能找到放置圆圈的位置,您可以执行以下操作。考虑每个现有的圆C.我们将尝试找到一个位置,我们可以放置新圆,使其接触C.对于每个圆D(除了C)足够接近C,将有一系列角度在C周围的一个角度放置一个新圆圈将使其与D相交。某些几何图形将为您提供该范围。类似地,对于足够接近C的四个边界中的每一个,将存在一系列角度,其中将新圆放置在这些角度中的一个处将使其与边界相交。如果所有这些间隔都覆盖C周围的所有360度,那么你不能在C附近放置一个圆圈,你将不得不尝试下一个圆圈,直到没有更多的候选人为C.如果你找到一个放置新圆圈的地方,你可以将它从C移动一些随机距离,这样如果没有必要,你的所有新圈子都不必与现有的圈子相邻。