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

22.03.2010, 22:41

Problem: Sprite Kollisionsbehandlung

Hallo,

ich hänge nun doch schon seit einiger zeit an einem problem, das für mich aus rein logischer sicht gar nicht auftreten kann und da ich es wohl auch in den nächsten jahrzehnten nicht alleine hinkrigen werde, wollt ich hier um rat fragen :)

wie der titel schon sagt, geht es um 2d kollisionsbehandlung. um genau zu sein:
ich will, dass wenn ein sprite bewegt wird und das zielgebiet geblockt wird, dass es nicht bewegt wird, sondern an seiner position bleibt.

mein lösungsvorschlag war, dass ich das rect für die neue position "erzeuge", überprüfe, ob es damit eine kollision gibt und wenn ja, dann bewege das sprite nicht.

klingt einfach? dacht ich auch, aber funktionieren will es nicht :/

leider ist das ganze "etwas" umfangreicher. meine persönliche vermutung ist jedoch, dass vl in der rect klasse die intersect methode nicht 100% funktioniert?

zum testfall:
ich habe zwei sprites auf gleicher höhe und das rechte sprite bewegt sich automatisch auf das linke zu. solange das linke sprite ungefähr auf der höhe des rechten bleibt, funktioniert alles.
sobald es aber etwas unterhalb oder oberhalb ist, kann plötzlich das rechte sprite in das linke "eindringen". ich verstehe nicht warum und erbitte hiermit hilfe.



QuadTree.h
QuadTree.cpp

Rect.h

GameObject.cpp
Unit.cpp

Mainloop

die 2 sprites, von denen ich rede, sind in der mainloop, zeile 24 und 25 und werden in zeile 62 und 54 upgedated. mage->Update() erfolgt ebenfalls in einer game methode, wo lediglich abgefragt wird, welche taste gedrückt wird um das sprite vor dem update richtig zu drehen.

wie gesagt, meine vermutung wäre in rect.h in der intersect methode, aber die scheint mir zu passen.
sonst wäre noch in gameobject.cpp zeile 68 abwärts möglich. die zurückgegebenen objekte des quadtrees stimmen (also die elemente in vektor stimmen).


mit der hoffnung auf hilfe oder denkanstöße
Simon

NachoMan

Community-Fossil

Beiträge: 3 885

Wohnort: Berlin

Beruf: (Nachhilfe)Lehrer (Mathematik, C++, Java, C#)

  • Private Nachricht senden

2

22.03.2010, 23:42

bring doch erstmal ordnung in deine rect klasse... du hast das ganze unnötig kompliziert gemacht

die variablennamen solltest du ändern...

C-/C++-Quelltext

1
2
3
4
float left;
float top;
float right;
float bottom;


sry ich bin im moment total fertig. abgesehen von deinen verwirrenden variablennamen find keinen fehler :(
vllt morgen.

KeksX

Community-Fossil

Beiträge: 2 107

Beruf: Game Designer

  • Private Nachricht senden

3

23.03.2010, 00:43

Also von diesem Fehler lese ich häufiger ( hatte ich auch schon selbst ) und es hatte verschiedene Ursachen wie falsche Wertvergabe bzw. Überprüfung.
Also auf den ersten Blick würde ich vermuten, dass die Werte, die der Überprüfung übergeben werden, schlichtweg fehlerhaft sind. Überprüf doch mal in der Konsole, ob alle Werte stimmen.

----
Allerdings ist es doch eigentlich viel einfacher, die Werte des Rects zu haben und immer zu schauen, ob bei den verschiedenen Werten des Rects( + 1 ) eine Kollision stattfindet. Jedes Object hat halt entweder false oder true und das überprüfst du immer. Du holst dir das Rect des gegenüberliegenden Sprites und wenn da collision auf true ist, findet keine Bewegung statt bzw. wird das Sprite zurückgesetzt oder sonstiges.

Dafür reicht ein einfaches Rect, eine Funktion um sich Rects zu holen und ein paar if-Abfragen, der Rest ist dann unnötig.
WIP Website: kevinheese.de

4

24.03.2010, 18:31

@nachoman:
finde die varbezeichnung für mich so angenehmer. brauch ich immer nur .b schreiben für die rechten werte bzw .t für die linksseitigen werte und eben einmal pfeiltaste um zwischen x/y zu wechseln. ebenso find ichs so angenehmer zum lesen :P


wie auch immer:
habe jetzt einiges getestet. anstatt den sprites hab ich einfach weiße vierecke zeichnen lassen und vom mage rect und dem kollidierenden rect dauernd die werte ausgeben lassen, wenn es zu einer kollision kam.
"merkwürdigerweise" konnten die quadrate eben ineinander gehen, obwohl intersectswith true zurückgeben hätte müssen.
daraufhin entdeckte ich, dass beim "hineingehen" in andere quadrate die textausgabe gar nicht kam, was nur mehr auf einen fehler hinwies. die GetObjects methode des quadtrees liefert nicht alle objekte retour.

dem war dann auch so. denn das problem ist, dass ich einmal überprüfte, ob der punkt innerhalb einer node grenze lag (boundary) oder ob der abstand vom punkt zum mittelpunkt des nodes <= dem radius ist. und genau hier lag der fehler. denn wenn das magesprite z.b. mit der rechten kante innerhalb des quadtreenodes liegt, brauch ich natürlich auch die objekte dieses nodes. dies setzt jedoch nicht zwingend voraus, dass das sprite den mittelpunkt einschließt.

lange rede kurzer sinn:

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
46
47
48
49
// returns all objects within the radius of the given position

std::vector<GameObject*> QuadTree::GetObjects(float coordx, float coordy, float radius )
{
    std::list<QTNode*> nodes;
    nodes.push_back(root);
    std::vector<GameObject*> result;
    const Rect r2 = Rect( coordx-radius, coordy-radius, coordx+radius, coordy+radius );
        // radius *= radius

    
    for( std::list<QTNode*>::iterator it = nodes.begin(); it != nodes.end(); ++it )
    {
        for( int i=0; i<4; ++i )
        {
            QTNode* child = (*it)->child[i];
            const Rect r = child->boundary;
            bool collides = false;
            if( r.IsPointInside( coordx, coordy ) || r.IntersectsWithRect( r2 ) )
                collides = true;
            /*else
            {
                const float dx = coordx - r.GetCenterX();
                const float dy = coordy - r.GetCenterY();
                if( dx*dx+dy*dy <= radius )
                    collides = true;
            }*/

            if( collides )
            {
                if( child->type == QTNODE_TYPE_PARENT )
                    nodes.push_back( child );
                else
                {
                    std::vector<GameObject*> v = child->GetObjects();
                    if( !v.empty() )
                    {
                        for( std::vector<GameObject*>::iterator it = v.begin(); it != v.end(); ++it )
                        {
                            // add object to the result vector if it isn't in the result vector yet

                            if( std::find( result.begin(), result.end(), (*it) ) == result.end() )
                                result.push_back( (*it) );
                        }
                    }
                }
            }
        }
    }
    //nodes.clear();

    return result;
}   // end GetObjects


habe statt der radius abfrage einfach ein rect mit dem radius erstellt und überprüfe nun mit dem, ob der node wichtig ist oder nicht.


scheint jetzt soweit perfekt zu funktionieren.


ich weiß, schlecht erklärt, aber es ist auch etwas schwierig zum erklären^^

danke jedenfalls an keksx und nachoman

Werbeanzeige