2010-01-15 18 views
2

Je veux trouver quand une collision entre une balle statique et une balle en mouvement se produit, mais l'algorithme que je suis venu, parfois ne détecte pas une collision et la balle en mouvement passe par la statique. La balle en mouvement est affectée par la gravité et la balle statique ne l'est pas.simple problème de collision 2d

Voici mon code de détection de collision:

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; 
} 

Et voici la fonction de mise à jour qui appelle la détection de collision:

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; 
    } 

Pourquoi ne pas la collision détectée dans 100% des cas? Il n'est détecté que dans 70% des cas. Merci. MISE À JOUR: Le problème semble être résolu lorsque je change FPS de 30 à 10. Comment FPS affecte-t-il ma détection de collision?

+1

Eh bien dans ce cas, essayez de régler le FPS très élevé et le débogage de la ligne par ligne programme, en regardant attentivement la façon dont les variables valeurs coïncident avec ce que vous pensez qu'ils devraient être. –

+0

Pouvez-vous fournir plus de détails sur la fonction respondToCollision? Spécifiquement, recourt-il pour détecter une collision ultérieure avec un tiers? Comment gérez-vous plusieurs collisions dans un cadre? – markets

Répondre

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

Si pas être delta = b - ac?


[Modifier] Oh, je vois, vous le 4 factorisation out. Dans ce cas, êtes-vous sûr de considérer les deux solutions?

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

et

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

J'utilise une formule alternative qui peut être utilisée lorsque le coefficient avant x est pair. –

+0

Je ne considère qu'une seule solution - le moins de temps. Je ne m'intéresse pas au temps le plus long car il se produira lorsque la distance entre les objets sera de 0 pour la deuxième fois (la collision elle-même se produit pour un temps moindre). –

+0

Cela peut très bien être dû à des erreurs d'arrondi - le programme s'attend à ce que la collision se produise à la prochaine image, mais, en raison de légères erreurs d'arrondi, la collision devrait déjà avoir eu lieu à la trame suivante. Essayez de remplacer vos 'floats' par' doubles', ou faites que la collision arrive quelques images plus tôt (remplacez 'collisionTime <= 1.0f/GAME_FPS' avec, par exemple,' collisionTime <= 1.9f/GAME_FPS') –

1

Quelle est la taille de la sphère et à quelle vitesse se déplacent-elles? Une sphère peut-elle "sauter" par-dessus la seconde pendant une image (c'est-à-dire, est-ce que son vecteur de vélocité est plus long que sa largeur?).

Le long de ces lignes, ce qui se passe si vous supprimez la limite supérieure ici:

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

Si la sphère se déplaçait trop vite, peut-être votre algorithme détecte une collision qui a eu lieu il y a plus d'un cadre .. (?)

+0

Les sphères ont approximativement la même taille. Généralement, cette limite supérieure définit si la collision se produira pendant la trame suivante. Si oui, il signale une collision. –