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

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

21

28.07.2015, 06:35

Ich verstehe ehrlich gesagt nicht, wieso Du für so unterschiedliche Dinge unbedingt eine Oberklasse verwenden willst. Die Events sind massiv unterschiedlich, ich würde daher eine solche Vereinheitlichung gar nicht vornehmen wollen. Welchen Zweck soll das genau haben außer Faulheit? Einheitlichkeit nur zum Zwecke der Einheitlichkeit sieht mir nicht sehr hilfreich aus.
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]

Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

22

28.07.2015, 09:31

Oder man geht es so an, wie man es eigentlich sonst auch immer angehen würde: das Physiksystem bzw. die von deinem System abstrahierten Collider besitzen Events eines bestimmten Typs (also sammeln Callbacks, die bestimmte Parameter erwarten) und sobald das entsprechende Ereignis eintritt, werden alle Callbacks des Events ausgelöst. Weiterhin besitzen alle "Drawables"/"Renderables"/"Sprite-" und "MeshRenderer"/... Events für das betreten des sichtbaren Bereichs, für das Verlassen dieses usw.
Welchen Vorteil erhoffst du dir von einem zentralen "EventManager"/"EventSystem"/"EventForwarder"/... in deinem System? Wie sollten die anderen Stellen (Physiksystem, der Code mit den Callbacks etc.) an diese zentrale Stelle kommen? Vielleicht sogar noch per Singleton?
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

23

28.07.2015, 09:59

Dann sind wir wieder beim Observer-Pattern.

Was genau ist denn das Problem mit dem Observer Pattern?

24

28.07.2015, 20:43

Um nochmal deine Ursrpüngliche Frage aufzugreifen, ob man auch ohne RTTI an type ID's kommt: Unter gewissen Umständen JA.

Eigenetlich hat DeKugelschieber deine Frage ja schon beantwortet. So kannst du type ID's ermitteln:

Quellcode

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
#include <iostream>

unsigned int maxTypeID = 0;

template < typename T >
unsigned int type() {
    static unsigned int id = ++maxTypeID;
    return id;
}
template < typename T >
unsigned int type( T t ) {
    return type<decltype( t )>();
}

void main() {
    int a = 1;
    int b = 2;
    float c = 3;

    std::cout << type(a) << std::endl;
    std::cout << type(b) << std::endl;
    std::cout << type(c) << std::endl;

    if(type(5) == type<int>())
        std::cout << "ok" << std::endl;
}


Ausgabe:

1
1
2
"ok"



Und bezogen auf dein Event System, könntest du sowas machen:

Quellcode

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
#include <iostream>
#include <vector>

unsigned int maxTypeID = 0;

template < typename T >
unsigned int type() {
    static unsigned int id = ++maxTypeID;
    return id;
}
template < typename T >
unsigned int type( T t ) {
    return type<decltype( t )>();
}

class IEvent {
public:
    IEvent() {}
    virtual ~IEvent() {}
    virtual unsigned int Type() = 0;
};

template < typename T >
class EventType : public IEvent {
public:
    EventType() {}
    virtual ~EventType() {}
    unsigned int Type() {
        return type<T>();
    }
};

class A : public EventType<A> {
public:
    A() {}
    ~A() {}
};

class B : public EventType<B> {
public:
    B() {}
    ~B() {}
};

void main() {
    std::vector<IEvent*> events;

    A e1;
    B e2;
    B e3;
    A e4;
    A e5;
    events.push_back( &e1 );
    events.push_back( &e2 );
    events.push_back( &e3 );
    events.push_back( &e4 );
    events.push_back( &e5 );


    for(IEvent* e : events)
        std::cout << "Event Type: " << e->Type() << std::endl;

}


Ausgabe:

1
2
2
1
1


HTH

Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

25

29.07.2015, 00:27

Das Problem dabei ist, dass zur Initialisierung diese Funktion erstmal für jeden Typen einmal aufgerufen werden muss.
Mal ganz abgesehen davon, dass die grundsätzliche herangehensweise eher angepasst werden sollte.
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

26

29.07.2015, 08:15

Zitat von »"Sacaldur"«

Das Problem dabei ist, dass zur Initialisierung diese Funktion erstmal für jeden Typen einmal aufgerufen werden muss.
Mal ganz abgesehen davon, dass die grundsätzliche herangehensweise eher angepasst werden sollte.


Ich geb dir Recht, dass es wahrscheinlich eine elegantere Lösung gibt.
Dennoch fand ich die Frage, ob man fürs gewünschte Ergebnis ohne RTTI (ohne typeinfo & dynamic_cast) auskommen kann, ganz interessant.

Was ich glaube, was der OP machen möchte, ist folgendes:

Quellcode

1
2
3
4
5
6
7
8
9
    for (IEvent* e : events) {
        if (e->Type() == type< A >()) {
            A* a = static_cast< A* >( e );
            a->PrintA();
        } else if (e->Type() == type< B >()) {
            B* b = static_cast< B* >( e );
            b->PrintB();
        }
    }


Und ja, das geht.

Das Problem, das die Funktion mit jedem Type einmal im Code vorkommen muss, ist in diesem Fall glaub ich kein nennenswertes Problem, da das bei der Abfrage automatisch passieren muss.
Zumindest fällt mir gerade kein Beispiel ein, wo es ein Problem damit geben könnte.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Xanatus« (29.07.2015, 08:34)


Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

27

29.07.2015, 10:05

Eine elegantere Lösung habe ich ja bereits beschrieben: statt eine zentrale Stelle zu haben, die sich um alle Events kümmert (was auch immer damit dann gemeint wäre), besitzt jedes Objekt bzw. jedes System für jedes Event, was von diesem erzeugt (oder beobachtet) werden kann ein "Event", mit dessen Hilfe die Callbacks gesammelt und mit einem Schlag abgearbeitet werden können. So ist es möglich, dass jedes einzelne dieser Events auch einen bestimmten Typen besitzt, wodurch eine Unterscheidung der Typen nicht benötigt wird.
Das Problem dabei ist, dass man unterschiedliche Codestellen anpassen muss, um neue Events hinzuzufügen. Das "Feuern" des Events (also das Aufrufen aller Callbacks) ist an der einen Stelle (innerhalb des jeweiligen Objekts oder Systems) und das Finden der Passenden Callbacks an einer anderen Stelle (die von dir beschriebene). Vergisst man letzteres, wird kein einziger Callback aufgerufen.

Und dabei habe ich noch nichtmal damit angefangen, dass alle Objekte(/Systeme), die Events besitzen, auf einmal dieses Eventsystem kennen müssen (wofür sie auch Zugriff auf die gleiche Instanz brauchen). Und um die Parameterliste des Konstruktors kurz zu halten und blöde Setter zu vermeiden wird dieses EventSystem dann vielleicht noch global zugreifbar gemacht (bspw. mit einem Singleton).
Auch wenn das vielleicht sehr nach Schwarzmalerei klingen mag, leider scheint es zu oft so abzulaufen.
Dann doch lieber gleiche eine saubere und weit verbreitete Lösung verwenden.
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

Werbeanzeige