diff options
Diffstat (limited to 'entityx/System.h')
-rw-r--r-- | entityx/System.h | 180 |
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 |