Added FSM and Game State Manager
This commit is contained in:
parent
78629be4d8
commit
e4de32f9f7
Binary file not shown.
@ -87,7 +87,7 @@ public:
|
||||
sprite->Play("Idle");
|
||||
if (!Game::gravityOnPlayer){
|
||||
Game::gravityOnPlayer = true;
|
||||
sprite->Play("Fall");
|
||||
// sprite->Play("Fall");
|
||||
}
|
||||
break;
|
||||
case SDLK_RIGHT:
|
||||
@ -108,6 +108,13 @@ public:
|
||||
transform->velocity.y = 0;
|
||||
sprite->Play("Fall");
|
||||
Game::gravityOnPlayer = true;
|
||||
break;
|
||||
case SDLK_u:
|
||||
// Advance the GSM state via the u key
|
||||
Game::gsm->AdvanceState();
|
||||
break;
|
||||
case SDLK_i:
|
||||
Game::gsm->GameOver();
|
||||
break;
|
||||
case SDLK_ESCAPE: // exit the game when Escape pressed
|
||||
Game::isRunning = false;
|
||||
|
@ -28,6 +28,7 @@ UIText* text;
|
||||
UINineSlice* my9Slice;
|
||||
UIText* scoreboardText;
|
||||
UINineSlice* scoreboard9Slice;
|
||||
GameStateManager* Game::gsm = new GameStateManager();
|
||||
|
||||
SDL_Renderer* Game::renderer = nullptr;
|
||||
SDL_Event Game::event;
|
||||
@ -243,7 +244,10 @@ void Game::update()
|
||||
void Game::render()
|
||||
{
|
||||
SDL_RenderClear(renderer);
|
||||
|
||||
// if (gsm->currentState==GameStateManager::ST_COREGAME)
|
||||
// {
|
||||
// printf("Core Game state\n");
|
||||
// }
|
||||
for (auto& t : tiles)
|
||||
{
|
||||
t->draw();
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <vector>
|
||||
#include "Vector2D.h"
|
||||
#include "../assetmgr/AssetManager.h"
|
||||
#include "GameStateManager.h"
|
||||
|
||||
class ColliderComponent;
|
||||
class AssetManager;
|
||||
@ -41,6 +42,7 @@ public:
|
||||
static bool playerIsGrounded;
|
||||
static SDL_Rect camera;
|
||||
static AssetManager* assets;
|
||||
static GameStateManager* gsm;
|
||||
enum groupLabels : std::size_t
|
||||
{
|
||||
groupMap,
|
||||
|
95
src/game/GameStateManager.cpp
Normal file
95
src/game/GameStateManager.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
#include <assert.h>
|
||||
#include "GameStateManager.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void GameStateManager::AdvanceState()
|
||||
{
|
||||
//given the AdvanceState event transition to a new state based on current state and gameData
|
||||
BEGIN_TRANSITION_MAP // (Next State) // - Current State -
|
||||
TRANSITION_MAP_ENTRY (ST_TITLESCREEN) // ST_Init
|
||||
TRANSITION_MAP_ENTRY (ST_COREGAME) // ST_TitleScreen
|
||||
TRANSITION_MAP_ENTRY (EVENT_IGNORED) // ST_Instructions
|
||||
TRANSITION_MAP_ENTRY (EVENT_IGNORED) // ST_HiScoreList
|
||||
TRANSITION_MAP_ENTRY (EVENT_IGNORED) // ST_Credits
|
||||
TRANSITION_MAP_ENTRY (EVENT_IGNORED) // ST_CoreGame
|
||||
TRANSITION_MAP_ENTRY (ST_COREGAME) // ST_PauseScreen
|
||||
TRANSITION_MAP_ENTRY (ST_INIT) // ST_GameOver
|
||||
END_TRANSITION_MAP(NULL)
|
||||
}
|
||||
|
||||
void GameStateManager::PauseGame(GameData* gameData)
|
||||
{
|
||||
// given the PauseGame event transition to a new state based on current state and gameData
|
||||
// printf("gameData->isPaused: %d\n",gameData->isPaused);
|
||||
BEGIN_TRANSITION_MAP // - Current State -
|
||||
TRANSITION_MAP_ENTRY (EVENT_IGNORED) // ST_Init
|
||||
TRANSITION_MAP_ENTRY (EVENT_IGNORED) // ST_TitleScreen
|
||||
TRANSITION_MAP_ENTRY (EVENT_IGNORED) // ST_Instructions
|
||||
TRANSITION_MAP_ENTRY (EVENT_IGNORED) // ST_HiScoreList
|
||||
TRANSITION_MAP_ENTRY (EVENT_IGNORED) // ST_Credits
|
||||
TRANSITION_MAP_ENTRY (EVENT_IGNORED) // ST_CoreGame
|
||||
TRANSITION_MAP_ENTRY (ST_INSTRUCTIONS) // ST_PauseScreen
|
||||
TRANSITION_MAP_ENTRY (CANNOT_HAPPEN) // ST_GameOver
|
||||
END_TRANSITION_MAP(gameData)
|
||||
|
||||
}
|
||||
void GameStateManager::GameOver()
|
||||
{
|
||||
//given the PauseGame event transition to a new state based on current state and gameData
|
||||
// printf("GameOver triggered\n");
|
||||
BEGIN_TRANSITION_MAP // - Current State -
|
||||
TRANSITION_MAP_ENTRY (EVENT_IGNORED) // ST_Init
|
||||
TRANSITION_MAP_ENTRY (EVENT_IGNORED) // ST_TitleScreen
|
||||
TRANSITION_MAP_ENTRY (EVENT_IGNORED) // ST_Instructions
|
||||
TRANSITION_MAP_ENTRY (EVENT_IGNORED) // ST_HiScoreList
|
||||
TRANSITION_MAP_ENTRY (EVENT_IGNORED) // ST_Credits
|
||||
TRANSITION_MAP_ENTRY (ST_GAMEOVER) // ST_CoreGame
|
||||
TRANSITION_MAP_ENTRY (EVENT_IGNORED) // ST_PauseScreen
|
||||
TRANSITION_MAP_ENTRY (EVENT_IGNORED) // ST_GameOver
|
||||
END_TRANSITION_MAP(NULL)
|
||||
}
|
||||
|
||||
void GameStateManager::ST_Init(EventData*)
|
||||
{
|
||||
printf("GameStateManager::ST_Init\n");
|
||||
// InternalEvent(ST_TITLESCREEN);
|
||||
}
|
||||
|
||||
void GameStateManager::ST_TitleScreen(EventData*)
|
||||
{
|
||||
printf("GameStateManager::ST_TitleScreen\n");
|
||||
// InternalEvent(ST_TITLESCREEN);
|
||||
}
|
||||
|
||||
void GameStateManager::ST_Instructions(GameData*)
|
||||
{
|
||||
printf("GameStateManager::ST_Instructions\n");
|
||||
}
|
||||
|
||||
void GameStateManager::ST_HiScoreList(GameData*)
|
||||
{
|
||||
printf("GameStateManager::ST_HiScoreList\n");
|
||||
}
|
||||
|
||||
void GameStateManager::ST_Credits(GameData*)
|
||||
{
|
||||
printf("GameStateManager::ST_Credits\n");
|
||||
}
|
||||
|
||||
void GameStateManager::ST_CoreGame(EventData*)
|
||||
{
|
||||
printf("GameStateManager::ST_CoreGame\n");
|
||||
}
|
||||
|
||||
void GameStateManager::ST_PauseScreen(EventData*)
|
||||
{
|
||||
printf("GameStateManager::ST_PauseScreen\n");
|
||||
}
|
||||
|
||||
void GameStateManager::ST_GameOver(GameData*)
|
||||
{
|
||||
printf("GameStateManager::ST_GameOver\n");
|
||||
}
|
||||
|
57
src/game/GameStateManager.h
Normal file
57
src/game/GameStateManager.h
Normal file
@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
#include "StateMachine.h"
|
||||
|
||||
// Structure to hold event data passed into state StateMachine
|
||||
struct GameData : public EventData
|
||||
{
|
||||
char* menuId;
|
||||
bool win;
|
||||
};
|
||||
|
||||
// The Game State Machine Class
|
||||
class GameStateManager : public StateMachine
|
||||
{
|
||||
public:
|
||||
GameStateManager() : StateMachine(ST_MAX_STATES) {}
|
||||
|
||||
// external events taken by this state machine
|
||||
void AdvanceState();
|
||||
void GameOver();
|
||||
void PauseGame(GameData* gameData);
|
||||
private:
|
||||
//state machine state functions
|
||||
void ST_Init(EventData*);
|
||||
void ST_TitleScreen(EventData*);
|
||||
void ST_Instructions(GameData*);
|
||||
void ST_HiScoreList(GameData*);
|
||||
void ST_Credits(GameData*);
|
||||
void ST_CoreGame(EventData*);
|
||||
void ST_PauseScreen(EventData*);
|
||||
void ST_GameOver(GameData*);
|
||||
|
||||
//state map to define state function order
|
||||
BEGIN_STATE_MAP
|
||||
STATE_MAP_ENTRY(&GameStateManager::ST_Init)
|
||||
STATE_MAP_ENTRY(&GameStateManager::ST_TitleScreen)
|
||||
STATE_MAP_ENTRY(&GameStateManager::ST_Instructions)
|
||||
STATE_MAP_ENTRY(&GameStateManager::ST_HiScoreList)
|
||||
STATE_MAP_ENTRY(&GameStateManager::ST_Credits)
|
||||
STATE_MAP_ENTRY(&GameStateManager::ST_CoreGame)
|
||||
STATE_MAP_ENTRY(&GameStateManager::ST_PauseScreen)
|
||||
STATE_MAP_ENTRY(&GameStateManager::ST_GameOver)
|
||||
END_STATE_MAP
|
||||
|
||||
//state enumeration order must match order of state method entries on state map
|
||||
enum E_States {
|
||||
ST_INIT = 0,
|
||||
ST_TITLESCREEN,
|
||||
ST_INSTRUCTIONS,
|
||||
ST_HISCORELIST,
|
||||
ST_CREDITS,
|
||||
ST_COREGAME,
|
||||
ST_PAUSESCREEN,
|
||||
ST_GAMEOVER,
|
||||
ST_MAX_STATES
|
||||
};
|
||||
};
|
||||
|
84
src/game/StateMachine.cpp
Normal file
84
src/game/StateMachine.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
#include <assert.h>
|
||||
#include "StateMachine.h"
|
||||
// =============================================================================
|
||||
// Do NOT modify this file, instead make custom changes in the GameStateManager
|
||||
// or create your own StateMachine including and implementing this header
|
||||
// =============================================================================
|
||||
|
||||
StateMachine::StateMachine(unsigned char maxStates) :
|
||||
currentState(0),
|
||||
_maxStates(maxStates),
|
||||
_eventGenerated(false),
|
||||
_pEventData(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
// generates an external event. called once per external event
|
||||
// to start the state machine executing
|
||||
void StateMachine::ExternalEvent(unsigned char newState,
|
||||
EventData* pData)
|
||||
{
|
||||
// if we are supposed to ignore this event
|
||||
if (newState == EVENT_IGNORED) {
|
||||
// just delete the event data, if any
|
||||
if (pData)
|
||||
delete pData;
|
||||
}
|
||||
else {
|
||||
// TODO - capture software lock here for thread-safety if necessary
|
||||
|
||||
// generate the event and execute the state engine
|
||||
InternalEvent(newState, pData);
|
||||
StateEngine();
|
||||
|
||||
// TODO - release software lock here
|
||||
}
|
||||
}
|
||||
|
||||
// generates an internal event. called from within a state
|
||||
// function to transition to a new state
|
||||
void StateMachine::InternalEvent(unsigned char newState,
|
||||
EventData* pData)
|
||||
{
|
||||
if (pData == NULL)
|
||||
pData = new EventData();
|
||||
|
||||
_pEventData = pData;
|
||||
_eventGenerated = true;
|
||||
currentState = newState;
|
||||
}
|
||||
|
||||
// the state engine executes the state machine states
|
||||
void StateMachine::StateEngine(void)
|
||||
{
|
||||
EventData* pDataTemp = NULL;
|
||||
|
||||
// while events are being generated keep executing states
|
||||
while (_eventGenerated) {
|
||||
pDataTemp = _pEventData; // copy of event data pointer
|
||||
_pEventData = NULL; // event data used up, reset ptr
|
||||
_eventGenerated = false; // event used up, reset flag
|
||||
|
||||
assert(currentState < _maxStates);
|
||||
|
||||
// get state map
|
||||
const StateStruct* pStateMap = GetStateMap();
|
||||
|
||||
// execute the state passing in event data, if any
|
||||
(this->*pStateMap[currentState].pStateFunc)(pDataTemp);
|
||||
|
||||
// if event data was used, then delete it
|
||||
if (pDataTemp) {
|
||||
delete pDataTemp;
|
||||
pDataTemp = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unsigned char getCurrentState()
|
||||
// {
|
||||
// const StateStruct* pStateMap = GetStateMap();
|
||||
// this->*pStateMap[currentState];
|
||||
// unsigned char state = StateMachine.currentState;
|
||||
// return state;
|
||||
// }
|
64
src/game/StateMachine.h
Normal file
64
src/game/StateMachine.h
Normal file
@ -0,0 +1,64 @@
|
||||
#ifndef _STATE_MACHINE_H
|
||||
#define _STATE_MACHINE_H
|
||||
#include <stdio.h>
|
||||
// =============================================================================
|
||||
// Do NOT modify this file, instead make custom changes in the GameStateManager
|
||||
// or create your own StateMachine including and implementing this header
|
||||
// =============================================================================
|
||||
class EventData
|
||||
{
|
||||
public:
|
||||
virtual ~EventData() {};
|
||||
};
|
||||
|
||||
struct StateStruct;
|
||||
|
||||
// base class for state machines
|
||||
class StateMachine
|
||||
{
|
||||
public:
|
||||
StateMachine(unsigned char maxStates);
|
||||
virtual ~StateMachine() {}
|
||||
// unsigned char getCurrentState();
|
||||
unsigned char currentState;
|
||||
protected:
|
||||
enum { EVENT_IGNORED = 0xFE, CANNOT_HAPPEN };
|
||||
void ExternalEvent(unsigned char, EventData* = NULL);
|
||||
void InternalEvent(unsigned char, EventData* = NULL);
|
||||
virtual const StateStruct* GetStateMap() = 0;
|
||||
private:
|
||||
const unsigned char _maxStates;
|
||||
bool _eventGenerated;
|
||||
EventData* _pEventData;
|
||||
void StateEngine(void);
|
||||
};
|
||||
|
||||
typedef void (StateMachine::*StateFunc)(EventData *);
|
||||
struct StateStruct
|
||||
{
|
||||
StateFunc pStateFunc;
|
||||
};
|
||||
|
||||
#define BEGIN_STATE_MAP \
|
||||
public:\
|
||||
const StateStruct* GetStateMap() {\
|
||||
static const StateStruct StateMap[] = {
|
||||
|
||||
#define STATE_MAP_ENTRY(stateFunc)\
|
||||
{ reinterpret_cast<StateFunc>(stateFunc) },
|
||||
|
||||
#define END_STATE_MAP \
|
||||
}; \
|
||||
return &StateMap[0]; }
|
||||
|
||||
#define BEGIN_TRANSITION_MAP \
|
||||
static const unsigned char TRANSITIONS[] = {\
|
||||
|
||||
#define TRANSITION_MAP_ENTRY(entry)\
|
||||
entry,
|
||||
|
||||
#define END_TRANSITION_MAP(data) \
|
||||
0 };\
|
||||
ExternalEvent(TRANSITIONS[currentState], data);
|
||||
|
||||
#endif //STATE_MACHINE_H
|
Loading…
Reference in New Issue
Block a user