From 3d8c25796dd30f9636baf2ad7836085fd34d3f06 Mon Sep 17 00:00:00 2001 From: Berags Date: Wed, 4 May 2022 15:09:25 +0200 Subject: [PATCH] EntityManager - Entity Component System Added Entity Manager on the Engine ECS ECS Refactoring --- include/engine/ecs/Entity.h | 16 ++++++++++- include/engine/ecs/EntityManager.h | 45 ++++++++++++++++++++++++++++++ include/engine/ecs/IComponent.h | 18 ++++++------ include/engine/ecs/TestComponent.h | 8 ++++-- src/engine/ecs/Entity.cpp | 6 ++++ src/engine/ecs/EntityManager.cpp | 37 ++++++++++++++++++++++++ 6 files changed, 119 insertions(+), 11 deletions(-) create mode 100644 include/engine/ecs/EntityManager.h create mode 100644 src/engine/ecs/EntityManager.cpp diff --git a/include/engine/ecs/Entity.h b/include/engine/ecs/Entity.h index ff7e106..5587e81 100644 --- a/include/engine/ecs/Entity.h +++ b/include/engine/ecs/Entity.h @@ -11,21 +11,35 @@ namespace Engine::ECS { class Entity { public: - using id_t = unsigned int; + using id_t = uint32_t; + // Explicitly deleted public constructor so that an Entity + // can only be created from its Factory Method Entity() = delete; + // Entity Factory Method + // Generates its own id static Entity create() { static id_t currentId = 0; return Entity{currentId++}; } + // Adds a component to the Entity components vector + // Checks if the same component is already stored void addComponent(Engine::ECS::IComponent *component); + // Removes a component to the Entity components vector + // Checks if the component is actually stored void removeComponent(Engine::ECS::IComponent *component); + // Updates all the components stored into components vector + // Calls onUpdate on each component stored into components vector void update(float dt); + // Destroys the Entity + // Calls onDestroy on each component stored into components vector + void destroy(); + [[nodiscard]] id_t getId() const; private: diff --git a/include/engine/ecs/EntityManager.h b/include/engine/ecs/EntityManager.h new file mode 100644 index 0000000..4b07993 --- /dev/null +++ b/include/engine/ecs/EntityManager.h @@ -0,0 +1,45 @@ +// +// Created by Jacopo Beragnoli on 04/05/22. +// + +#ifndef MINIMINIMOTORWAYS_ENTITYMANAGER_H +#define MINIMINIMOTORWAYS_ENTITYMANAGER_H + +#include +#include "Entity.h" +#include "../FrameInfo.h" + +namespace Engine::ECS { + class EntityManager { + public: + using Map = std::unordered_map; + static constexpr uint32_t MAX_ENTITIES = 64; + + // Creates a new Entity and adds it to availableEntities Map + // Checks if number of living entities is greater than MAX_ENTITIES + // and asserts if true + Engine::ECS::Entity createNewEntity(); + + // Destroys an Entity from availableEntities Map + // Calls onDestroy method on all Entity components + // Updates numberOfLivingEntities to match availableEntities size + void destroyEntity(Engine::ECS::Entity::id_t id); + + // Returns an Entity from a given id + Engine::ECS::Entity &getEntity(Engine::ECS::Entity::id_t id); + + // Updates all Entities stored in availableEntities + // i.e. calls method update() on each entity + void updateEntities(Engine::FrameInfo &frameInfo); + + private: + // Stores all living Entities + Engine::ECS::EntityManager::Map availableEntities{}; + + // Number of living Entities, should always match availableEntities size + uint32_t livingEntityCount{}; + }; +} + + +#endif //MINIMINIMOTORWAYS_ENTITYMANAGER_H diff --git a/include/engine/ecs/IComponent.h b/include/engine/ecs/IComponent.h index 556fa35..40e61d6 100644 --- a/include/engine/ecs/IComponent.h +++ b/include/engine/ecs/IComponent.h @@ -10,16 +10,18 @@ namespace Engine::ECS { class IComponent { public: - virtual void onCreate() = 0; // Only called one time when dt == 0 + // On Create Method + // Is called when a Component is created and added to an Entity + virtual void onCreate() = 0; - virtual void onUpdate(float dt) { - if (equals(dt, .0f)) onCreate(); - } + // On Update Method + // Is called on each frame and updates the Component related to an Entity + virtual void onUpdate(float dt) = 0; - private: - static bool equals(float a, float b) { - return fabs(a - b) <= ((fabs(a) > fabs(b) ? fabs(b) : fabs(a)) * std::numeric_limits::epsilon()); - } + // On Destroy Method + // Is called whenever a Component is removed from an Entity or whenever an + // Entity is destroyed + virtual void onDestroy() = 0; }; } diff --git a/include/engine/ecs/TestComponent.h b/include/engine/ecs/TestComponent.h index b0a7f93..312ac65 100644 --- a/include/engine/ecs/TestComponent.h +++ b/include/engine/ecs/TestComponent.h @@ -13,11 +13,15 @@ namespace Engine::ECS { class TestComponent : public Engine::ECS::IComponent { public: void onCreate() override { - std::cout << "On Create function" << std::endl; + std::cout << "On Create method" << std::endl; } void onUpdate(float dt) override { - IComponent::onUpdate(dt); + std::cout << "On Update method" << std::endl; + } + + void onDestroy() override { + std::cout << "On destroy method" << std::endl; } }; } diff --git a/src/engine/ecs/Entity.cpp b/src/engine/ecs/Entity.cpp index 5ce3576..1d27200 100644 --- a/src/engine/ecs/Entity.cpp +++ b/src/engine/ecs/Entity.cpp @@ -28,5 +28,11 @@ namespace Engine::ECS { id_t Entity::getId() const { return id; } + + void Entity::destroy() { + std::for_each(components.begin(), components.end(), [&](const auto &item) { + item->onDestroy(); + }); + } } diff --git a/src/engine/ecs/EntityManager.cpp b/src/engine/ecs/EntityManager.cpp new file mode 100644 index 0000000..6a907f6 --- /dev/null +++ b/src/engine/ecs/EntityManager.cpp @@ -0,0 +1,37 @@ +// +// Created by Jacopo Beragnoli on 04/05/22. +// + +#include "../../../include/engine/ecs/EntityManager.h" + +namespace Engine::ECS { + Engine::ECS::Entity EntityManager::createNewEntity() { + assert(livingEntityCount < Engine::ECS::EntityManager::MAX_ENTITIES && "Too many entities!"); + + auto entity = Engine::ECS::Entity::create(); + availableEntities.emplace(livingEntityCount, entity); + livingEntityCount++; + return entity; + } + + void EntityManager::destroyEntity(Engine::ECS::Entity::id_t id) { + assert(id < Engine::ECS::EntityManager::MAX_ENTITIES && "Entity out of range!"); + + availableEntities.at(id).destroy(); + availableEntities.erase(id); + livingEntityCount--; + } + + Engine::ECS::Entity &EntityManager::getEntity(Engine::ECS::Entity::id_t id) { + assert(id < Engine::ECS::EntityManager::MAX_ENTITIES && "Entity out of range!"); + + return availableEntities.at(id); + } + + void EntityManager::updateEntities(Engine::FrameInfo &frameInfo) { + std::for_each(availableEntities.begin(), availableEntities.end(), [&](auto &item) { + auto &entity = item.second; + entity.update(frameInfo.frameTime); + }); + } +} \ No newline at end of file