Kollisionerkennung



  • Guten Abend,

    ich muss eine Simulation für Mehrkörperstöße schreiben in C++. Nun habe ich schon einiges geschafft, aber mir will es nicht kollidieren.

    So direkt mal etwas Code:

    //Hauptschleife	
    while(true)
    	{
    		fTime+=1.0f;
    		pApp->Loop();
    
    		if(BallPhysics::IsKollisionBall(pBall1, pBall2) == false)
    		{
    			pBall1->Update(fTime);
    			pBall2->Update(fTime);
    		}
    		else
    		{
    			BallPhysics::Kollision(pBall1, pBall2, fTime);
    			pBall1->Update(fTime);
    			pBall2->Update(fTime);
    		}
    
    		pApp->DrawLinie(pBall1->GetXFirstPosition(), pBall1->GetYFirstPosition(), pBall1->GetXPosition(), pBall1->GetYPosition(), BLACK);
    		pApp->DrawLinie(pBall2->GetXFirstPosition(), pBall2->GetYFirstPosition(), pBall2->GetXPosition(), pBall2->GetYPosition(), RED);
    	}
    

    Hier wird alles zusammengebracht.

    Hier mein Code zur Kollisionerkennung:

    bool IsKollisionBall(CBall* A, CBall* B)
    {
    	//Es muss gelten d <= R_1 + R_2 (d: Abstand der Mittelpunkte der Kreise)
    	//d^2 = Delta(y)^2 + Delta(x)^2
    	//Delta(y) = y_1 - y_2, Delta(x) = x_2 - x_1
    	float fX = B->GetXPosition() - A->GetXPosition();
    	float fY = A->GetYPosition() - B->GetYPosition();
    
    	float fDis = sqrt(fX*fX + fY*fY);
    
    	if(fDis < (A->GetRadius() + B->GetRadius()))
    	{
    		return true;
    	}
    	else if(fDis == (A->GetRadius() + B->GetRadius()))
    	{
    		return true;
    	}
    	else if(fDis > (A->GetRadius() + B->GetRadius()))
    	{
    		return false;
    	}
    }
    

    Hintergrund ist halt, dass der Abstand zwischen den beiden Mittelpunkte der Kugeln gleich kleiner der Summe der beiden Radien sein sollte damit die kollidieren.
    Es ist halt eingestellt, dass Kugel 1 mit x = 0 und y = 300 und Kugel 2 mit x = 300 und y = 300 ihre Position haben aber sollten sie schon nach einer Zeit kollidieren, aber das tut es nicht!

    Hier noch die Update Methoden von CBall:

    void CBall::Update(float fTime)
    {
    	//Geschwindigkeit = Beschleunigung * Zeit = (F / m) * t
    	m_fXSpeed += (m_fXForce / m_fMass) * fTime;
    	m_fYSpeed += (m_fYForce / m_fMass) * fTime;
    
    	//Bewegung = Geschwindigkeit * Zeit
    	m_fXPosition += (m_fXSpeed * fTime);
    	m_fYPosition += (m_fYSpeed * fTime);
    }
    

    und was passiert wenn beide Kugeln kollidieren:

    void Kollision(CBall* A, CBall* B, float fTime)
    {
    	//v_12 = (m_1 - m2) / (m_1 + m_2) * v_11
    	//v_22 = 2*m_1 / (m_1 + m_2) * v_11
    	//Geschwindigkeit von Ball A überträgt sich auf Ball B, durch Impuls- und Energieerhaltung
    	//Da m und R gleich sind, ist v_12 = 0 und v_22 = v_11
    	//F=m*a = m*v/t
    	B->SetSpeed(A->GetXSpeed(), A->GetYSpeed());
    	float fXAcc = A->GetXSpeed()/fTime; 
    	float fYAcc = A->GetYSpeed()/fTime; 
    	B->SetFirstForce(fXAcc, fYAcc);
    
    	//Geschwindigkeit von Ball A ist gleich Null
    	A->SetSpeed(0, 0);
    	A->SetFirstForce(0, 0);
    }
    

    Physikalisch gilt halt nach Energie- und Impulserhaltung, dass die erste Kugeln nach der Kollision halt die Geschwindigkeit 0 hat und die zweite Kugel die Geschwindigkeit von Kugel 1 vor der Kollision (Natürlich gilt das nur, wenn beide Radien und Massen gleich sind, aber das ist hier der Fall).

    Ich hoffe ihr sieht wo mein Problem ist, da ich nicht mehr weiter weiß warum mit die Kollisionerkennung nichts als false ausgibt.



  • 1. Bist du in einem völlig falschen Forum. Hier geht es um Standard C++ Fragen und nicht um andere Probleme. Dafür gibt es die anderen Unterforen..

    2. Erklärst du überhaupt nicht, wo genau dein Problem ist. Findet die Kollision nicht statt? Stimmen nach der Kollision die Werte nicht? Bewegen sich die Bälle nicht? usw.

    3. Kleine, gänige Optimierung

    bool IsKollisionBall(CBall* A, CBall* B)
    {
        //Es muss gelten d <= R_1 + R_2 (d: Abstand der Mittelpunkte der Kreise)
        //d^2 = Delta(y)^2 + Delta(x)^2
        //Delta(y) = y_1 - y_2, Delta(x) = x_2 - x_1
        float fX = B->GetXPosition() - A->GetXPosition();
        float fY = A->GetYPosition() - B->GetYPosition();
    
        float fDis = (fX*fX + fY*fY);
    
        if(fDis <= (pow(A->GetRadius(),2) + pow(B->GetRadius(),2) ) )
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    


  • Lemma 2.1.7
    Sei eine Abfrage nach folgendem Schema gegeben, wobei der Ausdruck "Bedingung" einen boolschen Wahrheitswert repräsentiert:

    if (Bedingung)
    {
        return true;
    }
    else
    {
        return false;
    }
    

    So lässt sich eine äquivalente Schreibweise finden, für die die gegebenen Gesetze in gleichem Masse gelten. Diese lautet:

    return Bedingung;
    

    Ein Beweis sei an dieser Stelle dem Leser überlassen.



  • drakon schrieb:

    3. Kleine, gänige Optimierung

    //(...)
        if(fDis <= (pow(A->GetRadius(),2) + pow(B->GetRadius(),2) ) )
        //(...)
    

    a² + b² != (a + b)²
    Und 2x pow() statt 1x sqrt() ist keine Optimierung.
    Also wenn dann

    //(...)
        float const rsum = fabs(A->GetRadius()) + fabs(B->GetRadius()); // fabs vermutlich überflüssig, Radien sollten ja nie negativ werden.. hm...
        float const rsumsquared = rsum * rsum;
        if (fDis <= rsumsquared)
        //(...)
    


  • 😮
    Ah mist. Ja, ich habe es eigentlich anders rum gemeint.. -.-

    Das pow war eigl. nur da, weil ich zu faul war das ganze nochmal hinzuklatschen, oder den Code oben in eine Variable zu packen..



  • Das Problem liegt darin, dass mit die Funktion IsKollisionBall kein true zurückgibt. Ich habe jetzt schon im paar Mal im Inet nachgeschaut, aber überall ist es gang und gäbe so die Kollisionserkennung zwischen zwei Kreisen zu machen.

    Und ich wusste selbst das sqrt ziemlich unoptimiert ist und man da lieber die Quadrate nehmen sollte, aber bevor man an die Optimierung denken sollte, muss es ja erstmal richtig funktionieren.



  • Dann schau da doch mal mit dem Debugger. Die Funktion sieht soweit richtig aus. Was jetzt halt sein könnte ist, dass die beiden übergebenen Zeiger nicht die richtigen sind. Oder die getter etwas falsches zurückgeben.

    Ich würde mal darauf tippen, dass die Werte, die du für x und y in Ball gespeichert hast nicht aktuell sind.

    Das ist jetzt etwas, was sehr gut mit dem Debugger überprüft werden kann. Schalt den einfach mal an, wenn du glaubst, dass eine Kollision stattfindet und überprüf die Werte.



  • Nun, ich habe das Problem selbst gelöst und zwar ist der Algorithmus zur Kollisionserkennung nicht gerade der beste ist.
    Das Problem liegt hier:

    float fX = B->GetXPosition() - A->GetXPosition();
        float fY = A->GetYPosition() - B->GetYPosition();
    
        float fDis = (fX*fX + fY*fY);
    

    Wenn nämlich fX negativ wird, wird durch das Quadrat das Vorzeichen zerstört und daher wird die kleiner gleich abfrage auch verfälscht.
    Übrigens bin ich selbst schon längst auf die Idee gekommen mit dem Debugger drüber zu schauen und wusste daher das die (x,y) Koordinaten und die Zeiger richtig sind.



  • Physiker04 schrieb:

    Wenn nämlich fX negativ wird, wird durch das Quadrat das Vorzeichen zerstört und daher wird die kleiner gleich abfrage auch verfälscht.

    Wie kann eine Distanz denn ein Vorzeichen haben?
    Wie hast du das Problem gelöst?


Anmelden zum Antworten