我正在尝试编写一个非常精简的简单对撞机,类似于Box2D--没有所有的物理,旋转等。我这样做是为了保持代码足迹微小且易于理解,并且还要简单地学习内部这些事情的个人运作。
我要做的就是碰撞圆圈和线条,防止它们互相嵌入。
Box2D几乎完美地做到了这一点 - 非常微小的重叠!但是,当我编写自己的简单模拟器时,我会遇到很多重叠:。
当我使用Box2D运行相同的模拟时(这只是所有圆圈追逐屏幕中心的一个点),我在所有时间都没有看到可见的重叠。
在伪代码中,这就是我所做的:
For each Circle In List:
Determine who will collide with the circle in next step
Sort collisions by closest first
For each possible collision:
Add the unembed vector to the Circle's movement vector
...and then:
For each Circle In List:
At the movement to the circle
所以,如果圈子没有被推入其他任何东西,这也很有效。然而,当事情堆积起来时,它不起作用,我知道为什么 - 因为后来的圈子与早期的圈子没有结合,所以每个人都会推动和推挤,并且在模拟结束时,一些人被困在其他人中。非常有道理。
这是我困惑的地方: 接近我可以说,Box2D完全以相同的方式运行 - 完成可能的碰撞,相互之间的冲突。但Box2D永远不会像我一样重叠(或者让它们变得如此之小,以至于无关紧要)。
有人能告诉我我错过了哪一步吗?我可以做一些调整来改进一些事情(比如迭代一次又一次碰撞的人......但Box2D似乎没有做到这一点,我希望在保持代码轻快的同时理解。)
谢谢!
下面的相关实际代码:
aO->mPos = x,y of object
aO->mMove = x,y of movement this step
aO->mRadius = radius of object
aO->MovingBound() = bound of object including the move
void Step()
{
EnumList(MCObject,aO,mMovingObjectList)
{
mTree.GetAllNearbyObjects(aO->MovingBound().Expand(aO->mRadius/4),&aHitList);
aHitList-=aO; // Remove self from list
if (aHitList.GetCount()>0)
{
// Sort the collisions by closest first
if (mSortCollisions)
{
// Snip, took this out for clarity...
// It just sorts aHitList by who is closest
// to the current object
}
// Apply the unembedding
EnumList(MCObject,aO2,aHitList) CollideObjectObject(aO,aO2);
}
}
// Do the actual moves
EnumList(MCObject,aO,mMovingObjectList)
{
mTree.Move(aO->mProxy,aO->Bound(),aO->mMove);
aO->mPos+=aO->mMove;
aO->mMove=0;
}
}
void CollideObjectObject(MCObject* theO1, MCObject* theO2)
{
float aOverlap=gMath.DistanceSquared(theO1->mPos+theO1->mMove,theO2->mPos+theO2->mMove);
float aMixRadius=theO1->mRadius+theO2->mRadius;
if (aOverlap<=aMixRadius*aMixRadius)
{
Point aUnembed=(theO1->mPos-theO2->mPos);
float aUnembedLength=aMixRadius-sqrt(aOverlap);
aUnembed.SetLength(aUnembedLength);
float aMod=.5f;
if (theO2->mCollideFlags&COLLIDEFLAG_STATIONARY) aMod=1.0f;
theO1->mMove+=aUnembed*aMod;
}
}
答案 0 :(得分:2)
解决许多物体之间的碰撞是一个非常困难的问题,因为除了基本的碰撞数学之外,你还必须更加努力地解决来自近似求解器的数学误差的积累(现实世界中的物理学工作)基于整合,它规定了无限小的时间步长;而在我们的模拟中,我们通常每秒仅解决约60次。)
让我们来看看Box2D's constraint solver loop, located in b2island.cpp:在每一个世界步骤中,碰撞解析器不仅会运行一次。它将重复velocityIterations
次,在官方测试案例中通常设置为6或8.这也是你必须要做的事情。