Lazarus
Engine for creating roguelikes in C++
 All Classes Namespaces Functions
ECSEngine.h
1 #pragma once
2 
3 #include <functional>
4 #include <sstream>
5 
6 #include <lazarus/ECS/Entity.h>
7 #include <lazarus/ECS/EventListener.h>
8 #include <lazarus/ECS/Updateable.h>
9 
10 namespace lz
11 {
27 class ECSEngine
28 {
29 public:
33  Entity* addEntity();
34 
41  void addEntity(Entity& entity);
42 
48  Entity* getEntity(Identifier entityId);
49 
57  template <typename... Types>
58  std::vector<Entity*> entitiesWithComponents(bool includeDeleted=false);
59 
70  template <typename... Types>
71  void applyToEach(
72  typename std::common_type<std::function<void(Entity*, Types*...)>>::type&& func,
73  bool includeDeleted=false);
74 
84  template <typename EventType>
85  void subscribe(EventListener<EventType>* eventListener);
86 
90  template <typename EventType>
91  void unsubscribe(EventListener<EventType>* eventListener);
92 
96  template <typename EventType>
97  void emit(const EventType& event);
98 
104  void registerUpdateable(Updateable* updateable);
105 
111  virtual void update();
112 
113 private:
117  void garbageCollect();
118 
119 private:
120  std::unordered_map<Identifier, std::shared_ptr<Entity>> entities;
121  std::vector<Updateable*> updateables;
122  // Maps event type index -> list of event listeners for that event type
123  std::unordered_map<std::type_index,
124  std::vector<__lz::BaseEventListener*>> subscribers;
125 };
126 
127 template <typename... Types>
128 std::vector<Entity*> ECSEngine::entitiesWithComponents(bool includeDeleted)
129 {
130  std::vector<Entity*> result;
131  applyToEach<Types...>([&](Entity* ent, Types*... comp)
132  {
133  result.push_back(ent);
134  },
135  includeDeleted);
136  return result;
137 }
138 
139 template <typename... Types>
141  typename std::common_type<std::function<void(Entity*, Types*...)>>::type&& func,
142  bool includeDeleted)
143 {
144  for (auto it = entities.begin(); it != entities.end(); ++it)
145  {
146  Entity* entity = it->second.get();
147 
148  if (!includeDeleted && entity->isDeleted())
149  continue;
150 
151  if (entity->has<Types...>())
152  func(entity, entity->get<Types>()...);
153  }
154 }
155 
156 template <typename EventType>
158 {
159  std::type_index typeId = __lz::getTypeIndex<EventType>();
160  auto found = subscribers.find(typeId);
161  if (found == subscribers.end())
162  {
163  // No subscribers to this type of event yet, create vector
164  std::vector<__lz::BaseEventListener*> vec;
165  vec.push_back(eventListener);
166  subscribers[typeId] = vec;
167  }
168  else
169  {
170  // There already exists a list of subscribers to this event type
171  found->second.push_back(eventListener);
172  }
173 }
174 
175 template <typename EventType>
177 {
178  auto found = subscribers.find(__lz::getTypeIndex<EventType>());
179  if (found != subscribers.end())
180  {
181  auto eventListeners = found->second;
182  for (auto it = eventListeners.begin(); it != eventListeners.end(); ++it)
183  {
184  if (*it == eventListener)
185  {
186  // System found, remove it from the subscriber list
187  eventListeners.erase(it);
188  return;
189  }
190  }
191  }
192  // System was not found
193  std::stringstream msg;
194  msg << "ECS engine was not subscribed to the event ";
195  msg << typeid(EventType).name();
196  throw __lz::LazarusException(msg.str());
197 }
198 
199 template <typename EventType>
200 void ECSEngine::emit(const EventType& event)
201 {
202  // TODO: Log case in which an event is emitted but no listeners for that type exist
203  auto found = subscribers.find(__lz::getTypeIndex<EventType>());
204  if (found != subscribers.end())
205  {
206  auto eventListeners = found->second;
207  for (auto it = eventListeners.begin(); it != eventListeners.end(); ++it)
208  {
209  auto* listener = dynamic_cast<EventListener<EventType>*>(*it);
210  listener->receive(*this, event);
211  }
212  }
213 }
214 } // namespace lz
virtual void update()
Updates all the updateable objects in the engine.
Definition: ECSEngine.cpp:32
void applyToEach(typename std::common_type< std::function< void(Entity *, Types *...)>>::type &&func, bool includeDeleted=false)
Applies a function to each of the entities from the collection that have the specified component type...
Definition: ECSEngine.h:140
virtual void receive(ECSEngine &engine, const EventType &event)=0
Called when the EventListener receives an event from the ECS engine.
void registerUpdateable(Updateable *updateable)
Adds an updateable object to the engine.
Definition: ECSEngine.cpp:27
Entity * addEntity()
Adds a new entity to the collection and returns a pointer to it.
Definition: ECSEngine.cpp:5
std::vector< Entity * > entitiesWithComponents(bool includeDeleted=false)
Returns a vector with the entities that have the specified components.
Definition: ECSEngine.h:128
void unsubscribe(EventListener< EventType > *eventListener)
Unsubscribes the event listener from the list of listeners of that event type.
Definition: ECSEngine.h:176
Entity * getEntity(Identifier entityId)
Gets a pointer to the entity from the collection with the given ID, or a nullptr if an entity with su...
Definition: ECSEngine.cpp:19
Definition: common.h:21
Interface for objects that react to events of a certain type.
Definition: EventListener.h:32
bool isDeleted() const
Returns whether this entity is marked for deletion upon the next pass of the garbage collector...
Definition: Entity.h:111
Component * get()
Returns a pointer to the entity's component of the specified type.
Definition: Entity.h:189
Interface for objects that can be updated by the ECS engine when it ticks.
Definition: Updateable.h:15
bool has() const
Returns whether the entity has a component of type T.
Definition: Entity.h:144
An Entity is a collection of components with a unique ID.
Definition: Entity.h:50
void subscribe(EventListener< EventType > *eventListener)
Subscribes the event listener to the list of listeners of that event type.
Definition: ECSEngine.h:157
Main driver to work with entities, components and systems.
Definition: ECSEngine.h:27
void emit(const EventType &event)
Emit an event to all listeners of that type of event.
Definition: ECSEngine.h:200