diff --git a/lib/wal/CMakeLists.txt b/lib/wal/CMakeLists.txt index e8cd8655..088188b4 100644 --- a/lib/wal/CMakeLists.txt +++ b/lib/wal/CMakeLists.txt @@ -17,6 +17,6 @@ add_library(wal sources/Component/Component.cpp sources/System/System.cpp sources/Models/Callback.hpp -) + sources/View/BaseView.hpp) target_include_directories(wal PUBLIC sources) \ No newline at end of file diff --git a/lib/wal/sources/Entity/Entity.cpp b/lib/wal/sources/Entity/Entity.cpp index 90e9a41a..35fa2c53 100644 --- a/lib/wal/sources/Entity/Entity.cpp +++ b/lib/wal/sources/Entity/Entity.cpp @@ -3,6 +3,7 @@ // #include "Entity/Entity.hpp" +#include "Scene/Scene.hpp" #include #include @@ -65,4 +66,14 @@ namespace WAL { return this->_components.contains(type); } + + void Entity::_componentAdded(const std::type_index &type) + { + this->_scene._componentAdded(*this, type); + } + + void Entity::_componentRemoved(const std::type_index &type) + { + this->_scene._componentRemoved(*this, type); + } } // namespace WAL \ No newline at end of file diff --git a/lib/wal/sources/Entity/Entity.hpp b/lib/wal/sources/Entity/Entity.hpp index 60bd0090..b7e46dc2 100644 --- a/lib/wal/sources/Entity/Entity.hpp +++ b/lib/wal/sources/Entity/Entity.hpp @@ -10,22 +10,10 @@ #include #include "Component/Component.hpp" #include "Exception/WalError.hpp" -#include "Wal.hpp" namespace WAL { - - class Scene { - public: - //! @brief Notify this scene that a component has been added to the given entity. - //! @param entity The entity with the new component - //! @param type The type of the component added. - void _componentAdded(const Entity &entity, std::type_index type); - //! @brief Notify this scene that a component has been removed to the given entity. - //! @param entity The entity with the removed component - //! @param type The type of the component removed. namespace WAL - void _componentRemoved(const Entity &entity, std::type_index type); - }; + class Scene; //! @brief An entity of the WAL's ECS. class Entity @@ -42,6 +30,13 @@ namespace WAL //! @brief This ID will be the one of the next entity created. static unsigned nextID; + + //! @brief Callback called when a component is added + //! @param type The type of component + void _componentAdded(const std::type_index &type); + //! @brief Callback called when a component is removed + //! @param type The type of component + void _componentRemoved(const std::type_index &type); protected: //! @brief A reference to the ECS. Scene &_scene; @@ -96,7 +91,7 @@ namespace WAL if (this->hasComponent(type)) throw DuplicateError("A component of the type \"" + std::string(type.name()) + "\" already exists."); this->_components[type] = std::make_unique(*this, std::forward(params)...); - this->_scene._componentAdded(*this, type); + this->_componentAdded(type); return *this; } @@ -115,7 +110,7 @@ namespace WAL if (existing == this->_components.end()) throw NotFoundError("No component could be found with the type \"" + std::string(type.name()) + "\"."); this->_components.erase(existing); - this->_scene._componentRemoved(*this, type); + this->_componentRemoved(type); return *this; } diff --git a/lib/wal/sources/Scene/Scene.cpp b/lib/wal/sources/Scene/Scene.cpp index 930382f7..db5c9d6a 100644 --- a/lib/wal/sources/Scene/Scene.cpp +++ b/lib/wal/sources/Scene/Scene.cpp @@ -21,13 +21,28 @@ namespace WAL return this->_entities.emplace_back(*this, name); } - void Scene::_componentAdded(const Entity &entity, std::type_index type) + void Scene::_componentAdded(Entity &entity, const std::type_index &type) { - + for (auto &view : this->_views) { + if (std::find(view->types.begin(), view->types.end(), type) == view->types.end()) + continue; + bool valid = std::all_of(view->types.begin(), view->types.end(), [&entity](const auto &type){ + return entity.hasComponent(type); + }); + if (valid) + view->entities.emplace_back(entity); + } } - void Scene::_componentRemoved(const Entity &entity, std::type_index type) + void Scene::_componentRemoved(const Entity &entity, const std::type_index &type) { - + for (auto &view : this->_views) { + if (std::find(view->types.begin(), view->types.end(), type) == view->types.end()) + continue; + view->entities.erase(std::remove_if(view->entities.begin(), view->entities.end(), [&entity](const auto &ref) + { + return &ref.get() == &entity; + }), view->entities.end()); + } } } // namespace WAL \ No newline at end of file diff --git a/lib/wal/sources/Scene/Scene.hpp b/lib/wal/sources/Scene/Scene.hpp index 4ccf9316..e233debc 100644 --- a/lib/wal/sources/Scene/Scene.hpp +++ b/lib/wal/sources/Scene/Scene.hpp @@ -3,11 +3,11 @@ // -#ifndef WAL_SCENE -#define WAL_SCENE +#pragma once #include #include +#include #include "Entity/Entity.hpp" namespace WAL @@ -18,15 +18,17 @@ namespace WAL private: //! @brief The list of registered entities std::vector _entities = {}; + //! @brief The list of cached views to update. + std::vector> _views = {}; //! @brief Notify this scene that a component has been added to the given entity. //! @param entity The entity with the new component //! @param type The type of the component added. - void _componentAdded(const Entity &entity, std::type_index type); + void _componentAdded(Entity &entity, const std::type_index &type); //! @brief Notify this scene that a component has been removed to the given entity. //! @param entity The entity with the removed component //! @param type The type of the component removed. - void _componentRemoved(const Entity &entity, std::type_index type); + void _componentRemoved(const Entity &entity, const std::type_index &type); public: //! @brief Get the list of entities. std::vector &getEntities(); @@ -37,25 +39,13 @@ namespace WAL Entity &addEntity(const std::string &name); template - std::vector> &view() + View &view() { - return this->view(typeid(Components)...); + static auto view = std::make_shared>(this->_entities); + this->_views.emplace_back(view); + return *view; } -#pragma clang diagnostic push -#pragma ide diagnostic ignored "NotImplementedFunctions" - template - std::vector> &view(const Components &...index) requires(std::is_same_v) - { - static std::vector> view; - - std::copy_if(this->_entities.begin(), this->_entities.end(), std::back_inserter(view), [&index...](Entity &entity) { - return (entity.hasComponent(index) && ...); - }); - return view; - } -#pragma clang diagnostic pop - //! @brief A default constructor Scene() = default; //! @brief A scene is copy constructable @@ -68,8 +58,4 @@ namespace WAL friend Entity; }; -} // namespace WAL - -#else - -#endif \ No newline at end of file +} // namespace WAL \ No newline at end of file diff --git a/lib/wal/sources/System/System.hpp b/lib/wal/sources/System/System.hpp index c3e5ee83..8dc164a7 100644 --- a/lib/wal/sources/System/System.hpp +++ b/lib/wal/sources/System/System.hpp @@ -8,11 +8,10 @@ #include #include #include +#include "Entity/Entity.hpp" namespace WAL { - class Entity; - //! @brief A base system of WAL class System { diff --git a/lib/wal/sources/View/BaseView.hpp b/lib/wal/sources/View/BaseView.hpp new file mode 100644 index 00000000..4a8502d4 --- /dev/null +++ b/lib/wal/sources/View/BaseView.hpp @@ -0,0 +1,50 @@ +// +// Created by Zoe Roux on 2021-06-03. +// + + +#pragma once + +#include +#include +#include +#include +#include "Entity/Entity.hpp" + +namespace WAL +{ + class BaseView + { + public: + std::vector> entities = {}; + + std::vector types = {}; + + size_t size() + { + return entities.size(); + } + +// std::vector> &view(const Components &...index) requires(std::is_same_v) +// { +// static std::vector> view; +// +// std::copy_if(this->_entities.begin(), this->_entities.end(), std::back_inserter(view), [&index...](Entity &entity) { +// return (entity.hasComponent(index) && ...); +// }); +// return view; +// } + }; + + template + class View : public BaseView + { + public: + explicit View(std::vector &scene) + { + std::copy_if(scene.begin(), scene.end(), std::back_inserter(this->entities), [](Entity &entity) { + return (entity.hasComponent() && ...); + }); + } + }; +} \ No newline at end of file diff --git a/lib/wal/sources/Wal.hpp b/lib/wal/sources/Wal.hpp index a16e4f5c..7e361904 100644 --- a/lib/wal/sources/Wal.hpp +++ b/lib/wal/sources/Wal.hpp @@ -12,6 +12,7 @@ #include "Exception/WalError.hpp" #include "System/System.hpp" #include "Models/Callback.hpp" +#include "Scene/Scene.hpp" namespace WAL { diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 7e03bfef..c6270366 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -66,7 +66,7 @@ namespace BBM std::shared_ptr loadGameScene(WAL::Wal &wal) { - auto scene = std::make_shared(wal); + auto scene = std::make_shared(); scene->addEntity("player") .addComponent() .addComponent>("assets/player/player.iqm", std::make_pair(MAP_DIFFUSE, "assets/player/blue.png")) diff --git a/sources/System/Collision/CollisionSystem.cpp b/sources/System/Collision/CollisionSystem.cpp index 24971304..6bb58d51 100644 --- a/sources/System/Collision/CollisionSystem.cpp +++ b/sources/System/Collision/CollisionSystem.cpp @@ -6,6 +6,7 @@ #include "Component/Position/PositionComponent.hpp" #include "Component/Collision/CollisionComponent.hpp" #include "System/Collision/CollisionSystem.hpp" +#include "Scene/Scene.hpp" namespace BBM { diff --git a/tests/CallbackTest.cpp b/tests/CallbackTest.cpp index 44b3a103..30d67e76 100644 --- a/tests/CallbackTest.cpp +++ b/tests/CallbackTest.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "Entity/Entity.hpp" #include "Models/Callback.hpp" @@ -37,7 +38,7 @@ TEST_CASE("Callback multiple arguments", "[Callback]") callback.addCallback([](const std::string& str, int a, unsigned *value, Entity &entity) { throw std::runtime_error(""); }); - Wal wal; - Entity entity(wal, "name"); + Scene scene; + Entity entity(scene, "name"); REQUIRE_THROWS_AS(callback("1", 0, nullptr, entity), std::runtime_error); } diff --git a/tests/CollisionTest.cpp b/tests/CollisionTest.cpp index 42b7d186..447a8dbb 100644 --- a/tests/CollisionTest.cpp +++ b/tests/CollisionTest.cpp @@ -21,7 +21,7 @@ TEST_CASE("Collision test", "[Component][System]") { Wal wal; CollisionSystem collision(wal); - wal.scene = std::make_shared(wal); + wal.scene = std::make_shared(); wal.scene->addEntity("player") .addComponent() .addComponent([](Entity &actual, const Entity &) { @@ -65,7 +65,7 @@ TEST_CASE("Collsion test with movable", "[Component][System]") Wal wal; CollisionSystem collision(wal); MovableSystem movable; - wal.scene = std::make_shared(wal); + wal.scene = std::make_shared(); wal.scene->addEntity("player") .addComponent() .addComponent([](Entity &actual, const Entity &) {}, [](Entity &actual, const Entity &) {}, 5.0) diff --git a/tests/EntityTests.cpp b/tests/EntityTests.cpp index 7a0a3490..3520f862 100644 --- a/tests/EntityTests.cpp +++ b/tests/EntityTests.cpp @@ -6,14 +6,15 @@ #include "Component/Position/PositionComponent.hpp" #include #include +#include using namespace WAL; using namespace BBM; TEST_CASE("Component", "[Entity]") { - Wal wal; - Entity entity(wal, "Bob"); + Scene scene; + Entity entity(scene, "Bob"); entity.addComponent(2, 3, 4); SECTION("Check value") { @@ -33,15 +34,15 @@ TEST_CASE("Component", "[Entity]") TEST_CASE("ComponentNotFound", "[Entity]") { - Wal wal; - Entity entity(wal, "Bob"); + Scene scene; + Entity entity(scene, "Bob"); REQUIRE_THROWS_AS(entity.getComponent(), NotFoundError); } TEST_CASE("Add component by reference", "[Entity]") { - Wal wal; - Entity entity(wal, "Bob"); + Scene scene; + Entity entity(scene, "Bob"); PositionComponent component(entity, 4, 5, 6); REQUIRE(&entity.addComponent(component) == &entity); diff --git a/tests/MoveTests.cpp b/tests/MoveTests.cpp index 0a47bd10..cd37d22a 100644 --- a/tests/MoveTests.cpp +++ b/tests/MoveTests.cpp @@ -19,8 +19,7 @@ using namespace BBM; TEST_CASE("Move test", "[Component][System]") { - Wal wal; - Scene scene(wal); + Scene scene; scene.addEntity("player") .addComponent() .addComponent() diff --git a/tests/ViewTest.cpp b/tests/ViewTest.cpp index 90328acd..21315f2b 100644 --- a/tests/ViewTest.cpp +++ b/tests/ViewTest.cpp @@ -18,8 +18,7 @@ using namespace BBM; TEST_CASE("View creation", "[View]") { - Wal wal; - Scene scene(wal); + Scene scene; scene.addEntity("player") .addComponent() .addComponent(); @@ -28,6 +27,6 @@ TEST_CASE("View creation", "[View]") REQUIRE(scene.view().size() == 2); REQUIRE(scene.view().size() == 1); Entity &entity = *scene.getEntities().begin(); - Entity &firstView = *scene.view().begin(); + Entity &firstView = *scene.view().entities.begin(); REQUIRE(&entity == &firstView); } \ No newline at end of file