aboutsummaryrefslogtreecommitdiffstats
path: root/entityx/System.h
diff options
context:
space:
mode:
Diffstat (limited to 'entityx/System.h')
-rw-r--r--entityx/System.h180
1 files changed, 180 insertions, 0 deletions
diff --git a/entityx/System.h b/entityx/System.h
new file mode 100644
index 0000000..3d2e4b2
--- /dev/null
+++ b/entityx/System.h
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2012 Alec Thomas <alec@swapoff.org>
+ * All rights reserved.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution.
+ *
+ * Author: Alec Thomas <alec@swapoff.org>
+ */
+
+#pragma once
+
+
+#include <cstdint>
+#include <unordered_map>
+#include <utility>
+#include <cassert>
+#include "entityx/config.h"
+#include "entityx/Entity.h"
+#include "entityx/Event.h"
+#include "entityx/help/NonCopyable.h"
+
+
+namespace entityx {
+
+
+class SystemManager;
+
+
+/**
+ * Base System class. Generally should not be directly used, instead see System<Derived>.
+ */
+class BaseSystem : entityx::help::NonCopyable {
+ public:
+ typedef size_t Family;
+
+ virtual ~BaseSystem();
+
+ /**
+ * Called once all Systems have been added to the SystemManager.
+ *
+ * Typically used to set up event handlers.
+ */
+ virtual void configure(EntityManager &entities, EventManager &events) {
+ (void)entities;
+ configure(events);
+ }
+
+ /**
+ * Legacy configure(). Called by default implementation of configure(EntityManager&, EventManager&).
+ */
+ virtual void configure(EventManager &events) { (void)events; }
+
+ /**
+ * Apply System behavior.
+ *
+ * Called every game step.
+ */
+ virtual void update(EntityManager &entities, EventManager &events, TimeDelta dt) = 0;
+
+ static Family family_counter_;
+
+ protected:
+};
+
+
+/**
+ * Use this class when implementing Systems.
+ *
+ * struct MovementSystem : public System<MovementSystem> {
+ * void update(EntityManager &entities, EventManager &events, TimeDelta dt) {
+ * // Do stuff to/with entities...
+ * }
+ * }
+ */
+template <typename Derived>
+class System : public BaseSystem {
+ public:
+ virtual ~System() {}
+
+private:
+ friend class SystemManager;
+
+ static Family family() {
+ static Family family = family_counter_++;
+ return family;
+ }
+};
+
+
+class SystemManager : entityx::help::NonCopyable {
+ public:
+ SystemManager(EntityManager &entity_manager,
+ EventManager &event_manager) :
+ entity_manager_(entity_manager),
+ event_manager_(event_manager) {}
+
+ /**
+ * Add a System to the SystemManager.
+ *
+ * Must be called before Systems can be used.
+ *
+ * eg.
+ * std::shared_ptr<MovementSystem> movement = entityx::make_shared<MovementSystem>();
+ * system.add(movement);
+ */
+ template <typename S>
+ void add(std::shared_ptr<S> system) {
+ systems_.insert(std::make_pair(S::family(), system));
+ }
+
+ /**
+ * Add a System to the SystemManager.
+ *
+ * Must be called before Systems can be used.
+ *
+ * eg.
+ * auto movement = system.add<MovementSystem>();
+ */
+ template <typename S, typename ... Args>
+ std::shared_ptr<S> add(Args && ... args) {
+ std::shared_ptr<S> s(new S(std::forward<Args>(args) ...));
+ add(s);
+ return s;
+ }
+
+ /**
+ * Retrieve the registered System instance, if any.
+ *
+ * std::shared_ptr<CollisionSystem> collisions = systems.system<CollisionSystem>();
+ *
+ * @return System instance or empty shared_std::shared_ptr<S>.
+ */
+ template <typename S>
+ std::shared_ptr<S> system() {
+ auto it = systems_.find(S::family());
+ assert(it != systems_.end());
+ return it == systems_.end()
+ ? std::shared_ptr<S>()
+ : std::shared_ptr<S>(std::static_pointer_cast<S>(it->second));
+ }
+
+ /**
+ * Call the System::update() method for a registered system.
+ */
+ template <typename S>
+ void update(TimeDelta dt) {
+ assert(initialized_ && "SystemManager::configure() not called");
+ std::shared_ptr<S> s = system<S>();
+ s->update(entity_manager_, event_manager_, dt);
+ }
+
+ /**
+ * Call System::update() on all registered systems.
+ *
+ * The order which the registered systems are updated is arbitrary but consistent,
+ * meaning the order which they will be updated cannot be specified, but that order
+ * will stay the same as long no systems are added or removed.
+ *
+ * If the order in which systems update is important, use SystemManager::update()
+ * to manually specify the update order. EntityX does not yet support a way of
+ * specifying priority for update_all().
+ */
+ void update_all(TimeDelta dt);
+
+ /**
+ * Configure the system. Call after adding all Systems.
+ *
+ * This is typically used to set up event handlers.
+ */
+ void configure();
+
+ private:
+ bool initialized_ = false;
+ EntityManager &entity_manager_;
+ EventManager &event_manager_;
+ std::unordered_map<BaseSystem::Family, std::shared_ptr<BaseSystem>> systems_;
+};
+
+} // namespace entityx