Defer ScreenStack actions to start of update

This commit is contained in:
Stephen Seo 2023-07-31 20:39:46 +09:00
parent a617ef3fb6
commit 7a4c8ea0f5
3 changed files with 77 additions and 10 deletions

View file

@ -5,9 +5,7 @@
Game::Game() Game::Game()
: screen_stack(ScreenStack::new_instance()), : screen_stack(ScreenStack::new_instance()),
prev_time(std::chrono::steady_clock::now()) { prev_time(std::chrono::steady_clock::now()) {}
screen_stack->push_screen<TestScreen>();
}
void Game::update() { void Game::update() {
auto next_time = std::chrono::steady_clock::now(); auto next_time = std::chrono::steady_clock::now();

View file

@ -1,7 +1,24 @@
#include "screen.h" #include "screen.h"
// standard library includes
#include <cassert>
#ifndef NDEBUG
#include <iostream>
#endif // NDEBUG
// local includes
#include "screen_test.h"
Screen::Screen(std::weak_ptr<ScreenStack> stack) : stack(stack) {} Screen::Screen(std::weak_ptr<ScreenStack> 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::Ptr>(screen)), action(Action::PUSH_SCREEN) {}
ScreenStack::Ptr ScreenStack::new_instance() { ScreenStack::Ptr ScreenStack::new_instance() {
std::shared_ptr<ScreenStack> ptr = std::shared_ptr<ScreenStack> ptr =
std::shared_ptr<ScreenStack>(new ScreenStack{}); std::shared_ptr<ScreenStack>(new ScreenStack{});
@ -10,7 +27,17 @@ ScreenStack::Ptr ScreenStack::new_instance() {
} }
void ScreenStack::update(float dt) { void ScreenStack::update(float dt) {
handle_pending_actions();
auto idx = stack.size(); 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<TestScreen>(self_weak));
update(dt);
return;
}
while (idx > 0 && stack.at(--idx)->update(dt)) { while (idx > 0 && stack.at(--idx)->update(dt)) {
} }
} }
@ -22,13 +49,33 @@ void ScreenStack::draw() {
} }
void ScreenStack::push_screen(Screen::Ptr &&screen) { void ScreenStack::push_screen(Screen::Ptr &&screen) {
stack.emplace_back(std::forward<Screen::Ptr>(screen)); actions.push_back(PendingAction(std::forward<Screen::Ptr>(screen)));
} }
void ScreenStack::pop_screen() { void ScreenStack::pop_screen() {
if (!stack.empty()) { actions.push_back(PendingAction(Action::POP_SCREEN));
stack.pop_back();
}
} }
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();
}
}

View file

@ -1,6 +1,7 @@
#ifndef JUMPARTIFACT_DOT_COM_DEMO_0_SCREEN_H_ #ifndef JUMPARTIFACT_DOT_COM_DEMO_0_SCREEN_H_
#define JUMPARTIFACT_DOT_COM_DEMO_0_SCREEN_H_ #define JUMPARTIFACT_DOT_COM_DEMO_0_SCREEN_H_
#include <deque>
#include <memory> #include <memory>
#include <vector> #include <vector>
@ -31,12 +32,30 @@ class Screen {
protected: protected:
Screen(std::weak_ptr<ScreenStack> stack); Screen(std::weak_ptr<ScreenStack> stack);
private:
std::weak_ptr<ScreenStack> stack; std::weak_ptr<ScreenStack> stack;
}; };
class ScreenStack { 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: public:
using Ptr = std::shared_ptr<ScreenStack>; using Ptr = std::shared_ptr<ScreenStack>;
using Weak = std::weak_ptr<ScreenStack>; using Weak = std::weak_ptr<ScreenStack>;
@ -64,8 +83,11 @@ class ScreenStack {
private: private:
ScreenStack(); ScreenStack();
void handle_pending_actions();
Weak self_weak; Weak self_weak;
std::vector<Screen::Ptr> stack; std::vector<Screen::Ptr> stack;
std::deque<PendingAction> actions;
}; };
template <typename SubScreen> template <typename SubScreen>