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

KeksX

Community-Fossil

Beiträge: 2 107

Beruf: Game Designer

  • Private Nachricht senden

11

21.05.2015, 12:03

Templates wären hier das richtige Stichwort. Und Factories.
WIP Website: kevinheese.de

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

12

21.05.2015, 12:12

Ich halte das hier vorgeschlagene Design für nicht zu sinnvoll. Alle States müssen normal nicht behalten werden. Einen Spielzustand möchte man oft wiederherstellen. Menüzustände etc braucht man da normal nicht. Da will man ja sogar oft in den Grundzustand des Menüs wechseln weshalb man den Zustand jedes mal reseten müsste. Das wäre natürlich auch eine Möglichkeit. Jeden Zustand ein mal am Anfang anlegen und dann eine Init und Exit Methode anbieten welche in der ChangeState Methode ausgeführt wird. Init und Exit Methoden sind zwar nicht unbedingt best practice aber da die Zustände normal nur vom Manager verwaltet werden sollten hier keine Probleme auftreten. Was man überlegen könnte wäre den Manager weg zu lassen. Du kannst mal nach dem Zustand Entwurfsmuster gucken. Man benötigt da normal nicht unbedingt einen Manager darüber.

Aber zu deinem aktuellen Problem. Leg dir intern im Manager eine Map an welche als Key einen String oder besser noch eine Enumeration bekommt. Als Value dann eben den Zustand. Da fügst du dann am Anfang deine Zustände hinzu und wenn du einen Zustand tauschen möchtest machst du das über den Schlüssel. Für den aktuellen Zustand speicherst du dann nur den Schlüssel.
Durch einen String Schlüssel bist du halt erst mal erweiterbarer. Einer Aufzählung kannst du nachträglich nichts hinzufügen solltest du den Code in eine Bibliothek auslagern wollen. Dafür hat die Aufzählung den riesen Vorteil dass dir bei falschen Schlüsseln der Compiler direkt Fehler um die Ohren haut anstatt dass du zur Laufzeit irgendwelche Fehler bekommst. Ich würde die Version mit der Aufzählung vorziehen. Vor allem da so ein Manager schnell implementiert ist und du ihn so jedes mal einfach fix anpassen kannst.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Statemanager {
private Map<enum StateType, reference State> states;

private enum StateType currentState;

public void AddState(enum StateType, reference State) {
  states.add(StateType, State);
}

public void Update() {
  states.get(currentState).Update();
}

public void ChangeState(enum StateType new) {
  states.get(currentState).Exit();
  currentState = new;
  states.get(currentState).Init();
}

}

Hier noch ein wenig Pseudocode wie so etwas aussehen kann.

edit: Das erzeugen der Zustände könnte man dann wie KeksX vorschlägt in eine Factory Klasse verschieben. Diese könntest du an sich auch erweitern. Die Factory könnte selbst die Zustände speichern, der Manager holt sich jedes mal den neuen Zustand von der Factory wobei die Factory die alten Zustände speichert, also nicht jedes mal neu erstellt wenn der Zustand schon vorhanden ist.
„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.“

13

21.05.2015, 15:14

Ja das Speichern der Zustände ist für mich immoment noch überflüssig. So wie du es beschrieben hast mit dem Init und Exit hatte ich mir das auch vorgestellt. Jedoch kämpfe ich ein wening mit der Map. Der erste Wert ist bei mir die Enum. ich weiß aber nicht wie ich den zweiten Wert definieren soll das er eine KLasse annimmt. also das eine Klasse übergeben wird.

Mein Code sieht wie folgt aus:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
std::map<enum StateType, ???> States;

void CStateManager::addState(enum StateType)
{
    
}

void CStateManager::changeState(enum StateType newState)
{


}


Wie soll ich das machen das ich dort anstatt der ??? meine klasse angeben kann. bzw der Map sagen das in Zukunft dort klassen gespeichert werden sollen. :?:

Urprimat
Most good programmers do programming not because they expect to get paid or get adulation by the public, but because it is fun to program.

Linus Torvalds

14

21.05.2015, 17:02

Kannst du mir eben einen Fall sagen, in dem man den "Namen" eines States wissen muss, statt einfach zu wissen, welcher State es ist?

Nicht das wie an einander Vorbeireden, wenn ich sage Name meine ich z.B. die Enum Bezeichnung, ich denke da wurden von Schorsch bsp. gebracht wo man es nutzt.

Da will man ja sogar oft in den Grundzustand des Menüs wechseln weshalb man den Zustand jedes mal reseten müsste.

Ja da gebe ich dir Grundsätzlich recht, aber resten bei einem Menu? Fällt mir spontan nicht ein was ich bei einem MainMenü Reseten wollen würde.

Wie soll ich das machen das ich dort anstatt der ??? meine klasse angeben kann. bzw der Map sagen das in Zukunft dort klassen gespeichert werden sollen.


Als erstes mal das Bsp. von Schorsch ist Pseudocode, das heist bissi selber überlegen muss man da schon noch. Das enum ist überall überflüssig.
Ich könnte dir hier jetzt ein Lösung hin klatschne aber ich glaube das ist nicht Sinn der Übung.

Google doch mal std::map

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
void CStateManager::addState(StateType type, State* newState)
{
     States.insert(type, newState);
}

void CStateManager::changeState(StateType newState)
{
    currentState = States.find(newState);
}


Ist auch nur Pseudocode, aber so in etwa kann es aussehen.

Edit: Naja mein Code wird dich wohl auch nicht weiterbringen, da er sich wohl mit Schorsch's code in etwa deckt.
Darum hier mal noch ein Verweis auf das Wiki es geht ja auch anders einen StateManager zu realisieren (ich persönlich finde die Variante mit Stack aber zu unflexible).
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Koschi« (21.05.2015, 17:07)


15

21.05.2015, 20:59

Als erstes mal das Bsp. von Schorsch ist Pseudocode, das heist bissi selber überlegen muss man da schon noch. Das enum ist überall überflüssig.
Ich könnte dir hier jetzt ein Lösung hin klatschne aber ich glaube das ist nicht Sinn der Übung.


Da hast du absolut Recht. Das ist nicht das Problem. ich habe schon mit Maps gearbeitet und den Pseudocode habe ich auch verstanden. Ich habe mich einfach nur sau blöd ausgedrückt.

StateManger.hpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class CStateManager : public TSingleton<CStateManager>
{
private:

    CGameState * CurrentState;

public:

    CStateManager(){};
    ~CStateManager();
    void Update();
    void Render();

    enum StateType;
    map<StateType, CGameState> States;
    pair<StateType, CGameState> StatePair;

    void addState(StateType newState,CGameState *GameState);
    void changeState(StateType newState);
};

StateManager.cpp

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void CStateManager::addState(StateType newState,CGameState *GameState)
{
    StatePair = make_pair(newState, &GameState);
    States.insert(StatePair);
}

void CStateManager::changeState(StateType newState)
{
    CurrentState->Exit();
    auto i = States.find(newState);
    *CurrentState = i->second;
    CurrentState->Init();
    
}


Das ist mein Derzeitiger code. Ob er Funzt weiß ich noch nicht da ich 2 kleine Fragen habe.

1. Wie ich das von Schorch mitbekommen habe kann ich doch keine Enum erweitern oder? Somit ist meine addState Methode mit den Enums etwas plöd. sollte ich nicht lieber einfach nur strings benutzen, wenn ich eine Flexible GameStates haben möchte.
und
2. wann und von Wo soll ich den addState() aufrufen. Aktuell hatte ich nur im Kopf sie aus meiner main.cpp auszuführen. Würde dann ca so aussehen:

C-/C++-Quelltext

1
2
3
    CGameState * GameState;
    GameState = new CGame;
    StateManager->addState("name", GameState);


Allerdings nicht gerade hübsch oder nicht? :thumbdown:


Vielen Danke für eure Geduld... Urprimat
Most good programmers do programming not because they expect to get paid or get adulation by the public, but because it is fun to program.

Linus Torvalds

16

21.05.2015, 21:17

1. Wie ich das von Schorch mitbekommen habe kann ich doch keine Enum erweitern oder? Somit ist meine addState Methode mit den Enums etwas plöd. sollte ich nicht lieber einfach nur strings benutzen, wenn ich eine Flexible GameStates haben möchte.

Schorsch hat es ja im prinzip schon erklärt. Wenn du mit Enum arbeitest sagt dir der Compiler schon das es ein State nicht gibt, ausgelagert in eine DLL gibt es später dann aber keine Möglichkeit die Aufzählung zu erweitern. Im aktuellen Code kannst du ihn natürlich beliebieg erweitern.

Wenn du mit Strings arbeitest kannst du den StateManager in eine DLL auslagern und beliebige werte zuweisen. Der Nachteil ist dann aber wenn du ein Schreibfehler hast (Groß/Kleinschreibung oder was auch immer) und der State nicht vorhanden ist gibt dir der Compiler keinen Fehler mehr aus. Dir Crasht dann einfach das Programm bzw. muss über exception abgefangen werden.


2. wann und von Wo soll ich den addState() aufrufen. Aktuell hatte ich nur im Kopf sie aus meiner main.cpp auszuführen. Würde dann ca so aussehen:

Ja im prinzip in der main.cpp, Idealer weise schreibst du dir aber noch eine Klasse die dann z.B. den Statemanger oder ein RessourcenManger hält und sich vielleicht um das Window an sich kümmert, dort könnte man es z.B. im Konstruktor machen.
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

17

21.05.2015, 22:36

Schorsch hat es ja im prinzip schon erklärt. Wenn du mit Enum arbeitest sagt dir der Compiler schon das es ein State nicht gibt, ausgelagert in eine DLL gibt es später dann aber keine Möglichkeit die Aufzählung zu erweitern. Im aktuellen Code kannst du ihn natürlich beliebieg erweitern.


Allet klar. Ich werd mir das dann nochma genau anschauen. Ich bin eigentlich recht zufrieden mit der Lösung. und werde sie jt mal in ein kleines Spiel einbauen und sie ausreizen. :search:

Ich danke dir für deine geduldige Hilfe. Liebe grüße Urprimat!
Most good programmers do programming not because they expect to get paid or get adulation by the public, but because it is fun to program.

Linus Torvalds

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

18

22.05.2015, 09:40

Fällt mir spontan nicht ein was ich bei einem MainMenü Reseten wollen würde.

Das hängt natürlich von deinem Menü ab. Möglicherweise hast du eine Steuerung über die Tastatur oder ein Gamepad. Dann könnte das Menü einen Cursor speichern. Wenn man aber neu ins Menü kommt würde man den Cursor normal an erster Stelle erwarten und nicht dort wo er zuletzt platziert wurde. Menüs könnten noch Fenster und Leisten haben die möglicherweise geöffnet wurden. Sobald das Menü komplexer wird wirst du in irgendeiner Form einen Zustand speichern.
„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.“

19

22.05.2015, 10:26

Ja, wenn es komplex wird ist das Richtig, deshalb hatte ich extra ein Hauptmenü in den Raum geworfen.

Ich weiß auch nicht ob es sinnvoll ist States immer wieder zu erzeugen und beim verlassen zu löschen, ich sag es mal so "nur um sie Jungfräulich Aussehen zu lassen".
Mir persönlich gefällt da eine Init und Exit-Methode besser, wobei ich bei der nahmenswahl onEnter/onLeave dafür wählen würde.

Sei es wie es sei Urprimat scheint erstma damit zufrieden zu sein.

Gruß Koschi
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

20

22.05.2015, 11:20

Da stimme ich dir zu. Die Erzeugungskosten für die Zustände kann man sich sparen. Man könnte sich da zum Beispiel auch ein Caching System bauen.
„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.“

Werbeanzeige