Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

physX

Treue Seele

  • »physX« ist der Autor dieses Themas

Beiträge: 119

Wohnort: Dresden

  • Private Nachricht senden

1

28.04.2009, 18:28

problem mit kollision in 2d

hallo, ich habe eine Kollisionsabfrage für meine Asteroiden geschrieben. Prinzipiell funktioniert aus alles. Nur relativ oft bleiben die Objekte aneinander "kleben" bzw. kreisen um sich rum.
Für den Kollision selbst verwende ich eine Abfrage im Sinne von Abstand der Mittelpunkte ist kleiner als die Summe der Radien. Das Bestimmen der Geschwindigkeitsvektoren nach dem Stoß ist soweit auch korrekt.

Das Problem (klebende Objekte) tritt meist dann auf, wenn mehr als zwei Objekte dicht beieinander sind, aber auch bei nur zwei nahegelegenen Objekten.

Ich habe schonmal probiert eine zusätzliche Bedingung an die Kollisionserkennung zu knüpfen, indem ich den Abstand der beiden Objekte aus den aktuellen Vektoren für den naechsten Frame im Voraus berechnen lasse und die Kollisionserkennung übergehe, wenn die Objekte im naechsten Frame noch zu nahe beienander wären, um mir so sozusagen etwas Zeit zu verschaffen. Das funktioniert leider nicht für alle Fälle und ich möchte auch nicht zuviele Frames vorausinterpolieren, um nicht die eigentlich Kollisionserkennung voellig aus den Angeln zu heben.

Gibt es hier noch weitere Ansätze, was man hier machen könnte? Vielleicht hat hier ja noch einer eine Idee, die mir weiterhelfen könnte.
Danke schonmal.
gruss

2

28.04.2009, 18:28

Code wäre sicher nicht unbehilflich.

physX

Treue Seele

  • »physX« ist der Autor dieses Themas

Beiträge: 119

Wohnort: Dresden

  • Private Nachricht senden

3

28.04.2009, 18:40

Zitat von »"Koerperkarle"«

Code wäre sicher nicht unbehilflich.


hmm. mir geht es ja eher um einen prinzipiellen Ansatz zur Lösung des Problems. Die Kollisionserkennung selbst arbeitet schon richtig, nur kommt es eben manchmal zu "eingefangenen" Objekten.
Trotzdem hier mal die wichtigsten Zeilen:

Bestimmung ob es eine Kollision gab:
es werden 2schleifen durchlaufen für ItAsteroid und It2Asteroid; dargestellt ist nur die 2.Schleife:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
            for (It2Asteroid=m_AsteroidList.begin();It2Asteroid!=m_AsteroidList.end();It2Asteroid++)
            {
                    //Prüfe ob Object aus Liste eins identisch mit Objekt aus Liste 2 

                    //und ob Objekt bereits auf Kollision überprüft wurde

                    if (ItAsteroid!=It2Asteroid && !ItAsteroid->Checked())
                    {
                        sf::Vector2f r1=It2Asteroid->GetElement()->GetPosition(); //Ortsvektor r1

                        sf::Vector2f dr=r2-r1; //Abstandsvektor

                        float dsquare=(dr.x*dr.x+dr.y*dr.y); //Abstand der Mittelpunkte zum Quadrat

                        //Bestimmung des Quadrat der Summe der Radien

                        float RSq=(It2Asteroid->GetElement()->GetRadius()+ItAsteroid->GetElement()->GetRadius())
                            *(It2Asteroid->GetElement()->GetRadius()+ItAsteroid->GetElement()->GetRadius());
                        //prüfe Kollisionsbedingung

                        if (dsquare<=RSq)
                        {
                            // bei Kollision Berechne neue Geschwindigkeitsvektoren

                            ItAsteroid->GetElement()->UpdateDynamics(It2Asteroid->GetElement());
                            // Objekt wird als kollidiert markiert

                            It2Asteroid->SetCheck(true);
                        }
                    }
                    
            }


Berechnung der Geschwindigkeitsvektoren bei Kollision:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void CElement::UpdateDynamics(CElement *pElement2)
{
        sf::Vector2f dR=m_vPosition-pElement2->GetPosition();
        sf::Vector2f V1=m_vVelocity;
        sf::Vector2f V2=pElement2->GetVelocity();
        float m1=m_fMass;
        float m2=pElement2->GetMass();
        float L=sqrt(dR.x*dR.x+dR.y*dR.y);
        // Matrix mit neuen Koordinatenachsen (parallel/senkrecht zum Stoss)

        float M11=dR.x/L;
        float M12=-dR.y/L;
        float M21=dR.y/L;
        float M22=dR.x/L;
        // Koordinatentransformation

        float Vp1=V1.x*M11+V1.y*-M12;
        float Vs1=V1.x*-M21+V1.y*M22;
        float Vp2=V2.x*M11+V2.y*-M12;
        float Vs2=V2.x*-M21+V2.y*M22;
        float Vp1_,Vp2_;
        // Zentraler Stoss

        float M=m1+m2;
        Vp1_=(m1-m2)/M*Vp1+2.0f*m2/M*Vp2;
        Vp2_=(m2-m1)/M*Vp2+2.0f*m1/M*Vp1;
        // Rücktransformation

        V1.x=Vp1_*M11+Vs1*M12;
        V1.y=Vp1_*M21+Vs1*M22;
        V2.x=Vp2_*M11+Vs2*M12;
        V2.y=Vp2_*M21+Vs2*M22;
        SetVelocity(V1);
        pElement2->SetVelocity(V2);
}
[/cpp]

4

29.04.2009, 08:37

bloß ne vermutung, aber kann es sein, dass die, wenn die praktisch ineinander kleben, immer wieder kollidieren? du musst demnach verhindern, dass objekte nach der kollision sich noch berühren / überlappen

physX

Treue Seele

  • »physX« ist der Autor dieses Themas

Beiträge: 119

Wohnort: Dresden

  • Private Nachricht senden

5

29.04.2009, 09:17

Zitat von »"WarMuuh!!"«

bloß ne vermutung, aber kann es sein, dass die, wenn die praktisch ineinander kleben, immer wieder kollidieren? du musst demnach verhindern, dass objekte nach der kollision sich noch berühren / überlappen


Genau. Dazu fehlt mir aber ein guter Ansatz, vielleicht hat ja hier noch einer eine gute Idee dazu
Gruss

babelfish

Alter Hase

Beiträge: 1 222

Wohnort: Schweiz

Beruf: Informatiker

  • Private Nachricht senden

6

29.04.2009, 10:06

Entweder lässt du es gar nicht so weit kommen (Also vor dem Bewegen die Kollision überprüfen) oder du stosst sie sozusagen auseinander. Das wären mal ganz grobe Ansätze :P

physX

Treue Seele

  • »physX« ist der Autor dieses Themas

Beiträge: 119

Wohnort: Dresden

  • Private Nachricht senden

7

29.04.2009, 10:42

Zitat von »"babelfish"«

Entweder lässt du es gar nicht so weit kommen (Also vor dem Bewegen die Kollision überprüfen) oder du stosst sie sozusagen auseinander. Das wären mal ganz grobe Ansätze :P


Den ersten Fall hab ich bereits so eingebaut, also Kollisionsabfrage vor der eigentlich Bewegung. Deinen zweiten Vorschlag könnte ich mir so vorstellen, dass ich die Bewegung im aktuellen Frame kurz etwas beschleunige um aus dem Einfangbereich zu kommen bzw. ein Delta zum Ortsvektor dazurechne.

Das Einfangen passiert offenbar immer dann, wenn:

a) neue Objekte innerhalb des Radius gespawned werden --> hab ich bereits beim Spawn durch eine Abfrage geändert.

b) die kollidierenden Objekte sehr ähnliche Geschwindigkeitsvektoren haben: gleiche Richtung bzw. sehr kleiner Winkel der Vektoren zueinander und der Abstander der Objekte beträgt etwa die Summe der Radien;

zu b) muesste eine Abfrage der differenz der jeweiligen Komponenten der Vektoren genügen. Eventuell reicht dann eine kleine zusätzliche Vektorkomponente senkrecht zum ürsprünglichen Geschwindigkeitsvektor bereits aus. probier ich heut abend mal aus.

gruss

8

29.04.2009, 11:11

Ein Ansatz wäre eventuell noch, die Bewegung nur zu verhindern, wenn der Abstand der Objektmittelpunkte kleiner wird. Also, wenn sie laut der Radienüberprüfung kollidieren, lässt du sie trotzdem laufen, wenn sie "auseinander" wollen.

physX

Treue Seele

  • »physX« ist der Autor dieses Themas

Beiträge: 119

Wohnort: Dresden

  • Private Nachricht senden

9

29.04.2009, 14:46

Zitat von »"ministry"«

Ein Ansatz wäre eventuell noch, die Bewegung nur zu verhindern, wenn der Abstand der Objektmittelpunkte kleiner wird. Also, wenn sie laut der Radienüberprüfung kollidieren, lässt du sie trotzdem laufen, wenn sie "auseinander" wollen.


Ja , das ist denke ich die einfachste und beste Lösung; hatte es bereits mal probiert, aber einen Fehler im Code mit eingebaut. jetzt versuch ich es mal folgendermaßen: (kann es aber leider erst heute abend ausprobieren) Denke sollte es funktionieren.

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
for (It2Asteroid=m_AsteroidList.begin();
     It2Asteroid!=m_AsteroidList.end();
     It2Asteroid++)
{
    //Prüfe ob Object aus Liste eins identisch mit Objekt aus Liste 2

    //und ob Objekt bereits auf Kollision überprüft wurde

    if (ItAsteroid!=It2Asteroid && !ItAsteroid->Checked())
    {
       sf::Vector2f r1=It2Asteroid->GetElement()->GetPosition();
       sf::Vector2f dr=r2-r1;
       
       // Bestimmung des Abstandes der Objekte beim naechsten Frame

       sf::Vector2f v1=It2Asteroid->GetElement()->GetVelocity();
       sf::Vector2f v2=ItAsteroid->GetElement()->GetVelocity();
       sf::Vector2f drN=dr+(v1-v2)*g_pScreen->GetFrameTime();
       //Abstand der Mittelpunkte zum Quadrat im nächsten Frame;

       float dsquareN=(drN.x*drN.x+drN.y*drN.y);
       //Abstand der Mittelpunkte zum Quadrat aktuell

       float dsquare=(dr.x*dr.x+dr.y*dr.y);

       //Bestimmung des Quadrat der Summe der Radien

       float RSq=(It2Asteroid->GetElement()->GetRadius()+
             ItAsteroid->GetElement()->GetRadius())*
             (It2Asteroid->GetElement()->GetRadius()+
             ItAsteroid->GetElement()->GetRadius());

       //prüfe Kollisionsbedingung und ob die Objekte

       //momentan aufeinanderzufliegen; Abstand dsquareN sollte dann 

       //kleiner sein als der Aktuelle Abstand

       if (dsquare<=RSq && (dsquareN<dsquare))
       {
       ItAsteroid->GetElement()->UpdateDynamics(It2Asteroid->GetElement());
       It2Asteroid->SetCheck(true);
       }
    }

}

10

29.04.2009, 15:40

http://uk.geocities.com/olivier_rebellion/Polycolly.zip

Lesen, verstehen und umsetzen.
If it were not for laughter, there would be no Tao.

Werbeanzeige