Enum erweitern



  • Hallo,

    Ich habe in meinem Jump'n'Run-Spiel Klassen für verschiedene Spielobjekte, z.B. Aufzüge. In diesen Klassen ist jeweils ein enum definiert, das die einzelnen Typen kennzeichnet:

    enum LiftType
    {
        Waiting,     // wartet, bis man auf Lift springt
        Patrol,      // verkehrt immer zwischen zwei Punkten
        CyclePatrol, // bewegt sich auf einer Bahn und fängt wieder von vorne an
    };
    

    Nun habe ich einen Editor, in dem es unterschiedliche Modi gibt. Also beispielsweise "Gegner setzen" oder "Lifte setzen" oder "Verwaltung". Wenn der aktuelle Modus z.B. "Lifte setzen" ist, kann man neben dem Auswählen der drei Typen noch besondere Aktionen durchführen (z.B. Lift-Wegpunkte setzen). Man kann die Aktion ändern, indem man eine entsprechende Schaltfläche anklickt.

    Bis jetzt hatte ich im Editor eine LiftType -Variable, mit der die aktuelle Aktion angezeigt wurde. Da jetzt aber spezifische Aktionen dazukommen, geht das nicht mehr so leicht. Es wäre also praktisch, ein Enum zu vererben oder sonst zu erweitern. Durch Casten hinbiegen möchte ich es eigentlich nicht. Momentan überlege ich mir folgende Möglichkeiten:

    • Ich habe ein bool -Statusflag, das mir angibt, ob ich die drei bereits bestehenden Konstanten oder Erweiterungen brauche. Für die Erweiterungen kann ich ein eigenes Enum erstellen. Allerdings muss ich dann zwei Variablen für die ausgewählte Aktion anlegen, obwohl nur eine Aktion gleichzeitig möglich ist. Zusätzlich brauche ich das bool -Flag, also total 3 Variablen für einen Zustand.
    • Ich mache das Ganze statt mit Enum-Typen mit int , wodurch ich aber Typsicherheit verliere. Dann muss ich auch immer unschöne Fallunterscheidungen wie if (Action >= 3) machen.
    • Ich definiere das Enum neu, sodass es alle Aktions-Konstanten speichern kann. Ist zwar nachher sauber in der Handhabung, aber dafür schlecht wartbar und Codeduplizierung.

    Wie würdet ihr das machen?



  • Nexus schrieb:

    Da jetzt aber spezifische Aktionen dazukommen

    Sind das "andere" Optionen, die halt auch den Lift betreffen oder Alternativen zu den Status aus "LiftType"?



  • Badestrand schrieb:

    Sind das "andere" Optionen, die halt auch den Lift betreffen oder Alternativen zu den Status aus "LiftType"?

    Es sind andere Optionen, also keine Lift-Typen.

    Aber in der Zwischenzeit hab ich mir eine andere Lösung geschaffen, die auch relativ brauchbar und typsicher ist (wie praktisch doch Templates sind). 😉

    template <typename Enum1, typename Enum2, typename IntType = int>
    class MergedEnum
    {
    	public:
    
    		// Typdefinitionen
    		typedef IntType IntegerType;
    		typedef Enum1 FirstEnumType;
    		typedef Enum2 SecondEnumType;
    
    	public:
    
    		// Konstruktor von erstem Enum-Typ
    		MergedEnum(FirstEnumType Value);
    
    		// Konstruktor von zweitem Enum-Typ
    		MergedEnum(SecondEnumType Value);
    
    		// Konstruktor von anderem Objekt der Klasse
    		MergedEnum(const MergedEnum<Enum1, Enum2, IntType>& Origin);
    
    		// Zuweisungsoperator von erstem Enum-Typ
    		MergedEnum<Enum1, Enum2, IntType>& operator= (FirstEnumType Value);
    
    		// Zuweisungsoperator von zweitem Enum-Typ
    		MergedEnum<Enum1, Enum2, IntType>& operator= (SecondEnumType Value);
    
    		// Zuweisungsoperator von anderem Objekt der Klasse
    		MergedEnum<Enum1, Enum2, IntType>& operator= (const MergedEnum<Enum1, Enum2, IntType>& Origin);
    
    		// Automatische Umwandlung zu integralem Typ
    		operator IntegerType () const;
    
    		// Automatische Umwandlung zu erstem Enum-Typ (Laufzeitprüfung)
    		operator FirstEnumType () const;
    
    		// Automatische Umwandlung zu zweitem Enum-Typ (Laufzeitprüfung)
    		operator SecondEnumType () const;
    
    	private:
    
    		// Intern gespeicherter Enumerationswert
    		IntType MyValue;
    
    		// Status, welcher Typ
    		bool MyIsFirstEnumType;
    };
    

    Das kann man natürlich noch weiter treiben, doch momentan ist es eigentlich ziemlich okay so. Die Cast-Operatoren sind nicht so schön momentan, aber da sie zur Laufzeit geprüft werden (mittels der bool-Variable, die beim Setzen angepasst wird), ist auch da die Typsicherheit nicht ganz weg.

    Anmerkungen oder bessere Vorschläge sind trotzdem jederzeit willkommen. 🙂



  • Gut dass du's schon gelöst hast, ich palavere dann einfach mal drauf los 🙂

    Nexus schrieb:

    Es sind andere Optionen, also keine Lift-Typen.

    Dann verstehe ich nicht, wieso du das Enum erweitern bzw zwei Enums zusammenfügen willst..? Die Theorie muss ja nicht immer guten Code ergeben, aber wenn die Enums unabhängig sind, wird der Status vom Objekt nun mal von mehreren Variablen angegeben, oder nicht?

    In 'nem Editor würde ich es mir jetzt auch eher so vorstellen, dass ich einen Lift setze und danach die Eigenschaft "LiftType" (Waiting | Patrol | CyclicPatrol) und noch ein paar andere Eigenschaften des Lifts setze.



  • Badestrand schrieb:

    Gut dass du's schon gelöst hast, ich palavere dann einfach mal drauf los 🙂

    Nur zu, ich bin immer über Fragen und Vorschläge erfreut. 🙂

    Badestrand schrieb:

    Dann verstehe ich nicht, wieso du das Enum erweitern bzw zwei Enums zusammenfügen willst..? Die Theorie muss ja nicht immer guten Code ergeben, aber wenn die Enums unabhängig sind, wird der Status vom Objekt nun mal von mehreren Variablen angegeben, oder nicht?

    Vielleicht hab ich es nicht so gut ausgedrückt. Es gibt eine Klasse Lift , die hat ein enum mit den drei Typen (und natürlich eine Membervariable davon). Jetzt im Editor gibt es sozusagen ein Untermenü Lifte bearbeiten. Da kann man alles tun, was mit den Aufzügen zu tun hat. Also neue erstellen, alte löschen, Wegpunkte festlegen, ...

    Damit man weiss, was man gerade tut, gibt es verschiedene Aktionen, die von Schaltflächen repräsentiert werden. Das Setzen jedes einzelnen Lifts ist eine solche Aktion - die den drei Enum-Konstanten von LiftType entspricht. Spezifische Dinge wie Wegpunkte setzen oder Lift auswählen etc. stehen auch für jeweils eine Aktion. Also hat man total z.B. fünf Aktionen, von denen drei für das Setzen eines neuen Lifts stehen.

    enum Action  // sinngemäss in einem Enum zusammengefasst (nicht so in der Praxis)
    {
        CreateWaiting,
        CreatePatrol,
        CreateCyclePatrol,
        SetWaypoints,
        SelectLift
    };
    

    Gleichzeitig kann man aber nicht mehr als eine Aktion ausführen, deshalb finde ich es nicht so sinnvoll, mehrere Variablen für den einen Status (welche Aktion) zu haben.

    Badestrand schrieb:

    In 'nem Editor würde ich es mir jetzt auch eher so vorstellen, dass ich einen Lift setze und danach die Eigenschaft "LiftType" (Waiting | Patrol | CyclicPatrol) und noch ein paar andere Eigenschaften des Lifts setze.

    Ja, das wäre auch eine Möglichkeit. Aber ich finde es irgendwie benutzerfreundlicher, wenn man gleich zu Beginn den Typ auswählen kann (auch wegen der Grafik). Denn dass man einen Lift nachträglich noch ändert, ist eher unwahrscheinlich.


Log in to reply