我知道有很多关于碰撞检测的帖子,一般是关于在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;
}
答案 0 :(得分:3)
将您的窗口细分为w
个h
块。您将按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个圈子,你不会通过使用更高级的算法或数据结构(例如quadtree或kd-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移动一些随机距离,这样如果没有必要,你的所有新圈子都不必与现有的圈子相邻。