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()
: screen_stack(ScreenStack::new_instance()),
prev_time(std::chrono::steady_clock::now()) {
screen_stack->push_screen<TestScreen>();
}
prev_time(std::chrono::steady_clock::now()) {}
void Game::update() {
auto next_time = std::chrono::steady_clock::now();

View file

@ -1,7 +1,24 @@
#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) {}
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() {
std::shared_ptr<ScreenStack> ptr =
std::shared_ptr<ScreenStack>(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<TestScreen>(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::Ptr>(screen));
actions.push_back(PendingAction(std::forward<Screen::Ptr>(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();
}
}

View file

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