Add StateMachine class
This commit is contained in:
@@ -0,0 +1,84 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace copium
|
||||||
|
{
|
||||||
|
template <typename State, typename Trigger>
|
||||||
|
class StateMachine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StateMachine(State initialState)
|
||||||
|
: currentState{initialState},
|
||||||
|
failOnInvalidTrigger{false}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
StateMachine(State initialState, bool failOnInvalidTrigger)
|
||||||
|
: currentState{initialState},
|
||||||
|
failOnInvalidTrigger{failOnInvalidTrigger}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddTransition(State from, State to, Trigger trigger)
|
||||||
|
{
|
||||||
|
auto& map = transitionMap[from];
|
||||||
|
CP_ASSERT(
|
||||||
|
map.find(trigger) == map.end(), "Transition already exists for state {} using trigger {}", from, trigger);
|
||||||
|
|
||||||
|
map[trigger] = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleTrigger(Trigger trigger)
|
||||||
|
{
|
||||||
|
auto& map = transitionMap[currentState];
|
||||||
|
auto it = map.find(trigger);
|
||||||
|
if (it == map.end())
|
||||||
|
{
|
||||||
|
CP_ASSERT(!failOnInvalidTrigger, "Trigger {} doesn't exist for state {}", trigger, currentState);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CP_DEBUG("Transitioning from state {} to state {} due to trigger {}", currentState, it->second, trigger);
|
||||||
|
RunTrigger(leaveTriggers);
|
||||||
|
currentState = it->second;
|
||||||
|
RunTrigger(enterTriggers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddEnterTrigger(State from, std::function<void()> func)
|
||||||
|
{
|
||||||
|
CP_ASSERT(enterTriggers.find(from) == enterTriggers.end(), "State {} already has an enter trigger", from);
|
||||||
|
enterTriggers[from] = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddLeaveTrigger(State from, std::function<void()> func)
|
||||||
|
{
|
||||||
|
CP_ASSERT(leaveTriggers.find(from) == leaveTriggers.end(), "State {} already has a leave trigger", from);
|
||||||
|
leaveTriggers[from] = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
State GetCurrentState() const
|
||||||
|
{
|
||||||
|
return currentState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
State currentState;
|
||||||
|
bool failOnInvalidTrigger;
|
||||||
|
|
||||||
|
std::map<State, std::map<Trigger, State>> transitionMap;
|
||||||
|
|
||||||
|
std::map<State, std::function<void()>> enterTriggers;
|
||||||
|
std::map<State, std::function<void()>> leaveTriggers;
|
||||||
|
|
||||||
|
void RunTrigger(const std::map<State, std::function<void()>>& triggers)
|
||||||
|
{
|
||||||
|
auto it = triggers.find(currentState);
|
||||||
|
if (it != triggers.end())
|
||||||
|
{
|
||||||
|
it->second();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user