Servus,
ich hab eine Architekturfrage in C++. Ich arbeite an einer Game Engine und möchte die State Machine überarbeiten. Bisher ist es so, dass neue Szenen manuell in eine Enum eingetragen werden müssen und beim Szenenwechsel einfach die
Ich stoße dabei aber auf das Problem, dass ich ohne Binding eine zirkuläre Abhängigkeit aufbaue (siehe vereinfachtes Klassendiagramm). Im Internet werde ich leider nicht besonders schlau, denn die Wege, diese zirkuläre Abhängigkeit zu umgehen (bspw. mit einer anonymen Klasse und
Von daher hoffe ich, dass mir hier jemand helfen kann.
Liebe Grüße
Spoiler anzeigen
// Edit: Die eigentliche State Machine ergänzt. Ist schon echt hart widerlich gemacht
ich hab eine Architekturfrage in C++. Ich arbeite an einer Game Engine und möchte die State Machine überarbeiten. Bisher ist es so, dass neue Szenen manuell in eine Enum eingetragen werden müssen und beim Szenenwechsel einfach die
changeScene(...)
aus dem Manager
in der Szene durch ein gebindetes std::function
-Objekt aufgerufen wird. Ich möchte das ganze dahingehend umgestalten, dass zum einen die Szenen dynamisch hinzugefügt werden können und dass der Szenenwechsel über ihren Namen / Tag funktioniert. Weitergehend möchte ich gerne ohne das Binding arbeiten, ich persönlich finde das echt nicht schön.Ich stoße dabei aber auf das Problem, dass ich ohne Binding eine zirkuläre Abhängigkeit aufbaue (siehe vereinfachtes Klassendiagramm). Im Internet werde ich leider nicht besonders schlau, denn die Wege, diese zirkuläre Abhängigkeit zu umgehen (bspw. mit einer anonymen Klasse und
friend
-Funktionen) finde ich genauso unschön. Da kann ich dann ja auch direkt funktional programmieren. Und andere Beispiele für eine State Machine ohne Enum finde ich nicht, aber es muss ja einen Weg geben.Von daher hoffe ich, dass mir hier jemand helfen kann.
Liebe Grüße
C-Quellcode
- class Scene {
- public:
- virtual void load() = 0;
- virtual void unload() = 0;
- virtual void render(...) = 0;
- virtual void update(const std::chrono::high_resolution_clock::duration& deltaTime) = 0;
- public:
- enum class SceneType : int8_t {
- INVALID = -1,
- MAIN = 0,
- GAME = 1,
- OPTIONS = 2,
- CREDITS = 3
- };
- std::function<void(SceneType)> changeScene;
- std::function<void()> requestQuit;
- };
C-Quellcode
- void Manager::updateScene(const std::chrono::high_resolution_clock::duration& deltaTime) {
- switch (currentScene) {
- case scenes::Scene::SceneType::MAIN: mainScene.update(deltaTime); break;
- case scenes::Scene::SceneType::GAME: gameScene.update(deltaTime); break;
- case scenes::Scene::SceneType::OPTIONS: optionsScene.update(deltaTime); break;
- case scenes::Scene::SceneType::CREDITS: creditsScene.update(deltaTime); break;
- }
- }
- void Manager::changeScene(scenes::Scene::SceneType scene) {
- // Game state machine
- // We consciously don't check to see if a scene is trying to reload itself.
- // This way a scene can reset itself.
- // Unload the current scene
- if (currentScene != scenes::Scene::SceneType::INVALID) {
- switch (currentScene) {
- case scenes::Scene::SceneType::MAIN: mainScene.unload(); break;
- case scenes::Scene::SceneType::GAME: gameScene.unload(); break;
- case scenes::Scene::SceneType::OPTIONS: optionsScene.unload(); break;
- case scenes::Scene::SceneType::CREDITS: creditsScene.unload(); break;
- }
- }
- // Load the new scene
- switch (scene) {
- case scenes::Scene::SceneType::MAIN:
- mainScene.changeScene = std::bind(&Manager::changeScene, this, std::placeholders::_1);
- mainScene.requestQuit = std::bind(&Game::exit, game);
- mainScene.load();
- break;
- case scenes::Scene::SceneType::GAME:
- gameScene.changeScene = std::bind(&Manager::changeScene, this, std::placeholders::_1);
- gameScene.requestQuit = std::bind(&Game::exit, game);
- gameScene.load();
- break;
- case scenes::Scene::SceneType::OPTIONS:
- optionsScene.changeScene = std::bind(&Manager::changeScene, this, std::placeholders::_1);
- optionsScene.requestQuit = std::bind(&Game::exit, game);
- optionsScene.load();
- break;
- case scenes::Scene::SceneType::CREDITS:
- creditsScene.changeScene = std::bind(&Manager::changeScene, this, std::placeholders::_1);
- creditsScene.requestQuit = std::bind(&Game::exit, game);
- creditsScene.load();
- break;
- }
- currentScene = scene;
- }
// Edit: Die eigentliche State Machine ergänzt. Ist schon echt hart widerlich gemacht
Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ichduersie“ ()