Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ///-------------------------------------------------------------------------------------------------
- // AppState.h
- #ifndef _APPSTATE_H_
- #define _APPSTATE_H_
- ///-------------------------------------------------------------------------------------------------
- #include <deque>
- ///-------------------------------------------------------------------------------------------------
- class AppState
- {
- public:
- // Possible return states of the program at the completion of an update call
- enum EApplicationState
- {
- eState_Running,
- eState_End,
- eState_ExitProgram,
- };
- // Pushes a new state onto the active state stack
- static void PushState(AppState * a_poState);
- // Generic interface for updating the active state
- static EApplicationState Update(float a_fDeltaTime);
- // Generic interface for rendering states on the active stack
- static bool Draw();
- // Initialises required static resources
- static bool Init();
- // Cleans up any remaining static resources
- static void Destruct();
- // Allows external classes to get the update timestep value
- static float GetUpdateTick() { return m_fUpdateTick; }
- protected:
- // Prevent external, non-child class objects from trying to create an instance of this class
- AppState();
- // Prevent external, non-child class objects from trying to destroy an instance of this class family
- virtual ~AppState();
- // Abstract function called when a new state is pushed onto the stack. Must be defined in child class
- virtual void OnInsert() {}
- // Abstract update function. Must be defined in child class
- virtual EApplicationState OnUpdate(float a_fUpdateTick) { return eState_ExitProgram; }
- // Abstract draw function. Must be defined in child class
- virtual void OnDraw() {}
- // Abstract function called when a state is popped from the stack. Must be defined in child class
- virtual void OnRemove() {}
- // Allows AppState to suspend/resume states if superceded by a new state
- virtual void OnSuspend() { m_bSuspended = true; };
- virtual void OnResume() { m_bSuspended = false; };
- // Suspend state of this object
- bool m_bSuspended;
- private:
- // Application active state stack
- static std::deque<AppState *> m_dequeGameStates;
- // Stack of application states to push onto the active state stack
- static std::deque<AppState *> m_dequeNewGameStates;
- // Update & draw timesteps
- static float m_fUpdateTick;
- static float m_fDrawTick;
- // Used to track milliseconds elapsed since the most recent processing of update/draw
- static float m_fTimeSinceLastUpdate;
- static float m_fTimeSinceLastDraw;
- }; // class AppState
- ///-------------------------------------------------------------------------------------------------
- #endif // #ifndef _APPSTATE_H_
- ///-------------------------------------------------------------------------------------------------
- // AppState.cpp
- #include "AppState.h"
- #include <assert.h>
- ///-------------------------------------------------------------------------------------------------
- // Init static member variables
- std::deque<AppState *> AppState::m_dequeGameStates;
- std::deque<AppState *> AppState::m_dequeNewGameStates;
- float AppState::m_fUpdateTick = 1.f / 60.f; // Fixed 60 updates per second
- float AppState::m_fDrawTick = 1.f / 60.f; // Max 60 draws per second
- float AppState::m_fTimeSinceLastUpdate = 0.f;
- float AppState::m_fTimeSinceLastDraw = 0.f;
- ///-------------------------------------------------------------------------------------------------
- void AppState::PushState(AppState * a_poState)
- {
- if (a_poState != nullptr) m_dequeNewGameStates.push_back(a_poState);
- }
- ///-------------------------------------------------------------------------------------------------
- AppState::EApplicationState AppState::Update(float a_fDeltaTime)
- {
- // Advance update & draw timers
- m_fTimeSinceLastUpdate += a_fDeltaTime;
- m_fTimeSinceLastDraw += a_fDeltaTime;
- // If enough time has accumulated to perform an update,
- while (m_fTimeSinceLastUpdate > m_fUpdateTick)
- {
- // Attempt to update the active state
- if (!m_dequeGameStates.empty())
- {
- AppState * poCurrentState = m_dequeGameStates.back();
- EApplicationState eStateResult = poCurrentState->OnUpdate(m_fUpdateTick);
- // On exit result, return exit
- if (eStateResult == eState_ExitProgram) return eStateResult;
- // If the current state has ended,
- if (eStateResult == AppState::eState_End)
- {
- // Remove this state from the stack
- m_dequeGameStates.pop_back();
- poCurrentState->OnRemove();
- // Delete the removed state
- delete poCurrentState;
- // If a buried state exits and there are no new states,
- if (m_dequeNewGameStates.empty() && !m_dequeGameStates.empty())
- {
- // Activate the buried state
- m_dequeGameStates.back()->m_bSuspended = false;
- m_dequeGameStates.back()->OnResume();
- }
- }
- }
- // While there are newly pushed states,
- while (!m_dequeNewGameStates.empty())
- {
- // Suspend the topmost state
- if (!m_dequeGameStates.empty()) m_dequeGameStates.back()->OnSuspend();
- // Pop the newly pushed state from the back of the new states deque and push it onto the stack
- m_dequeGameStates.push_back(m_dequeNewGameStates.front());
- m_dequeNewGameStates.front()->OnInsert();
- m_dequeNewGameStates.pop_front();
- // If there are no more new states to push, activate the topmost state on the stack
- if (m_dequeNewGameStates.empty()) m_dequeGameStates.back()->m_bSuspended = false;
- }
- // Decrease the elapsed time counter by the update timestep
- m_fTimeSinceLastUpdate -= m_fUpdateTick;
- }
- // If no states exist to process, exit program
- if (m_dequeGameStates.empty() && m_dequeNewGameStates.empty()) return eState_ExitProgram;
- // If the topmost state is suspended, something went wrong. Report error
- if (!m_dequeGameStates.empty() && m_dequeGameStates.back()->m_bSuspended) assert("GameState::Execute() active state currently in suspended state" == nullptr);
- return eState_Running;
- }
- ///-------------------------------------------------------------------------------------------------
- bool AppState::Draw()
- {
- // If too little time has elapsed since the previous draw, return
- if (m_fTimeSinceLastDraw < m_fDrawTick) return false;
- // Render all states on the stack, from bottom to top
- for (auto oIter : m_dequeGameStates) oIter->OnDraw();
- // Reset the time elapsed since draw variable
- m_fTimeSinceLastDraw = 0.f;
- return true;
- }
- ///-------------------------------------------------------------------------------------------------
- bool AppState::Init()
- {
- // Init any resources
- return true;
- }
- ///-------------------------------------------------------------------------------------------------
- void AppState::Destruct()
- {
- // Destroy any uninserted game states
- while (!m_dequeNewGameStates.empty())
- {
- auto oIter = m_dequeNewGameStates.front();
- delete oIter;
- m_dequeNewGameStates.pop_front();
- }
- // Destroy any active/inactive game states
- while (!m_dequeGameStates.empty())
- {
- auto oIter = m_dequeGameStates.front();
- delete oIter;
- m_dequeGameStates.pop_front();
- }
- }
- ///-------------------------------------------------------------------------------------------------
- AppState::AppState()
- : m_bSuspended (false)
- {
- }
- ///-------------------------------------------------------------------------------------------------
- AppState::~AppState()
- {
- }
- ///-------------------------------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement