2

静的なボールと動いているボールの間の衝突がいつ発生するかを見つけたいのですが、私が思いついたアルゴリズムでは衝突が検出されず、動いているボールが静的なボールを通過することがあります。動いているボールは重力の影響を受けますが、静止しているボールは影響を受けません。

ここに私の衝突検出コードがあります:

GLfloat whenSpheresCollide(const sphere2d &firstSphere, const sphere2d &secondSphere)
{
    Vector2f relativePosition = subtractVectors(firstSphere.vPosition, secondSphere.vPosition);
    Vector2f relativeVelocity = subtractVectors(firstSphere.vVelocity, secondSphere.vVelocity);

    GLfloat radiusSum = firstSphere.radius + secondSphere.radius;

    //We'll find the time when objects collide if a collision takes place

    //r(t) = P[0] + t * V[0]
    //
    //d^2(t) = P[0]^2 + 2 * t * P[0] * V[0] + t^2 * V[0]^2
    //
    //d^2(t) = V[0]^2 * t^2 + 2t( P[0] . V[0] ) + P[0]^2
    //
    //d(t) = R
    //
    //d(t)^2 = R^2
    //
    //V[0]^2 * t^2 + 2t( P[0] . V[0] ) + P[0]^2 - R^2 = 0
    //
    //delta = ( P[0] . V[0] )^2 - V[0]^2 * (P[0]^2 - R^2)
    //
    //  We are interested in the lowest t:
    //
    //t = ( -( P[0] . V[0] ) - sqrt(delta) ) / V[0]^2
    //

    GLfloat equationDelta = squaref( dotProduct(relativePosition, relativeVelocity) ) - squarev( relativeVelocity ) * ( squarev( relativePosition ) - squaref(radiusSum)  );

    if (equationDelta >= 0.0f)
    {
        GLfloat collisionTime = ( - dotProduct(relativePosition, relativeVelocity) - sqrtf(equationDelta) ) / squarev(relativeVelocity);

        if (collisionTime >= 0.0f && collisionTime <= 1.0f / GAME_FPS)
        {
            return collisionTime;
        }
    }

    return -1.0f;
}

そして、衝突検出を呼び出す更新関数は次のとおりです。

void GamePhysicsManager::updateBallPhysics()
{
    //
    //Update velocity
    vVelocity->y -= constG / GAME_FPS;  //v = a * t = g * 1 sec / (updates per second)

    shouldApplyForcesToBall = TRUE;

    vPosition->x += vVelocity->x / GAME_FPS;
    vPosition->y += vVelocity->y / GAME_FPS;

    if ( distanceBetweenVectors( *pBall->getPositionVector(), *pBasket->getPositionVector() ) <= pBasket->getRadius() + vectorLength(*vVelocity) / GAME_FPS )
    {
        //Ball sphere
        sphere2d ballSphere;
        ballSphere.radius = pBall->getRadius();
        ballSphere.mass = 1.0f;
        ballSphere.vPosition = *( pBall->getPositionVector() );
        ballSphere.vVelocity = *( pBall->getVelocityVector() );


        sphere2d ringSphereRight;
        ringSphereRight.radius = 0.05f;
        ringSphereRight.mass = -1.0f;
        ringSphereRight.vPosition = *( pBasket->getPositionVector() );
        //ringSphereRight.vPosition.x += pBasket->getRadius();
        ringSphereRight.vPosition.x += (pBasket->getRadius() - ringSphereRight.radius);
        ringSphereRight.vVelocity = zeroVector();


        GLfloat collisionTime = whenSpheresCollide(ballSphere, ringSphereRight);

        if ( collisionTime >= 0.0f )
        {
            DebugLog("collision");
            respondToCollision(&ballSphere, &ringSphereRight, collisionTime, pBall->getRestitution() * 0.75f );
        }

        //
        //Implement selection of the results that are first to collide collision

        vVelocity->x = ballSphere.vVelocity.x;
        vVelocity->y = ballSphere.vVelocity.y;

        vPosition->x = ballSphere.vPosition.x;
        vPosition->y = ballSphere.vPosition.y;
    }

100% のケースで衝突が検出されないのはなぜですか? 70% のケースでしか検出されていません。ありがとう。

更新: FPS を 30 から 10 に変更すると問題が解決するようです。FPS は衝突検出にどのように影響しますか?

4

2 に答える 2

1
delta = ( P[0] . V[0] )^2 - V[0]^2 * (P[0]^2 - R^2)

それはdelta = b 2-4 acであるべきではありませんか?


[編集]ああ、なるほど、あなたは4つを因数分解しました。その場合、tの両方のソリューションを検討していると思いますか?

t = ( -( P[0] . V[0] ) - sqrt(delta) ) / V[0]^2

t = ( -( P[0] . V[0] ) + sqrt(delta) ) / V[0]^2
于 2010-01-15T18:42:54.617 に答える
1

球体の大きさと速さは?球体は、フレーム中に 2 番目の球体を「ジャンプ」できますか (つまり、速度ベクトルは幅よりも長いですか?)。

これらの線に沿って、ここで上限を削除するとどうなりますか:

if (collisionTime >= 0.0f && collisionTime <= 1.0f / GAME_FPS)
{
    return collisionTime;
}

球体の動きが速すぎる場合は、アルゴリズムが 1 フレーム以上前に発生した衝突を検出している可能性があります.. (?)

于 2010-01-15T17:51:09.370 に答える