Nymph Game Engine
Chaiscript based Game Engine
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
sprite_movement.h
Go to the documentation of this file.
1 #ifndef SPRITE_MOVEMENT_H
2 #define SPRITE_MOVEMENT_H
3 #include <glm/glm.hpp>
4 #include <map>
5 #include <memory>
6 #include "events/event.h"
8 #include <list>
9 #include "component.h"
10 #include "events/fsm/fsm.hpp"
11 #include "sprite_move_event.h"
13 
14 
15 namespace Game {
16 
25  enum SpriteInput : unsigned int {LEFT, RIGHT, UP, DOWN, NONE};
29  struct SpriteData {
30  float moving_speed;
32  glm::vec2 current_velocity;
33  glm::vec2 next_position;
34  glm::ivec2 tile_location;
36  std::shared_ptr<Transform> transform;
37  std::shared_ptr<Physics::CollisionData> collision_data;
38  };
44  static std::shared_ptr<SpriteData> defaultSpriteData() {
45  return std::make_shared<SpriteData>(SpriteData {
46  1.0,
47  1.0,
48  glm::vec2(),
49  glm::vec2(),
50  glm::ivec2(),
51  0,
52  nullptr,
53  nullptr
54  });
55  }
56 
66  static bool updateSprite(const std::shared_ptr<SpriteData> data, const SpriteState current_state, const double delta) {
67  if(current_state == MOVE_LEFT || current_state == MOVE_RIGHT ||
68  current_state == MOVE_UP || current_state == MOVE_DOWN) {
69  if(glm::distance(glm::vec2(data->transform->getAbsoluteTranslation()), data->next_position) > glm::length(data->current_velocity * 1.0f / 1000.0f * (float)delta)) {
70  data->transform->getParent()->translate(data->current_velocity * 1.0f / 1000.0f * (float)delta);
71  return true;
72  }
73  else {
74  data->transform->getParent()->translate(data->next_position - glm::vec2(data->transform->getAbsoluteTranslation()));
75  return false;
76  }
77  }
78  else {
79  return false;
80  }
81  }
82 
83 
84  class MoveUpReactor : public Events::FSM::StateReactor<SpriteData, SpriteState, SpriteInput> {
85  public:
86  MoveUpReactor(const std::shared_ptr<SpriteData>& data, Events::Subject* subject) : StateReactor(MOVE_UP, data, subject) {}
87  virtual void enterState() override {
88  data->current_velocity = glm::vec2(0.0, data->moving_speed);
89  data->next_position = glm::vec2(data->transform->getAbsoluteTranslation()) + glm::normalize(data->current_velocity) * data->move_quantization_in_tiles;
90  data->tile_location += glm::ivec2(0, -1);
91 
92  auto absolute_next_position = glm::vec2(data->transform->getAbsoluteTranslation()) + glm::normalize(data->current_velocity) * data->move_quantization_in_tiles;
93 
95  subject->notify(SpriteMoveEvent::create(data->current_velocity, absolute_next_position));
96  }
97 
98  virtual bool updateState(const double delta, SpriteInput& t) override {
99  if(!updateSprite(data, getStateType(), delta)) {
100  t = NONE;
101  return true;
102  }
103  return false;
104  }
105 
106  virtual SpriteState react(const SpriteInput transition) override {
107  switch(transition) {
108  case NONE: {
109  return FACE_UP;
110  }
111  default: {
112  return MOVE_UP;
113  }
114  };
115  }
116  };
117 
118  class FaceUpReactor : public Events::FSM::StateReactor<SpriteData, SpriteState, SpriteInput> {
119  public:
120  FaceUpReactor() = delete;
121  FaceUpReactor(const std::shared_ptr<SpriteData>& data, Events::Subject* subject) : StateReactor(FACE_UP, data, subject) {}
122  virtual void enterState() override {
123  data->current_velocity = glm::vec2(0.0, 0.0);
124  data->next_position = glm::vec2(data->transform->getAbsoluteTranslation());
125 
127  }
128 
129  virtual SpriteState react(const SpriteInput transition) override {
130  switch(transition) {
131  case LEFT: {
132  if(data->collision_data->getCollideLevel(data->tile_location.x - 1, data->tile_location.y) < data->current_level) {
133  return MOVE_LEFT;
134  }
135  else {
136  return FACE_LEFT;
137  }
138  }
139  case RIGHT: {
140  if(data->collision_data->getCollideLevel(data->tile_location.x + 1, data->tile_location.y) < data->current_level) {
141  return MOVE_RIGHT;
142  }
143  else {
144  return FACE_RIGHT;
145  }
146  }
147  case UP: {
148  if(data->collision_data->getCollideLevel(data->tile_location.x, data->tile_location.y - 1) < data->current_level) {
149  return MOVE_UP;
150  }
151  else {
152  return FACE_UP;
153  }
154  }
155  case DOWN: {
156  if(data->collision_data->getCollideLevel(data->tile_location.x, data->tile_location.y + 1) < data->current_level) {
157  return MOVE_DOWN;
158  }
159  else {
160  return FACE_DOWN;
161  }
162  }
163  case NONE: {
164  return FACE_UP;
165  }
166  };
167  }
168  };
169 
170  class MoveDownReactor : public Events::FSM::StateReactor<SpriteData, SpriteState, SpriteInput> {
171  public:
172  MoveDownReactor() = delete;
173  MoveDownReactor(const std::shared_ptr<SpriteData>& data, Events::Subject* subject) : StateReactor(MOVE_DOWN, data, subject) {}
174  virtual void enterState() override {
175  data->current_velocity = glm::vec2(0.0, -data->moving_speed);
176  data->next_position = glm::vec2(data->transform->getAbsoluteTranslation()) + glm::normalize(data->current_velocity) * data->move_quantization_in_tiles;
177  data->tile_location += glm::ivec2(0, 1);
178 
179  auto absolute_next_position = glm::vec2(data->transform->getAbsoluteTranslation()) + glm::normalize(data->current_velocity) * data->move_quantization_in_tiles;
180 
182  subject->notify(SpriteMoveEvent::create(data->current_velocity, absolute_next_position));
183  }
184 
185  virtual bool updateState(const double delta, SpriteInput& t) override {
186  if(!updateSprite(data, getStateType(), delta)) {
187  t = NONE;
188  return true;
189  }
190  return false;
191  }
192 
193  virtual SpriteState react(const SpriteInput transition) override {
194  switch(transition) {
195  case NONE: {
196  return FACE_DOWN;
197  }
198  default: {
199  return MOVE_DOWN;
200  }
201  };
202  }
203  };
204 
205  class FaceDownReactor : public Events::FSM::StateReactor<SpriteData, SpriteState, SpriteInput> {
206  public:
207  FaceDownReactor() = delete;
208  FaceDownReactor(const std::shared_ptr<SpriteData>& data, Events::Subject* subject) : StateReactor(FACE_DOWN, data, subject) {}
209  virtual void enterState() override {
210  data->current_velocity = glm::vec2(0.0, 0.0);
211  data->next_position = glm::vec2(data->transform->getAbsoluteTranslation());
212 
214  }
215 
216  virtual SpriteState react(const SpriteInput transition) override {
217  switch(transition) {
218  case LEFT: {
219  if(data->collision_data->getCollideLevel(data->tile_location.x - 1, data->tile_location.y) < data->current_level) {
220  return MOVE_LEFT;
221  }
222  else {
223  return FACE_LEFT;
224  }
225  }
226  case RIGHT: {
227  if(data->collision_data->getCollideLevel(data->tile_location.x + 1, data->tile_location.y) < data->current_level) {
228  return MOVE_RIGHT;
229  }
230  else {
231  return FACE_RIGHT;
232  }
233  }
234  case UP: {
235  if(data->collision_data->getCollideLevel(data->tile_location.x, data->tile_location.y - 1) < data->current_level) {
236  return MOVE_UP;
237  }
238  else {
239  return FACE_UP;
240  }
241  }
242  case DOWN: {
243  if(data->collision_data->getCollideLevel(data->tile_location.x, data->tile_location.y + 1) < data->current_level) {
244  return MOVE_DOWN;
245  }
246  else {
247  return FACE_DOWN;
248  }
249  }
250  case NONE: {
251  return FACE_DOWN;
252  }
253  };
254  }
255  };
256 
257  class MoveLeftReactor : public Events::FSM::StateReactor<SpriteData, SpriteState, SpriteInput> {
258  public:
259  MoveLeftReactor() = delete;
260  MoveLeftReactor(const std::shared_ptr<SpriteData>& data, Events::Subject* subject) : StateReactor(MOVE_LEFT, data, subject) {}
261  virtual void enterState() override {
262  data->current_velocity = glm::vec2(-data->moving_speed, 0.0);
263  data->next_position = glm::vec2(data->transform->getAbsoluteTranslation()) + glm::normalize(data->current_velocity) * data->move_quantization_in_tiles;
264  data->tile_location += glm::ivec2(-1, 0);
265 
266  auto absolute_next_position = glm::vec2(data->transform->getAbsoluteTranslation()) + glm::normalize(data->current_velocity) * data->move_quantization_in_tiles;
267 
269  subject->notify(SpriteMoveEvent::create(data->current_velocity, absolute_next_position));
270  }
271 
272  virtual bool updateState(const double delta, SpriteInput& t) override {
273  if(!updateSprite(data, getStateType(), delta)) {
274  t = NONE;
275  return true;
276  }
277  return false;
278  }
279 
280  virtual SpriteState react(const SpriteInput transition) override {
281  switch(transition) {
282  case NONE: {
283  return FACE_LEFT;
284  }
285  default: {
286  return MOVE_LEFT;
287  }
288  };
289  }
290  };
291 
292  class FaceLeftReactor : public Events::FSM::StateReactor<SpriteData, SpriteState, SpriteInput> {
293  public:
294  FaceLeftReactor() = delete;
295  FaceLeftReactor(const std::shared_ptr<SpriteData>& data, Events::Subject* subject) : StateReactor(FACE_LEFT, data, subject) {}
296  virtual void enterState() override {
297  data->current_velocity = glm::vec2(0.0, 0.0);
298  data->next_position = glm::vec2(data->transform->getAbsoluteTranslation());
299 
301  }
302 
303  virtual SpriteState react(const SpriteInput transition) override {
304  switch(transition) {
305  case LEFT: {
306  if(data->collision_data->getCollideLevel(data->tile_location.x - 1, data->tile_location.y) < data->current_level) {
307  return MOVE_LEFT;
308  }
309  else {
310  return FACE_LEFT;
311  }
312  }
313  case RIGHT: {
314  if(data->collision_data->getCollideLevel(data->tile_location.x + 1, data->tile_location.y) < data->current_level) {
315  return MOVE_RIGHT;
316  }
317  else {
318  return FACE_RIGHT;
319  }
320  }
321  case UP: {
322  if(data->collision_data->getCollideLevel(data->tile_location.x, data->tile_location.y - 1) < data->current_level) {
323  return MOVE_UP;
324  }
325  else {
326  return FACE_UP;
327  }
328  }
329  case DOWN: {
330  if(data->collision_data->getCollideLevel(data->tile_location.x, data->tile_location.y + 1) < data->current_level) {
331  return MOVE_DOWN;
332  }
333  else {
334  return FACE_DOWN;
335  }
336  }
337  case NONE: {
338  return FACE_LEFT;
339  }
340  };
341  }
342  };
343 
344  class MoveRightReactor : public Events::FSM::StateReactor<SpriteData, SpriteState, SpriteInput> {
345  public:
346  MoveRightReactor() = delete;
347  MoveRightReactor(const std::shared_ptr<SpriteData>& data, Events::Subject* subject) : StateReactor(MOVE_RIGHT, data, subject) {}
348  virtual void enterState() override {
349  data->current_velocity = glm::vec2(data->moving_speed, 0.0);
350  data->next_position = glm::vec2(data->transform->getAbsoluteTranslation()) + glm::normalize(data->current_velocity) * data->move_quantization_in_tiles;
351  data->tile_location += glm::ivec2(1, 0);
352 
353  auto absolute_next_position = glm::vec2(data->transform->getAbsoluteTranslation()) + glm::normalize(data->current_velocity) * data->move_quantization_in_tiles;
354 
356  subject->notify(SpriteMoveEvent::create(data->current_velocity, absolute_next_position));
357  }
358 
359  virtual bool updateState(const double delta, SpriteInput& t) override {
360  if(!updateSprite(data, getStateType(), delta)) {
361  t = NONE;
362  return true;
363  }
364  return false;
365  }
366 
367  virtual SpriteState react(const SpriteInput transition) override {
368  switch(transition) {
369  case NONE: {
370  return FACE_RIGHT;
371  }
372  default: {
373  return MOVE_RIGHT;
374  }
375  };
376  }
377  };
378 
379  class FaceRightReactor : public Events::FSM::StateReactor<SpriteData, SpriteState, SpriteInput> {
380  public:
381  FaceRightReactor() = delete;
382  FaceRightReactor(const std::shared_ptr<SpriteData>& data, Events::Subject* subject) : StateReactor(FACE_RIGHT, data, subject) {}
383  virtual void enterState() override {
384  data->current_velocity = glm::vec2(0.0, 0.0);
385  data->next_position = glm::vec2(data->transform->getAbsoluteTranslation());
386 
388  }
389 
390  virtual SpriteState react(const SpriteInput transition) override {
391  switch(transition) {
392  case LEFT: {
393  if(data->collision_data->getCollideLevel(data->tile_location.x - 1, data->tile_location.y) < data->current_level) {
394  return MOVE_LEFT;
395  }
396  else {
397  return FACE_LEFT;
398  }
399  }
400  case RIGHT: {
401  if(data->collision_data->getCollideLevel(data->tile_location.x + 1, data->tile_location.y) < data->current_level) {
402  return MOVE_RIGHT;
403  }
404  else {
405  return FACE_RIGHT;
406  }
407  }
408  case UP: {
409  if(data->collision_data->getCollideLevel(data->tile_location.x, data->tile_location.y - 1) < data->current_level) {
410  return MOVE_UP;
411  }
412  else {
413  return FACE_UP;
414  }
415  }
416  case DOWN: {
417  if(data->collision_data->getCollideLevel(data->tile_location.x, data->tile_location.y + 1) < data->current_level) {
418  return MOVE_DOWN;
419  }
420  else {
421  return FACE_DOWN;
422  }
423  }
424  case NONE: {
425  return FACE_RIGHT;
426  }
427  };
428  }
429  };
430 
431  using SpriteFSM = Events::FSM::FSM<SpriteData, SpriteState, SpriteInput,
432  MoveUpReactor, FaceUpReactor, MoveDownReactor, FaceDownReactor,
434  };
435 
439  //= SCRIPTABLE
440  //= SCRIPTABLE BASES Component
441  class SpriteMovement : public Component, public std::enable_shared_from_this<SpriteMovement> {
442  private:
443  std::unique_ptr<SpriteMovementMotor::SpriteFSM> state_machine;
444  std::shared_ptr<SpriteMovementMotor::SpriteData> data;
445 
446  public:
447  virtual bool onUpdate(const double delta) override;
448  virtual void onStart() override;
449  virtual void onDestroy() override {}
450 
451  virtual void handleQueuedEvent(std::shared_ptr<Events::Event> event) override;
452  virtual void onNotifyNow(std::shared_ptr<Events::Event> event) override;
453  virtual unsigned long long getValueForSorting() const noexcept override;
454 
455  //= BEGIN SCRIPTABLE
456 
460  SpriteMovement();
461 
467  void addCollisionData(std::shared_ptr<Physics::CollisionData> collision_data);
473  void setMovingSpeed(const float speed);
479  void setMoveQuantization(const float number_of_tiles);
480 
481 
482  virtual std::string className() const noexcept override;
483  virtual std::string to_string() const noexcept override;
484  //= END SCRIPTABLE
485 
486  virtual void log(el::base::type::ostream_t& os) const override;
487  };
488 }
489 
490 
491 #endif
virtual bool updateState(const double delta, SpriteInput &t) override
Definition: sprite_movement.h:98
virtual void enterState() override
enterState is called upon triggering of this state
Definition: sprite_movement.h:296
SpriteInput
Sprite input enum.
Definition: sprite_movement.h:25
virtual void onNotifyNow(std::shared_ptr< Events::Event > event) override
When receiving an event that is immediate, onNotifyNow is used. It acts as an interrupt to make sure ...
Definition: sprite_movement.cpp:42
virtual void enterState() override
enterState is called upon triggering of this state
Definition: sprite_movement.h:383
Definition: sprite_movement.h:25
SpriteState
Sprite state enum.
Definition: sprite_movement.h:21
MoveUpReactor(const std::shared_ptr< SpriteData > &data, Events::Subject *subject)
Definition: sprite_movement.h:86
virtual void notify(std::shared_ptr< Event > event)
notify is used to tell observers of an event.
Definition: subject.cpp:13
Definition: sprite_movement.h:25
Base Class for all components.
Definition: component.h:20
static std::shared_ptr< SpriteMoveEvent > create(glm::vec2 &velocity, const glm::vec2 &next_position)
SpriteMoveEvent factory function.
Definition: sprite_move_event.h:35
Definition: sprite_movement.h:21
Definition: sprite_movement.h:21
Class for animation trigger event.
Definition: animation_trigger_event.hpp:13
Definition: sprite_movement.h:21
virtual void enterState() override
enterState is called upon triggering of this state
Definition: sprite_movement.h:174
virtual std::string className() const noexceptoverride
Returns a string representing the class name.
Definition: sprite_movement.cpp:91
virtual void enterState() override
enterState is called upon triggering of this state
Definition: sprite_movement.h:122
FaceUpReactor(const std::shared_ptr< SpriteData > &data, Events::Subject *subject)
Definition: sprite_movement.h:121
Definition: sprite_movement.h:344
Definition: sprite_movement.h:25
glm::ivec2 tile_location
Definition: sprite_movement.h:34
virtual SpriteState react(const SpriteInput transition) override
Definition: sprite_movement.h:367
Class for state reactor.
Definition: fsm.hpp:18
FaceLeftReactor(const std::shared_ptr< SpriteData > &data, Events::Subject *subject)
Definition: sprite_movement.h:295
virtual void enterState() override
enterState is called upon triggering of this state
Definition: sprite_movement.h:209
Events::FSM::FSM< SpriteData, SpriteState, SpriteInput, MoveUpReactor, FaceUpReactor, MoveDownReactor, FaceDownReactor, MoveLeftReactor, FaceLeftReactor, MoveRightReactor, FaceRightReactor > SpriteFSM
Definition: sprite_movement.h:433
constexpr SpriteState getStateType() const noexcept
Definition: fsm.hpp:35
std::shared_ptr< Physics::CollisionData > collision_data
Definition: sprite_movement.h:37
virtual SpriteState react(const SpriteInput transition) override
Definition: sprite_movement.h:280
Class for a subject that an observer would observe for changes.
Definition: subject.h:13
Definition: sprite_movement.h:118
float move_quantization_in_tiles
Definition: sprite_movement.h:31
virtual void onDestroy() override
Called when the engine is shutting down.
Definition: sprite_movement.h:449
Definition: sprite_movement.h:21
virtual std::string to_string() const noexceptoverride
Returns a string representation of the object.
Definition: sprite_movement.cpp:95
glm::vec2 current_velocity
Definition: sprite_movement.h:32
MoveDownReactor(const std::shared_ptr< SpriteData > &data, Events::Subject *subject)
Definition: sprite_movement.h:173
std::shared_ptr< Transform > transform
Definition: sprite_movement.h:36
Definition: sprite_movement.h:170
virtual void handleQueuedEvent(std::shared_ptr< Events::Event > event) override
HandleQueuedEvent allows derived classes to define behaviour for when queuedEvents are received...
Definition: sprite_movement.cpp:46
virtual SpriteState react(const SpriteInput transition) override
Definition: sprite_movement.h:106
void addCollisionData(std::shared_ptr< Physics::CollisionData > collision_data)
Adds a collision data.
Definition: sprite_movement.cpp:19
virtual void enterState() override
enterState is called upon triggering of this state
Definition: sprite_movement.h:348
Definition: sprite_movement.h:17
FaceDownReactor(const std::shared_ptr< SpriteData > &data, Events::Subject *subject)
Definition: sprite_movement.h:208
FaceRightReactor(const std::shared_ptr< SpriteData > &data, Events::Subject *subject)
Definition: sprite_movement.h:382
static bool updateSprite(const std::shared_ptr< SpriteData > data, const SpriteState current_state, const double delta)
General sprite update for each reactor.
Definition: sprite_movement.h:66
Definition: sprite_movement.h:21
virtual SpriteState react(const SpriteInput transition) override
Definition: sprite_movement.h:390
Definition: sprite_movement.h:21
float moving_speed
Definition: sprite_movement.h:30
virtual void enterState() override
enterState is called upon triggering of this state
Definition: sprite_movement.h:87
virtual void notifyNow(std::shared_ptr< Event > event)
notifyNow is used to tell observers of an event as an interrupt.
Definition: subject.cpp:19
Definition: sprite_movement.h:25
void setMoveQuantization(const float number_of_tiles)
Sets the move quantization.
Definition: sprite_movement.cpp:83
virtual void enterState() override
enterState is called upon triggering of this state
Definition: sprite_movement.h:261
Definition: sprite_movement.h:379
int current_level
Definition: sprite_movement.h:35
glm::vec2 next_position
Definition: sprite_movement.h:33
Definition: sprite_movement.h:257
Definition: sprite_movement.h:21
virtual bool onUpdate(const double delta) override
Called every engine loop.
Definition: sprite_movement.cpp:30
virtual bool updateState(const double delta, SpriteInput &t) override
Definition: sprite_movement.h:359
MoveLeftReactor(const std::shared_ptr< SpriteData > &data, Events::Subject *subject)
Definition: sprite_movement.h:260
Definition: sprite_movement.h:205
virtual SpriteState react(const SpriteInput transition) override
Definition: sprite_movement.h:216
MoveRightReactor(const std::shared_ptr< SpriteData > &data, Events::Subject *subject)
Definition: sprite_movement.h:347
static std::shared_ptr< SpriteData > defaultSpriteData()
Create a default SpriteData POD.
Definition: sprite_movement.h:44
virtual bool updateState(const double delta, SpriteInput &t) override
Definition: sprite_movement.h:185
virtual unsigned long long getValueForSorting() const noexceptoverride
Gets the value for sorting.
Definition: sprite_movement.cpp:75
virtual void log(el::base::type::ostream_t &os) const override
Definition: sprite_movement.cpp:87
virtual SpriteState react(const SpriteInput transition) override
Definition: sprite_movement.h:303
Sprite data to be exposed for FSM mutation.
Definition: sprite_movement.h:29
virtual void onStart() override
Called when the engine starts and when a new scene is loaded.
Definition: sprite_movement.cpp:23
virtual SpriteState react(const SpriteInput transition) override
Definition: sprite_movement.h:129
virtual bool updateState(const double delta, SpriteInput &t) override
Definition: sprite_movement.h:272
Class for sprite movement.
Definition: sprite_movement.h:441
Definition: sprite_movement.h:84
Definition: sprite_movement.h:25
std::shared_ptr< SpriteData > data
Definition: fsm.hpp:20
Generic Finite State Machine.
Definition: fsm.hpp:78
Definition: sprite_movement.h:21
Definition: sprite_movement.h:292
virtual SpriteState react(const SpriteInput transition) override
Definition: sprite_movement.h:193
void setMovingSpeed(const float speed)
Sets the moving speed.
Definition: sprite_movement.cpp:79