Nymph Game Engine
Chaiscript based Game Engine
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
fsm.hpp
Go to the documentation of this file.
1 #ifndef FSM_H
2 #define FSM_H
3 #include <memory>
4 #include <stdexcept>
5 #include <type_traits>
6 #include "events/subject.h"
7 
8 namespace Events {
9  namespace FSM {
17  template<class DataType, typename StateType, typename TransitionType>
18  class StateReactor {
19  protected:
20  std::shared_ptr<DataType> data;
22  StateType state_type;
23  public:
24  StateReactor() = delete;
33  StateReactor(const StateType& state_type, const std::shared_ptr<DataType>& data_to_mutate, Subject* subject) : data(data_to_mutate), subject(subject), state_type(state_type) { }
34 
35  constexpr StateType getStateType() const noexcept {
36  return state_type;
37  }
38 
42  virtual void enterState() {}
52  virtual bool updateState(const double delta, TransitionType& transition_type) { return false; }
56  virtual void leaveState() {}
57 
66  virtual StateType react(const TransitionType transition) { return (StateType)0; }
67  };
68 
77  template<typename DataType, typename StateType, typename TransitionType, typename... Reactor>
78  class FSM : public std::enable_shared_from_this<FSM<DataType, StateType, TransitionType, Reactor...>> {
79  private:
80  std::shared_ptr<DataType> data;
81  Subject* subject;
82  StateType current_state;
83  StateType end_state;
84  bool is_terminated;
85 
86  std::map<StateType, std::shared_ptr<StateReactor<DataType, StateType, TransitionType>>> states;
87  bool running;
88 
89  template<typename T>
90  void unpackReactorAndMakeShared(const std::shared_ptr<T>& t) {
91  states[t->getStateType()] = t;
92  }
93 
94  template<typename T, typename... R>
95  void unpackReactorAndMakeShared(const std::shared_ptr<T>& t, const std::shared_ptr<R>&... reactors) {
96  states[t->getStateType()] = t;
97 
98  unpackReactorAndMakeShared(reactors...);
99  }
100 
101  template<typename... R>
102  void unpackAndConstructReactors() {
103  unpackReactorAndMakeShared<R...>(std::make_shared<R>(data, subject)...);
104  }
105 
106  public:
107  FSM() = delete;
115  FSM(const std::shared_ptr<DataType>& data_to_mutate, const StateType& begin_state, Subject* subject) : data(data_to_mutate), subject(subject), current_state(begin_state), is_terminated(false), running(false) {
116  if(data_to_mutate == nullptr) {
117  throw std::invalid_argument("FSM::data_to_mutate cannot be nullptr");
118  }
119 
120  unpackAndConstructReactors<Reactor...>();
121  }
122 
131  FSM(const std::shared_ptr<DataType>& data_to_mutate, const StateType& begin_state, const StateType& end_state, Subject* subject) : data(data_to_mutate), current_state(begin_state), end_state(end_state), is_terminated(true), subject(subject) {
132  if(data_to_mutate == nullptr) {
133  throw std::invalid_argument("FSM::data_to_mutate cannot be nullptr");
134  }
135 
136  unpackAndConstructReactors<Reactor...>();
137  }
138 
145  void transition(const TransitionType transition_type) {
146  auto new_state_type = states[current_state]->react(transition_type);
147  if(new_state_type != current_state) {
148  states[current_state]->leaveState();
149  current_state = new_state_type;
150  states[current_state]->enterState();
151  }
152  if(is_terminated && current_state == end_state) {
153  running = false;
154  }
155  }
156 
163  constexpr bool inFinalState() const noexcept {
164  return is_terminated && current_state == end_state;
165  }
166 
170  void start() {
171  running = true;
172  }
173 
179  void update(const double delta) {
180  if(running) {
181  TransitionType t;
182  if(states[current_state]->updateState(delta, t)) {
183  transition(t);
184  }
185  }
186  }
187 
191  void stop() {
192  running = false;
193  }
194  };
195  }
196 }
197 
198 #endif
StateReactor(const StateType &state_type, const std::shared_ptr< DataType > &data_to_mutate, Subject *subject)
StateReactor constructor. This sets which state this reactor is for and sets the data to be mutated...
Definition: fsm.hpp:33
Class for state reactor.
Definition: fsm.hpp:18
StateType state_type
Definition: fsm.hpp:22
constexpr StateType getStateType() const noexcept
Definition: fsm.hpp:35
virtual StateType react(const TransitionType transition)
This function is used to set up reactions for different types of transitions for this state...
Definition: fsm.hpp:66
Class for a subject that an observer would observe for changes.
Definition: subject.h:13
void transition(const TransitionType transition_type)
Sends a transition value to the FSM, causing the current state to react, and possible transition...
Definition: fsm.hpp:145
constexpr bool inFinalState() const noexcept
Check to see if the FSM is in it's final state.
Definition: fsm.hpp:163
virtual void leaveState()
leaveState is called upon triggering of a new state from this state.
Definition: fsm.hpp:56
FSM(const std::shared_ptr< DataType > &data_to_mutate, const StateType &begin_state, Subject *subject)
Finite state machine constructor.
Definition: fsm.hpp:115
void stop()
Stops the FSM.
Definition: fsm.hpp:191
void start()
Starts the FSM.
Definition: fsm.hpp:170
FSM(const std::shared_ptr< DataType > &data_to_mutate, const StateType &begin_state, const StateType &end_state, Subject *subject)
Finite state machine constructor for a terminated FSM.
Definition: fsm.hpp:131
Subject * subject
Definition: fsm.hpp:21
virtual bool updateState(const double delta, TransitionType &transition_type)
updateState is called once per engine loop for timed updates
Definition: fsm.hpp:52
void update(const double delta)
Update is called once per update loop in the engine.
Definition: fsm.hpp:179
virtual void enterState()
enterState is called upon triggering of this state
Definition: fsm.hpp:42
std::shared_ptr< DataType > data
Definition: fsm.hpp:20
Generic Finite State Machine.
Definition: fsm.hpp:78