diff --git a/lib/wal/sources/Entity/Entity.cpp b/lib/wal/sources/Entity/Entity.cpp index d9cd550c..e4e07453 100644 --- a/lib/wal/sources/Entity/Entity.cpp +++ b/lib/wal/sources/Entity/Entity.cpp @@ -11,17 +11,19 @@ namespace WAL { unsigned Entity::nextID = 0; - Entity::Entity(Scene &scene, std::string name) + Entity::Entity(Scene &scene, std::string name, bool notifyScene) : _uid(Entity::nextID++), _scene(scene), - _name(std::move(name)) + _name(std::move(name)), + _notifyScene(notifyScene) { } Entity::Entity(const Entity &other) : _uid(Entity::nextID++), _scene(other._scene), _name(other._name), - _disabled(other._disabled) + _disabled(other._disabled), + _notifyScene(other._notifyScene) { for (const auto &cmp : other._components) this->addComponent(*cmp.second); @@ -53,7 +55,8 @@ namespace WAL if (this->hasComponent(type, false)) throw DuplicateError("A component of the type \"" + std::string(type.name()) + "\" already exists."); this->_components.emplace(type, component.clone(*this)); - this->_scene._componentAdded(*this, type); + if (this->_notifyScene) + this->_scene._componentAdded(*this, type); return *this; } diff --git a/lib/wal/sources/Entity/Entity.hpp b/lib/wal/sources/Entity/Entity.hpp index 9fbd3657..9eab09a4 100644 --- a/lib/wal/sources/Entity/Entity.hpp +++ b/lib/wal/sources/Entity/Entity.hpp @@ -28,6 +28,8 @@ namespace WAL bool _disabled = false; //! @brief Has this entity been scheduled for deletion? bool _shouldDelete = false; + //! @brief Should this entity notify the scene of component changes? + bool _notifyScene; //! @brief The list of the components of this entity std::unordered_map> _components = {}; @@ -40,6 +42,8 @@ namespace WAL //! @brief Callback called when a component is removed //! @param type The type of component void _componentRemoved(const std::type_index &type); + + friend Scene; protected: //! @brief A reference to the ECS. Scene &_scene; @@ -141,7 +145,8 @@ 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, TypeHolder()..., std::forward(params)...); - this->_componentAdded(type); + if (this->_notifyScene) + this->_componentAdded(type); return *this; } @@ -160,12 +165,13 @@ 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->_componentRemoved(type); + if (this->_notifyScene) + this->_componentRemoved(type); return *this; } //! @brief A default constructor - explicit Entity(Scene &wal, std::string name); + explicit Entity(Scene &wal, std::string name, bool notifyScene = true); //! @brief An entity is copyable Entity(const Entity &); //! @brief An entity is movable. diff --git a/lib/wal/sources/Scene/Scene.cpp b/lib/wal/sources/Scene/Scene.cpp index c4e610cf..34ca940c 100644 --- a/lib/wal/sources/Scene/Scene.cpp +++ b/lib/wal/sources/Scene/Scene.cpp @@ -24,6 +24,11 @@ namespace WAL return this->_entities.emplace_back(*this, name); } + Entity &Scene::scheduleNewEntity(const std::string &name) + { + return this->_newEntities.emplace_back(*this, name, false); + } + void Scene::_componentAdded(Entity &entity, const std::type_index &type) { for (auto &view : this->_views) { @@ -52,7 +57,7 @@ namespace WAL view->erase(entity); } - void Scene::deleteMarkedEntities() + void Scene::applyChanges() { this->_entities.remove_if([this](auto &entity) { if (!entity.shouldDelete()) @@ -60,5 +65,16 @@ namespace WAL this->_entityRemoved(entity); return true; }); + for (auto &entity : this->_newEntities) { + for (auto &view : this->_views) { + bool valid = std::all_of(view->getTypes().begin(), view->getTypes().end(), [&entity](const auto &type){ + return entity.hasComponent(type); + }); + if (valid) + view->emplace_back(entity); + } + entity._notifyScene = true; + } + this->_entities.splice(this->_entities.end(), this->_newEntities); } } // 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 4dfc5ad8..3d7f702a 100644 --- a/lib/wal/sources/Scene/Scene.hpp +++ b/lib/wal/sources/Scene/Scene.hpp @@ -23,6 +23,8 @@ namespace WAL //! @brief The list of registered entities std::list _entities = {}; + //! @brief The list of entities to add on the next call to applyChanges. + std::list _newEntities = {}; //! @brief The list of cached views to update. std::vector> _views = {}; @@ -46,6 +48,11 @@ namespace WAL //! @return The created entity is returned. Entity &addEntity(const std::string &name); + //! @brief Add a new entity to the scene, this entity will be added on the next call to applyChanges. + //! @param name The name of the created entity. + //! @return The created entity is returned. + Entity &scheduleNewEntity(const std::string &name); + template View &view() { @@ -59,8 +66,8 @@ namespace WAL return *view; } - //! @brief Delete entities marked as deleted. - void deleteMarkedEntities(); + //! @brief Delete entities marked as deleted and create scheduled entities. + void applyChanges(); //! @brief A default constructor Scene() = default; diff --git a/lib/wal/sources/View/View.hpp b/lib/wal/sources/View/View.hpp index 15b31e09..6b847341 100644 --- a/lib/wal/sources/View/View.hpp +++ b/lib/wal/sources/View/View.hpp @@ -179,8 +179,10 @@ namespace WAL void erase(const Entity &entity) override { this->_entities.erase(std::remove_if(this->_entities.begin(), this->_entities.end(), [&entity](const auto &ref){ - return &std::get<0>(ref).get() == &entity; - })); + if (std::get<0>(ref).get().getUid() == entity.getUid()) + return true; + return std::get<0>(ref).get().getUid() == entity.getUid(); + }), this->_entities.end()); } //! @brief Construct a view from a list of entities. diff --git a/lib/wal/sources/Wal.hpp b/lib/wal/sources/Wal.hpp index e3d2a4f5..4748e84e 100644 --- a/lib/wal/sources/Wal.hpp +++ b/lib/wal/sources/Wal.hpp @@ -52,7 +52,7 @@ namespace WAL } for (auto &system : this->_systems) system->update(dtime); - this->scene->deleteMarkedEntities(); + this->scene->applyChanges(); callback(*this, state); } } @@ -76,7 +76,7 @@ namespace WAL } for (auto &system : wal._systems) system->update(dtime); - wal.scene->deleteMarkedEntities(); + wal.scene->applyChanges(); callback(wal, state); } #endif diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index e71d2c34..4386546a 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -20,14 +20,14 @@ namespace BBM const auto &wallPos = wall.getComponent(); auto diff = pos.position + mov->getVelocity() - wallPos.position; // mov->_velocity = Vector3f(); - if (diff.x <= 0 && mov->_velocity.x < 0) - mov->_velocity.x = 0; - if (diff.x >= 0 && mov->_velocity.x > 0) - mov->_velocity.x = 0; - if (diff.z <= 0 && mov->_velocity.z < 0) - mov->_velocity.z = 0; - if (diff.z >= 0 && mov->_velocity.z > 0) - mov->_velocity.z = 0; +// if (diff.x <= 0 && mov->_velocity.x < 0) +// mov->_velocity.x = 0; +// if (diff.x >= 0 && mov->_velocity.x > 0) +// mov->_velocity.x = 0; +// if (diff.z <= 0 && mov->_velocity.z < 0) +// mov->_velocity.z = 0; +// if (diff.z >= 0 && mov->_velocity.z > 0) +// mov->_velocity.z = 0; } const std::string MapGenerator::assetsPath = "./assets/"; diff --git a/sources/System/BombHolder/BombHolderSystem.cpp b/sources/System/BombHolder/BombHolderSystem.cpp index f09d2356..621c87b2 100644 --- a/sources/System/BombHolder/BombHolderSystem.cpp +++ b/sources/System/BombHolder/BombHolderSystem.cpp @@ -39,7 +39,7 @@ namespace BBM void BombHolderSystem::_spawnBomb(Vector3f position) { std::cout << "Spawnned" << std::endl; - this->_wal.scene->addEntity("Bomb") + this->_wal.scene->scheduleNewEntity("Bomb") .addComponent(position) .addComponent(BombHolderSystem::explosionTimer, &BombHolderSystem::_bombExplosion) .addComponent("assets/bombs/bomb.obj", diff --git a/tests/ViewTest.cpp b/tests/ViewTest.cpp index 569d42ad..aaa1bf36 100644 --- a/tests/ViewTest.cpp +++ b/tests/ViewTest.cpp @@ -50,6 +50,33 @@ TEST_CASE("View cache", "[View]") REQUIRE(&view == &scene.view()); } +TEST_CASE("View add entity", "[View]") +{ + Scene scene; + auto &entity = scene.addEntity("player") + .addComponent() + .addComponent(); + REQUIRE(scene.view().size() == 1); + scene.scheduleNewEntity("test") + .addComponent(); + scene.applyChanges(); + REQUIRE(scene.view().size() == 2); +} + +TEST_CASE("View remove entity", "[View]") +{ + Scene scene; + auto &entity = scene.addEntity("player") + .addComponent() + .addComponent(); + REQUIRE(scene.view().size() == 1); + entity.scheduleDeletion(); + scene.applyChanges(); + REQUIRE(scene.view().size() == 0); + for (auto &it : scene.view()) + REQUIRE(false); +} + TEST_CASE("View cache switch", "[View]") { Scene scene;