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

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

1

07.12.2013, 12:19

[GELÖST] Zwei verschiedene Varianten eines Typs - Designproblem

Hallo,
Letztens bin ich auf folgendes Designproblem gestoßen:

Ich habe eine Klasse "RigidBody", die einen Körper representiert. Dieser soll mit anderen Körpern kollidieren können. Das Problem ist, dass es Körper mit einem AABB-Collider und welche mit Kreis-Collider gibt.

Mein Ansatz war:

C-/C++-Quelltext

1
2
3
4
5
struct Collider{
    bool rectangular;
    AABB box;
    Circle circle;
};


oder:

C-/C++-Quelltext

1
2
3
4
class RigidBody { ... };

class AABBRigidBody : public RigidBody { ... };
class CircleRigidBody : public RigidBody { ... };


Beide Ansätze sehen für mich aber relativ hässlich aus, daher meine Frage:
Wie würde man so etwas in designtechnisch korrektem C++ lösen?

Danke schonmal im voraus :)

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »wluc-16« (08.12.2013, 11:49)


Legend

Alter Hase

Beiträge: 731

Beruf: Softwareentwickler

  • Private Nachricht senden

2

07.12.2013, 12:26

Mit der zweiten Variante, bei der ich nicht weiß, wieso das für dich hässlich aussieht.
"Wir müssen uns auf unsere Kernkompetenzen konzentrieren!" - "Juhu, wir machen eine Farm auf!"

Netzwerkbibliothek von mir, C#, LGPL: https://sourceforge.net/projects/statetransmitt/

3

07.12.2013, 13:05

Ich bin ganz der Meinung von Legend.
Also die Kollision von zwei verschiedenen Objekten würde ich dann über die Basisklasse machen(wenn ich das richtig verstanden hab :D).

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

4

07.12.2013, 13:12

OK, danke schonmal :thumbsup:

Ich hab jetzt das hier zusammenprogrammiert:

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
// Collider-Strukturen: Achsengebundenes Rechteck und Kreis
//
struct AABB{
    float x;
    float y;
    float w;
    float h;
};

struct Circle{
    float x;
    float y;
    float r;
};
//



// Körper-Klasse: virtuelle Methoden für Kollision, normale Methoden für andere Simulation
//
class AABBBody;
class CircleBody;

class Body{
public:
    void update(float time) { /* Implementierung */ };

    virtual bool collidesWith(AABBBody& other) = 0;
    virtual bool collidesWith(CircleBody& other) = 0;

protected:
    float mass;
};
//



// Collider-Erweiterungen für Körper-Klasse: Achsengebundenes Rechteck und Kreis
//
class AABBBody : public Body{
public:
    bool collidesWith(AABBBody& other) override { /* Implementierung */ return false; }
    bool collidesWith(CircleBody& other) override { /* Implementierung */ return false; }

protected:
    AABB aabb;
};

class CircleBody : public Body{
public:
    bool collidesWith(AABBBody& other) override { /* Implementierung */ return false; }
    bool collidesWith(CircleBody& other) override { /* Implementierung */ return false; }

protected:
    Circle circle;
};
//



// Zwei Testklassen: Stein und Fenster
//
class Stone : public CircleBody{
public:
    Stone(float x, float y, float r)
    {
        mass = r * 5;
        circle = { x, y, r };
    }
};
class Window : public AABBBody{
public:
    Window(float x, float y, float w, float h)
    {
        mass = w * h * 2;
        aabb = { x, y, w, h };
    }
};
//



int main()
{
    Stone s(50.0F, 50.0F, 4.0F);
    Window w(30.0F, 30.0F, 100.0F, 20.0F);

    if (s.collidesWith(w)) return 1;

    return 0;
}


Wäre schön, wenn ihr da mal einen Blick drauf werfen könntet :D

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

5

07.12.2013, 13:15

Das nun wiederum ist Quatsch. Jetzt kennt die Parent-Klasse die Child-Klassen. Das sollte man dringend vermeiden. Der Sinn von Polymorphie in diesem Fall ist doch gerade der, dass es mehrere konkrete Implementierungen geben kann und sich alle an dasselbe Interface der Eltern-Klasse halten.
Aktuell müsstest Du durch die multiplen Methoden sogar in zwei Klassen zweimal denselben Code haben. Das ist doch offenbar nicht Sinn der Sache.
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]

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

6

07.12.2013, 13:23

Ich würde dir empfehlen, die Konzepte "Rigid Body" und "Collider" zu trennen und eine 1:N-Relation daraus zu machen.
Ein Rigid Body kann beliebig viele Collider besitzen (ein Collider aber nur zu einem einzigen Rigid Body gehören). So machen das doch auch die Physik-Engines.

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

7

07.12.2013, 13:41

Mach Sinn :golly: :D
Heute Abend werde ich mich da mal dran setzen und poste dann das Resultat ;)

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

8

07.12.2013, 14:36

Hier schonmal ein "Prototyp" der Collider-Hierarchie:
Ich hatte Probleme bei der Übergabe zwischen den "collision"-Funktionen und den Collidern, daher die "getData"-Methode. Ich glaube, das muss irgendwie eleganter gehen, oder?

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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// Namespace für Kollisionprüfungen zwischen Collidern
//
class Collider;

namespace collision
{
    static bool boxVsBox(Collider* box1, Collider* box2) { return false; }
    static bool boxVsCircle(Collider* box, Collider* circle) { return false; }
    static bool circleVsCircle(Collider* circle1, Collider* circle2) { return false; }
}
//



// abstrakte Collider-Klasse
//
class Collider{
public:
    enum class Type{
        Box,
        Circle
    };
    struct Data{
        float x;
        float y;
        float wr; // Breite oder Radius
        float hu; // Höhe oder unbenutzt
    };

    virtual void set(Data& d) = 0;
    virtual bool collidesWith(Collider* other) = 0;
    virtual Type getType() = 0;
    virtual Data& getData() = 0;
};
//



// Collider-Typen: Rechteck und Kreis
//
class Box : public Collider{
public:
    void set(Data& d) override
    {
        x = d.x;
        y = d.y;
        w = d.wr;
        h = d.hu;
    }

    bool collidesWith(Collider* other) override
    {
        if (other->getType() == Type::Box) return collision::boxVsBox(this, other);
        if (other->getType() == Type::Circle) return collision::boxVsCircle(this, other);
    }

    Type getType() override
    {
        return Type::Box;
    }
    
    Data& getData() override
    {
        Data d = { x, y, w, h };
        return d;
    }

private:
    float x;
    float y;
    float w;
    float h;
};

class Circle : public Collider{
public:
    void set(Data& d) override
    {
        x = d.x;
        y = d.y;
        r = d.wr;
    }

    bool collidesWith(Collider* other) override
    {
        if (other->getType() == Type::Box) return collision::boxVsCircle(other, this);
        if (other->getType() == Type::Circle) return collision::circleVsCircle(this, other);
    }

    Type getType() override
    {
        return Type::Circle;
    }

    Data& getData() override
    {
        Data d = { x, y, r, 0.0f };
        return d;
    }

private:
    float x;
    float y;
    float r;
};
//

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

9

07.12.2013, 14:42

Irgendwie nicht so schön, dass die Basisklasse wissen muss, welche abgeleiteten Klassen es gibt (enum class Type) ...

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

10

07.12.2013, 14:51

Jaa, da muss ich mir auch noch etwas überlegen :)
Was haltet ihr von dem "Collider:: Data"-Zeugs bzw. wie könnte ich das eleganter machen?

Werbeanzeige