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

1

03.04.2014, 11:38

Kollision-Problem

Hallo miteinander

Ich habe erneut ein Problem mit der Kollision, dachte ich hätte es verstanden aber anscheinend noch nicht ganz.
An meinem aktuellen Projekt, ein Ping Pong Spiel hat der Spieler einen Balken am unteren Bildschirmrand von links nach rechts zu bewegen.
Ein Ball wird in der Mitte des Bildschirmes geladen und erhält zufällige Velocity für X und Y. Das Ziel ist es nun als Spieler mithilfe des Balkens den Ball
in die Richtung der Klötze zu zielen um das Level zu beenden.

Nun die Kollision SpielerBall hat zu einem früheren Zeitpunkt mal funktioniert. Mittlerweile ist dies nicht mehr der Fall. Geändert hat sich, dass ich mit einer *.xml Datei
nun die ganze Welt inklusive alle Objekte lade. Dies funktioniert auch problemlos. Im CollisionsManager verwalte ich alle Kollisionen. Aktuell habe ich nur die folgende 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
32
33
34
35
void CollisionManager::checkPlayerBallCollision (const vector<GameObject*> &objects)
{
    SDL_Rect* pRect1 = new SDL_Rect();
    SDL_Rect* pRect2 = new SDL_Rect();

    for(int i = 0; i < objects.size(); i++)
    {
        if(objects[i]->getTextureID() == "ball")
        {
        pRect1->x = objects[i]->getPosition().getX();
        pRect1->y = objects[i]->getPosition().getY();
        pRect1->w = objects[i]->getWidth();
        pRect1->h = objects[i]->getHeight();
        }
        
        if(objects[i]->getTextureID() == "player")
        {
        pRect2->x = objects[i]->getPosition().getX();
        pRect2->y = objects[i]->getPosition().getY();
        pRect2->w = objects[i]->getWidth();
        pRect2->h = objects[i]->getHeight();
        }
        
    }

    if(RectRect(pRect1, pRect2) == true)
    {
        cout << "Collision detected" << endl;
        Ball().collision();
    }
    
    delete pRect1;
    delete pRect2;

}


Anhand dieser Funktion werden mittels dem Vector alle GameObjekte angesteuert. Nachdem 2x Rect erstellt wurden, wird mit einer Schleife und mithilfe der getTextureID die gewünschten Objekte identifiziert und Werte für die Rects zugeordnet. Dies funktioniert auch, zumindest wenn ich einen Breakpoint vor der Funktion if(RectRect...) setze sehe ich dass alle Werte zugeteilt wurden und auch stimmen. Nun folgt die eigentliche Kollisionsabfrage, welche in einer anderen Datei namens Collision.hpp liegt:

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
38
39
40
41
42
43
44
45
bool RectRect(SDL_Rect* a, SDL_Rect* b)
{
    //The sides of the rectangles
    int leftA, leftB;
    int rightA, rightB;
    int topA, topB;
    int bottomA, bottomB;
    
    //Calculate the sides of rect A
    leftA = a->x;
    rightA = a->x + a->w;
    topA = a->y;
    bottomA = a->y + a->h;
    
    //Calculate the sides of rect B
    leftB = b->x;
    rightB = b->x + b->w;
    topB = b->y;
    bottomB = b->y + b->h;

    //If any of the sides from A are outside of B
    if( bottomA <= topB )
    {
        return false;
    }
    
    if( topA >= bottomB )
    {
        return false;
    }
    
    if( rightA <= leftB )
    {
        return false;
    }
    
    if( leftA >= rightB )
    {
        return false;
    }
    
    //If none of the sides from A are outside B
    return true;

}


Auch hier sehe ich wenn ich im Spiel bin, dass sobald der Ball über dem Spieler ist, dass in der Konsole "Collision detected" angezeigt wird und zwar mindestens 20x. Die letzte Funktion welche nun bei der Kollision aufgerufen wird ist Ball().collision();

C-/C++-Quelltext

1
2
3
4
void Ball::collision()
{
   m_velocity.setY(m_velocity.getY() * (-1));
}


Zuletzt werden in der GameObjekt Datei ständig nach Kollision gefragt:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
void ObjectLayer::update()
{
    
    for (int i = 0; i < m_gameObjects.size(); i++)
    {
        m_gameObjects[i]->update();
        g_pCollisionManager->checkPlayerBallCollision((const vector<GameObject*>&)m_gameObjects);
    }
    
    
}


Ich verstehe es einfach nicht, aber die Kollision funktioniert nicht mehr ... der Ball geht einfach durch den Spieler durch und gar nichts passiert obwohl in der Konsole eine Kollision delektiert wurde!

Danke im Voraus!

Eric

2

03.04.2014, 12:15

Du sagst es wird 20x die collision detected?

Überlege mal was passiert wenn 2x detected wird besonders in Bezug auf deine Rechnung in Ball::collision.


Gruß Koschi
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

3

03.04.2014, 12:20

Ich habe mir das auch überlegt, mir ist jedoch noch unklar ob dies das Problem ist.

Auch wenn ich z.B.

C-/C++-Quelltext

1
2
3
4
5
void Ball::collision()
{
   m_position.setX(30);
   m_position.setY(30);
}


verwendet habe, ist nichts passiert!

Falls ja, wie würde ich das lösen können, dass es nur einmalig durchlaufen soll?

4

03.04.2014, 12:31

Einfachste wäre wohl ein Flag zu setzen in Ball m_collision = true;
Solange der True ist gibt kein richtungs Wechsel
Wird keine Kollision mehr detected wird der flag wieder auf false gesetzt.

Allerdings bin ich mir nicht sicher ob die rectrect-Funktion wirklich das macht was sie soll.d
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

5

03.04.2014, 12:59

Danke Koschi für deine Antwort! Leider konnte ich das Problem so nicht lösen.

Ich habe mittlerweile herausgefunden, dass aus irgendeinem Grund bei der Kollision alle Werte auf 0 gesetzt werden (wenn ich einen Breakpoint in die Collision-Funktion lege), der Ball aber trotzdem einfach
weiter fliegt. Ich blicke einfach nicht durch ...

6

03.04.2014, 13:12

Koschi danke für deine Hilfe, dass mit dem Flag hat doch geholfen und es funktioniert jetzt.
Ich musste in der update()-Funktion des Balles folgendes hinzufügen:

C-/C++-Quelltext

1
2
3
4
5
if (g_pCollisionManager->getCollision() == true)
    {
        collision();
        g_pCollisionManager->setCollision();
    }


und die Collision von dort aus steuern.

Im CollisionsManager wurde folgendes geändert bei Kollision (Flag wird auf true gesetzt --> Also Kollision findet statt)

C-/C++-Quelltext

1
2
3
4
if(RectRect(pRect1, pRect2))
    {
        m_collision = true;
    }


Nur dann wird in der update()-funktion die if durchlaufen und die collision()-Funktion aufgerufen.
Mittels setCollision() wird die Flag zurück gesetzt auf false, da keine Kollision mehr.

Weshalb es vorher nicht funktioniert hat bleibt mir trotzdem ein Rätsel. Vielleicht kann ein Profi mir erklären weshalb ich es so lösen musste?

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

7

03.04.2014, 14:01

Das riecht aber eher danach, dass Du irgendwo eine Kopie Deines Objekts übergibst und folglich in der ganz falschen Instanz agierst. Insgesamt finde ich Dein Zusammenspiel von Ball und CollisionManager ganz ganz schlecht. Die kennen sich beide gegenseitig und rufen gegenseitige Logik auf um sich gegenseitig zu beeinflussen. Wirklich, das solltest Du dringend ändern. Jeder sollte sein Ding machen und das war's.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

8

04.04.2014, 11:16

Danke für dein Feedback BlueCobold. Leider verstehe ich noch nicht genau was du meinst.
Findest du mein Lösungsansatz, welcher zu einer funktionierenden Kollision führte, schlecht? Oder findest du die Tatsache, dass ich einen CollisionsManager habe unnötig?
Ich wäre extrem froh, wenn ich dieses Problem gut beheben könnte, bin leider als Anfänger auf detaillierte Angaben angewiesen.
Falls möglich wäre ich um Details sehr froh.

9

04.04.2014, 12:29

Generell spricht es für schlechtes Klassendesign wenn 2 Klassen sich gegenseitig kennen.
In deinem Fall Ball und CollisionsManager.

Im Idealfall sollte nur die Managerklasse seine Objekte kennen die er verwaltet.
Das Objekt soll/darf/brauch seine Managerklasse nicht kennen.

Was bei dir wohl nicht der Fall ist.


Auf Grund deiner Fehlerbeschreibung "alles auf 0" weist Blue darauf hin das es auch sein kann das auf einer lokalen Kopie gearbeitet wird und somit dem Original die Änderung entgeht. Das kann sein wenn Parameter in einer Funktion nicht als Referenz oder Pointer übergeben werden.

Gruß Koschi
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Koschi« (04.04.2014, 18:35)


Werbeanzeige