c++ - 许多圆的类似于 Box2D 的碰撞

标签 c++ collision

我正在尝试编写一个类似于 Box2D 的非常精简、简单的碰撞器 - 缺少所有物理、旋转等。我这样做既是为了保持代码占用空间小且易于理解,也是为了简单地了解内部这些事情的运作都是个人的。

我想做的就是使圆和线碰撞,并防止它们相互嵌入。

Box2D 几乎完美地做到了这一点——非常少量的重叠!然而,当我编写自己的简单模拟器时,我得到了很多重叠:picture of overlapped circles .

当我使用 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;
}
}

最佳答案

解决许多对象之间的碰撞是一个相当困难的问题,因为除了碰撞的基本数学之外,您还必须更加努力地修复来自近似求解器的数学误差的累积(现实世界中的物理工作)基于积分,它规定了无限小的时间步长;而在我们的模拟中,我们通常每秒只求解大约 60 次)。

让我们看看Box2D's constraint solver loop, located in b2island.cpp :在每个世界步骤中,碰撞解析器不仅仅运行一次。它将重复 velocityIterations 次,在官方测试用例中通常设置为 6 或 8。这也是您必须做的。

关于c++ - 许多圆的类似于 Box2D 的碰撞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41902594/

相关文章:

c++ - 'C' 程序 : multidimensional array issue

C++ 模板实例化 - 与 STL 不同,为什么我的模板实例化必须始终是显式的?

java - 二维网格中对象的碰撞处理

python - Pygame 碰撞仅作用于一个对象

java - android中如何检测两条路径是否相交?

c++ - 每个Windows服务都会调用其可执行的main函数吗?

c++ - 在桌面上创建一个按钮

c++ - 将字符串拆分为两个不同的 vector C++

java - 碰撞检测和 react java

ios - 与顶部和底部碰撞但不与侧面碰撞? (iOS 8)