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

11

07.12.2013, 14:53

Und irgendwie äußerst hässlich, dass Data 'polymorph' ist.

Durch virtuelle Funktionen kannst du polymorphe Objekte benutzen, ohne ihren Typ zu kennen. In diesem Beispiel ist das Problem, dass gleich 2 Objekte für die Kollision polymorph sind, aber man kann das z.B. so lösen:

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
bool BoxBox(*Box, *Box)
bool BoxSphere(...)
bool SphereSphere(...)

class Collider
{
bool CollideWith(Collider*)
};

class Box : public Collider
{
bool CollideWithBox(Box*, b)
{
  return BoxBox(this, b)
}

bool CollideWithSphere(Sphere*) ...
bool CollideWith(Collider* c) override
{
  c->CollideWithBox(this)
}

};

class Box : public Collider
{
bool CollideWithBox(Box*) ...
bool CollideWithSphere(Sphere*) ...
bool CollideWith(Collider* c) override ...
};


Du hast also 2 Funktionsaufrufe. Der erste 'sortiert' nach dem ersten Parametertyp, der zweite nach dem zweiten. Fortan hast du also nur noch 2 Colliderobjekte, von denen du gar nichts wissen musst, du kannst Collider1->CollideWith(Collider2) aufrufen und es wird automatisch die Richtige Routine aufgerufen die dann auch direkt einen konkreten Untertypen (Box oder Sphere) bekommt, mit dem sie arbeiten kann.

Ein Nachteil ist hier noch, dass du alles doppelt machen musst: Sphere/Box und Box/Sphere sind eben 2 unterschiedliche Fällt, weil die Box einmal der zweite und einmal der erste Parameter ist.

Beachte, dass der Code nur grob skizziert ist, aber ich hoffe man kann erkennen, worauf es hinaus läuft. Vielleicht hat hier jemand auch noch eine hübschere Idee dazu, das ist ja ansich ein bekanntes Problem (aber ich hab halt gerade keinen Link zur Hand).
Lieber dumm fragen, als dumm bleiben!

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

12

07.12.2013, 14:53

Data einfach weg lassen oder zumindest für jede abgeleitete Klasse separat definieren.
Das ist ja noch so ein Fall, wo in der Basisklasse schon Funktionalität der abgeleiteten Klassen drin steckt.
Ich sehe auch den Sinn davon nicht, für alle abgeleiteten Klassen dieselbe Data-Struktur zu benutzen.

Das Problem nennt man übrigens "Double Dispatch".
Wenn man danach googelt, findet man eine ganze Menge an Implementierungsmöglichkeiten.

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

13

07.12.2013, 15:00

Ich ich würde mir die Structs abgewöhnen. Die Dinger brauchst du eigentlich nicht.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

14

07.12.2013, 15:05

Man kann auch eine Tabelle verwenden, in der für jede Kombination aus zwei Objekttypen ein Zeiger auf eine Funktion abgelegt wird (bzw. ein std::function-Objekt), die diese Kombination aus Objekten handhabt.

Der Vorteil hierbei ist, dass man die abgeleiteten Klassen nicht allesamt anpassen muss, wenn man einen neuen Objekttyp hinzufügen möchte. Bei der Lösung von Jonathan_Klein muss man das tun, was ich nicht so schön finde.

wluc-16

Treue Seele

  • »wluc-16« ist der Autor dieses Themas

Beiträge: 212

Wohnort: in der Nähe von Bielefeld :D

Beruf: Schüler

  • Private Nachricht senden

15

07.12.2013, 15:06

OK, danke nochmals ;)
Wie schon gesagt, ich setze ich mich heute abend nochmal intensiver dran.

Ich hatte mir mit der "Data"-Struktur gedacht, dass ich sie für die Funktionen im Namespace "collision" als allgemeine Möglichkeit zur Rückgabe der jeweiligen Daten benutzen kann.

wluc-16

Treue Seele

  • »wluc-16« ist der Autor dieses Themas

Beiträge: 212

Wohnort: in der Nähe von Bielefeld :D

Beruf: Schüler

  • Private Nachricht senden

16

08.12.2013, 10:15

Mir kam gestern noch etwas dazwischen, weshalb es noch ein wenig dauert.

Zitat


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
bool BoxBox(*Box, *Box)
bool BoxSphere(...)
bool SphereSphere(...)

class Collider
{
bool CollideWith(Collider*)
};

class Box : public Collider
{
bool CollideWithBox(Box*, b)
{
  return BoxBox(this, b)
}

bool CollideWithSphere(Sphere*) ...
bool CollideWith(Collider* c) override
{
  c->CollideWithBox(this)
}

};

class Box : public Collider
{
bool CollideWithBox(Box*) ...
bool CollideWithSphere(Sphere*) ...
bool CollideWith(Collider* c) override ...
};



Verbessert mich, aber Jonathan_Kleins Quellcode, dürfte eigentlich nicht funktionieren (mir ist klar, dass es sich um eine Skizze handelt ;) ), da "Collider" die Methoden "CollideWithBox" und "CollideWithSphere" gar nicht kennt (siehe Zeile 20). Wenn er sie kennen würde, wären wir ja wieder vor der unschönen Problematik, dass die abstrakte Basisklasse ihre "Vererber" kennen muss.
Oder habe ich irgendetwas übersehen? :D

Andererseits werde ich höchstwahrscheinlich keine weiteren Collider-Typen hinzufügen, was wiederum dafür sprechen würde.

@David
So eine Tabelle kann ich mir auch mal anschauen ;)
Aber, wie schon gesagt, werde ich wahrscheinlich keine neuen Typen hinzufügen.

@Schorsch
Sind weg :D

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

17

08.12.2013, 11:05

Ich würde mir in diesem Forum mehr Diskussionen wie diese wünschen. :thumbup:

wluc-16

Treue Seele

  • »wluc-16« ist der Autor dieses Themas

Beiträge: 212

Wohnort: in der Nähe von Bielefeld :D

Beruf: Schüler

  • Private Nachricht senden

18

08.12.2013, 11:48

Freut mich das zu hören :D

Bei dieser Variante werde ich erstmal bleiben:

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
class AABB;
class Circle;

// Namespace für Kollisionsprüfungsfunktionen
//
namespace collision
{
    bool aabbVsAABB(AABB* a, AABB* b) { return false; }
    bool aabbVsCircle(AABB* a, Circle* b) { return false; }
    bool circleVsCircle(Circle* a, Circle* b) { return false; }
}
//



// abstrakte Basisklasse für Collider
//
class Collider{
public:
    virtual bool collidesWithAABB(AABB* other) = 0;
    virtual bool collidesWithCircle(Circle* other) = 0;

    virtual bool collidesWith(Collider* other) = 0;
};
//



// zwei Collider-Typen: achsengebundenes Rechteck und Kreis
//
class AABB : public Collider{
public:
    bool collidesWithAABB(AABB* other) override
    {
        return collision::aabbVsAABB(this, other);
    }
    bool collidesWithCircle(Circle* other) override
    {
        return collision::aabbVsCircle(this, other);
    }

    bool collidesWith(Collider* other) override
    {
        return other->collidesWithAABB(this);
    }
};

class Circle : public Collider{
public:
    bool collidesWithAABB(AABB* other) override
    {
        return collision::aabbVsCircle(other, this);
    }
    bool collidesWithCircle(Circle* other) override
    {
        return collision::circleVsCircle(this, other);
    }

    bool collidesWith(Collider* other) override
    {
        return other->collidesWithCircle(this);
    }
};
//


Danke an alle, war echt sehr hilfreich :thumbsup:

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

19

08.12.2013, 12:48

Wozu brauchst Du die beiden Klassen "Circle" und "AABB"? Sie tun genau dasselbe und sind damit überflüssig.
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]

wluc-16

Treue Seele

  • »wluc-16« ist der Autor dieses Themas

Beiträge: 212

Wohnort: in der Nähe von Bielefeld :D

Beruf: Schüler

  • Private Nachricht senden

20

08.12.2013, 12:57

Später bekommen sie ja auch ihre jeweiligen Werte (also Position und Größe bzw. Radius). Dann passe ich auch noch die Kollisionsfunktionen an.

Werbeanzeige