From 7a4c8ea0f5bb89db0f91ad5dfb601fa512ef9d9d Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Mon, 31 Jul 2023 20:39:46 +0900 Subject: [PATCH] Defer ScreenStack actions to start of update --- src/game.cc | 4 +--- src/screen.cc | 57 ++++++++++++++++++++++++++++++++++++++++++++++----- src/screen.h | 26 +++++++++++++++++++++-- 3 files changed, 77 insertions(+), 10 deletions(-) diff --git a/src/game.cc b/src/game.cc index 95324d7..a1fdab1 100644 --- a/src/game.cc +++ b/src/game.cc @@ -5,9 +5,7 @@ Game::Game() : screen_stack(ScreenStack::new_instance()), - prev_time(std::chrono::steady_clock::now()) { - screen_stack->push_screen(); -} + prev_time(std::chrono::steady_clock::now()) {} void Game::update() { auto next_time = std::chrono::steady_clock::now(); diff --git a/src/screen.cc b/src/screen.cc index bd855cf..8cd1bcc 100644 --- a/src/screen.cc +++ b/src/screen.cc @@ -1,7 +1,24 @@ #include "screen.h" +// standard library includes +#include +#ifndef NDEBUG +#include +#endif // NDEBUG + +// local includes +#include "screen_test.h" + Screen::Screen(std::weak_ptr stack) : stack(stack) {} +ScreenStack::PendingAction::PendingAction() : screen(), action(Action::NOP) {} + +ScreenStack::PendingAction::PendingAction(Action action) + : screen(), action(action) {} + +ScreenStack::PendingAction::PendingAction(Screen::Ptr &&screen) + : screen(std::forward(screen)), action(Action::PUSH_SCREEN) {} + ScreenStack::Ptr ScreenStack::new_instance() { std::shared_ptr ptr = std::shared_ptr(new ScreenStack{}); @@ -10,7 +27,17 @@ ScreenStack::Ptr ScreenStack::new_instance() { } void ScreenStack::update(float dt) { + handle_pending_actions(); + auto idx = stack.size(); + if (idx == 0) { +#ifndef NDEBUG + std::cerr << "WARNING: Stack is empty, pushing TestScreen...\n"; +#endif // NDEBUG + push_screen(Screen::new_screen(self_weak)); + update(dt); + return; + } while (idx > 0 && stack.at(--idx)->update(dt)) { } } @@ -22,13 +49,33 @@ void ScreenStack::draw() { } void ScreenStack::push_screen(Screen::Ptr &&screen) { - stack.emplace_back(std::forward(screen)); + actions.push_back(PendingAction(std::forward(screen))); } void ScreenStack::pop_screen() { - if (!stack.empty()) { - stack.pop_back(); - } + actions.push_back(PendingAction(Action::POP_SCREEN)); } -ScreenStack::ScreenStack() : self_weak(), stack() {} +ScreenStack::ScreenStack() : self_weak(), stack(), actions() {} + +void ScreenStack::handle_pending_actions() { + while (!actions.empty()) { + switch (actions.front().action) { + case Action::PUSH_SCREEN: + stack.push_back(std::move(actions.front().screen)); + break; + case Action::POP_SCREEN: + if (!stack.empty()) { + stack.pop_back(); + } + break; + case Action::NOP: + // Intentionally left blank. + break; + default: + assert(!"unreachable"); + break; + } + actions.pop_front(); + } +} diff --git a/src/screen.h b/src/screen.h index 679ccd9..fb11512 100644 --- a/src/screen.h +++ b/src/screen.h @@ -1,6 +1,7 @@ #ifndef JUMPARTIFACT_DOT_COM_DEMO_0_SCREEN_H_ #define JUMPARTIFACT_DOT_COM_DEMO_0_SCREEN_H_ +#include #include #include @@ -31,12 +32,30 @@ class Screen { protected: Screen(std::weak_ptr stack); - - private: std::weak_ptr stack; }; class ScreenStack { + private: + enum Action { PUSH_SCREEN, POP_SCREEN, NOP }; + + struct PendingAction { + PendingAction(); + PendingAction(Action action); + PendingAction(Screen::Ptr&&); + + // No copy. + PendingAction(const PendingAction&) = delete; + PendingAction& operator=(const PendingAction&) = delete; + + // Allow move. + PendingAction(PendingAction&&) = default; + PendingAction& operator=(PendingAction&&) = default; + + Screen::Ptr screen; + Action action; + }; + public: using Ptr = std::shared_ptr; using Weak = std::weak_ptr; @@ -64,8 +83,11 @@ class ScreenStack { private: ScreenStack(); + void handle_pending_actions(); + Weak self_weak; std::vector stack; + std::deque actions; }; template