Algorithm 平面上非相交圆盘运动的路径生成 我在找什么
在一个平面上有300个或更少的等半径圆盘。在时间0时,每个制动盘处于一个位置。在时间1时,每个光盘处于可能不同的位置。我希望在0到1之间的时间内为每个光盘生成一个2D路径,这样光盘就不会相交,并且如果可能的话,路径相对有效(短)且曲率较低。(例如,直线比曲线更好)Algorithm 平面上非相交圆盘运动的路径生成 我在找什么,algorithm,language-agnostic,game-physics,computational-geometry,motion-planning,Algorithm,Language Agnostic,Game Physics,Computational Geometry,Motion Planning,在一个平面上有300个或更少的等半径圆盘。在时间0时,每个制动盘处于一个位置。在时间1时,每个光盘处于可能不同的位置。我希望在0到1之间的时间内为每个光盘生成一个2D路径,这样光盘就不会相交,并且如果可能的话,路径相对有效(短)且曲率较低。(例如,直线比曲线更好) 较低的计算时间通常比解的精确性更重要。(例如,一个小交叉点是可以的,我不一定需要一个最佳结果) 然而,光盘不应该互相传送、突然停止或减速、或突然改变方向——越“平滑”越好。唯一的例外是时间0和1 路径可以表示为采样形式或分段线性性质
- 较低的计算时间通常比解的精确性更重要。(例如,一个小交叉点是可以的,我不一定需要一个最佳结果)
- 然而,光盘不应该互相传送、突然停止或减速、或突然改变方向——越“平滑”越好。唯一的例外是时间0和1
- 路径可以表示为采样形式或分段线性性质(或更好)——我不担心通过样条曲线得到真正平滑的路径。(如果我需要的话,我可以估计一下。)
- Spektre已经实现了一个非常快速的RTS风格的单位移动算法,该算法运行良好。它的快速和优雅,但它也有RTS运动风格的问题:方向突然改变,单位可以突然停止以解决碰撞。此外,机组并非全部同时到达目的地,这本质上是一种突然停止。这可能是一个很好的启发式方法,可以创建可行的非平滑路径,之后可以及时对路径重新采样,并运行“平滑”算法(与我的演示中使用的算法非常相似)
- Ashkan Kzme认为问题可能与网络流量有关。看来,只要空间和时间能够以合理的方式被描述,并且运行时间能够被缩短,那么该方法是可行的。这里的优点是,这是一组经过充分研究的问题,但速度的突然变化仍然是一个问题,一些“平滑”的后期步骤可能是可取的。我目前遇到的一个障碍是决定一种时空的网络表示形式,它不会导致光盘通过彼此传送
- Jay Kominek发布了一个答案,使用非线性优化器优化二次Bezier曲线,获得了一些有希望的结果
- 处理每个光盘
- 将速度设置为
恒定*目的地\u矢量
- 乘法常数
a
- 然后将速度限制为恒定
v
- 乘法常数
- 测试新的迭代位置是否与任何其他光盘冲突
- 如果它确实在一个方向上旋转某个角度步进
ang
- 循环,直到找到自由方向或覆盖整圈
- 如果未找到自由方向,则将光盘标记为卡住
这是圆到反向圆路径的外观:
以下是随机到随机路径的情况:
卡住的光盘呈黄色(在这种情况下为无),且未移动的光盘已到达目的地如果没有路径,这也可能会卡住,就像光盘已经在目标圆中,而另一个目标圆中一样。为了避免这种情况,您还需要更换碰撞盘。。。您可以使用
常量制作不同的外观,还可以尝试随机角度旋转方向,以避免旋转/扭曲运动ang,a,v
这里是我使用的源代码(C++):
- 为了好玩,我们玩了一下,结果如下:
算法:
//---------------------------------------------------------------------------
常数int discs=23;//光盘数量
常数双盘_r=5;//圆盘半径
常数双圆盘直径=4.0*di
double errorf(unsigned n, const double *pts, double *grad,
void *data)
{
problem_t *setup = (problem_t *)data;
double error = 0.0;
for(int step=0; step<setup->steps; step++) {
double t = (1.0+step) / (1.0+setup->steps);
for(int i=0; i<setup->N; i++)
quadbezier(&setup->starts[2*i],
&pts[2*i],
&setup->stops[2*i],
t,
&setup->scratch[2*i]);
for(int i=0; i<setup->N; i++)
for(int j=i+1; j<setup->N; j++) {
double d = distance(&setup->scratch[2*i],
&setup->scratch[2*j]);
d /= RADIUS;
error += (1.0/d) * (1.0/d);
}
}
return error / setup->steps;
}