diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b77aec0..48dcf444 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,8 +10,6 @@ include_directories(bomberman sources) add_subdirectory(${PROJECT_SOURCE_DIR}/lib/wal) add_subdirectory(${PROJECT_SOURCE_DIR}/lib/Ray) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2") - if (EMSCRIPTEN) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY") @@ -31,6 +29,8 @@ set(SOURCES sources/Component/Movable/MovableComponent.hpp sources/Component/Controllable/ControllableComponent.hpp sources/Component/Controllable/ControllableComponent.cpp + sources/Component/BombHolder/BombHolderComponent.cpp + sources/Component/BombHolder/BombHolderComponent.hpp sources/Component/Gamepad/GamepadComponent.cpp sources/Component/Gamepad/GamepadComponent.hpp sources/Component/Keyboard/KeyboardComponent.cpp @@ -61,6 +61,14 @@ set(SOURCES sources/System/Renderer/RenderSystem.cpp sources/Component/Renderer/CameraComponent.cpp sources/Component/Renderer/CameraComponent.hpp + sources/System/BombHolder/BombHolderSystem.cpp + sources/System/BombHolder/BombHolderSystem.hpp + sources/Component/Timer/TimerComponent.cpp + sources/Component/Timer/TimerComponent.hpp + sources/System/Timer/TimerSystem.cpp + sources/System/Timer/TimerSystem.hpp + sources/System/Event/EventSystem.cpp + sources/System/Event/EventSystem.hpp sources/Component/Animation/AnimationsComponent.cpp sources/Component/Animation/AnimationsComponent.hpp sources/System/Animation/AnimationsSystem.cpp @@ -77,7 +85,7 @@ set(SOURCES add_executable(bomberman sources/main.cpp ${SOURCES} - ) +) target_include_directories(bomberman PUBLIC sources) target_link_libraries(bomberman PUBLIC wal ray) diff --git a/lib/wal/sources/Entity/Entity.cpp b/lib/wal/sources/Entity/Entity.cpp index 35fa2c53..8e4ff0f1 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); @@ -50,21 +52,27 @@ namespace WAL Entity &Entity::addComponent(const Component &component) { const std::type_index &type = typeid(component); - if (this->hasComponent(type)) + 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; } - bool Entity::hasComponent(const std::type_info &type) const + bool Entity::hasComponent(const std::type_info &type, bool skipDisabled) const { - return this->hasComponent(static_cast(type)); + return this->hasComponent(static_cast(type), skipDisabled); } - bool Entity::hasComponent(const std::type_index &type) const + bool Entity::hasComponent(const std::type_index &type, bool skipDisabled) const { - return this->_components.contains(type); + auto cmp = this->_components.find(type); + if (cmp == this->_components.end()) + return false; + if (skipDisabled) + return !cmp->second->isDisabled(); + return true; } void Entity::_componentAdded(const std::type_index &type) @@ -76,4 +84,14 @@ namespace WAL { this->_scene._componentRemoved(*this, type); } + + bool Entity::shouldDelete() const + { + return this->_shouldDelete; + } + + void Entity::scheduleDeletion() + { + this->_shouldDelete = true; + } } // 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 25234f31..9eab09a4 100644 --- a/lib/wal/sources/Entity/Entity.hpp +++ b/lib/wal/sources/Entity/Entity.hpp @@ -26,6 +26,10 @@ namespace WAL std::string _name; //! @brief Is this entity enabled? 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 = {}; @@ -38,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; @@ -49,10 +55,14 @@ namespace WAL //! @brief Used if the entity is disabled bool isDisable() const; - //! @brief Disable this entity. void setDisable(bool disabled); + //! @brief Has this entity been scheduled for deletion? + bool shouldDelete() const; + //! @brief Schedule this entity for deletion + void scheduleDeletion(); + //! @brief Get a component of a specific type //! @tparam The type of the component //! @throw NotFoundError if the component could not be found @@ -106,21 +116,24 @@ namespace WAL } //! @brief Check if this entity has a component. + //! @param skipDisabled True if you want to skip disabled components (consider them non present), false otherwise. //! @tparam T The type of the component template - bool hasComponent() const + bool hasComponent(bool skipDisabled = true) const { const std::type_info &type = typeid(T); - return this->hasComponent(type); + return this->hasComponent(type, skipDisabled); } //! @brief Check if this entity has a component. + //! @param skipDisabled True if you want to skip disabled components (consider them non present), false otherwise. //! @param type The type of the component - bool hasComponent(const std::type_info &type) const; + bool hasComponent(const std::type_info &type, bool skipDisabled = true) const; //! @brief Check if this entity has a component. + //! @param skipDisabled True if you want to skip disabled components (consider them non present), false otherwise. //! @param type The type of the component - bool hasComponent(const std::type_index &type) const; + bool hasComponent(const std::type_index &type, bool skipDisabled = true) const; //! @brief Add a component to this entity. The component is constructed in place. //! @throw DuplicateError is thrown if a component with the same type already exist. @@ -132,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; } @@ -151,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 77526662..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) { @@ -45,4 +50,31 @@ namespace WAL view->erase(entity); } } + + void Scene::_entityRemoved(const Entity &entity) + { + for (auto &view : this->_views) + view->erase(entity); + } + + void Scene::applyChanges() + { + this->_entities.remove_if([this](auto &entity) { + if (!entity.shouldDelete()) + return false; + 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 aab47566..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 = {}; @@ -34,6 +36,9 @@ namespace WAL //! @param entity The entity with the removed component //! @param type The type of the component removed. void _componentRemoved(const Entity &entity, const std::type_index &type); + //! @brief Remove an entity from every views. + //! @param entity The entity to remove. + void _entityRemoved(const Entity &entity); public: //! @brief Get the list of entities. std::list &getEntities(); @@ -43,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() { @@ -56,6 +66,9 @@ namespace WAL return *view; } + //! @brief Delete entities marked as deleted and create scheduled entities. + void applyChanges(); + //! @brief A default constructor Scene() = default; //! @brief A scene is copy constructable diff --git a/lib/wal/sources/View/View.hpp b/lib/wal/sources/View/View.hpp index 15b31e09..50726a82 100644 --- a/lib/wal/sources/View/View.hpp +++ b/lib/wal/sources/View/View.hpp @@ -178,9 +178,9 @@ 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; - })); + this->_entities.erase(std::remove_if(this->_entities.begin(), this->_entities.end(), [&entity](const auto &ref) { + 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 de6bb394..4748e84e 100644 --- a/lib/wal/sources/Wal.hpp +++ b/lib/wal/sources/Wal.hpp @@ -52,6 +52,7 @@ namespace WAL } for (auto &system : this->_systems) system->update(dtime); + this->scene->applyChanges(); callback(*this, state); } } @@ -75,6 +76,7 @@ namespace WAL } for (auto &system : wal._systems) system->update(dtime); + wal.scene->applyChanges(); callback(wal, state); } #endif diff --git a/sources/Component/BombHolder/BombHolderComponent.cpp b/sources/Component/BombHolder/BombHolderComponent.cpp new file mode 100644 index 00000000..9f75b8ae --- /dev/null +++ b/sources/Component/BombHolder/BombHolderComponent.cpp @@ -0,0 +1,24 @@ +// +// Created by Tom Augier on 2021-05-20. +// Edited by Benjamin Henry on 2021-05-20. +// Edited by Louis Auzuret on 2021-05-20. +// + +#include "BombHolderComponent.hpp" + +namespace BBM +{ + BombHolderComponent::BombHolderComponent(WAL::Entity &entity) + : WAL::Component(entity) + {} + + BombHolderComponent::BombHolderComponent(WAL::Entity &entity, unsigned int maxBombCount) + : WAL::Component(entity), + maxBombCount(maxBombCount) + {} + + WAL::Component *BombHolderComponent::clone(WAL::Entity &entity) const + { + return new BombHolderComponent(entity, this->maxBombCount); + } +} \ No newline at end of file diff --git a/sources/Component/BombHolder/BombHolderComponent.hpp b/sources/Component/BombHolder/BombHolderComponent.hpp new file mode 100644 index 00000000..03906e84 --- /dev/null +++ b/sources/Component/BombHolder/BombHolderComponent.hpp @@ -0,0 +1,47 @@ +// +// Created by Tom Augier on 2021-05-20. +// Edited by Benjamin Henry on 2021-05-20. +// Edited by Louis Auzuret on 2021-05-20. +// + +#pragma once + +#include "Component/Component.hpp" +#include "Entity/Entity.hpp" +#include + +using namespace std::chrono_literals; + +namespace BBM +{ + class BombHolderComponent : public WAL::Component + { + public: + //! @brief The number of bomb that this entity hold. + unsigned int bombCount = 1; + //! @brief The max number of bomb that this entity can have. + unsigned int maxBombCount = 3; + //! @brief The number of seconds of each refill. This variable is used to reset the nextBombRefill value. + std::chrono::nanoseconds refillRate = 5000ms; + //! @brief The number of nanosecond before the next bomb refill. + std::chrono::nanoseconds nextBombRefill = refillRate; + + //! @inherit + WAL::Component *clone(WAL::Entity &entity) const override; + + //! @brief A component can't be instantiated, it should be derived. + explicit BombHolderComponent(WAL::Entity &entity); + + //! @brief Constructor + BombHolderComponent(WAL::Entity &entity, unsigned int maxBombCount); + + //! @brief A component can't be instantiated, it should be derived. + BombHolderComponent(const BombHolderComponent &) = default; + + //! @brief default destructor + ~BombHolderComponent() override = default; + + //! @brief A component can't be assigned + BombHolderComponent &operator=(const BombHolderComponent &) = delete; + }; +} \ No newline at end of file diff --git a/sources/Component/Health/HealthComponent.cpp b/sources/Component/Health/HealthComponent.cpp index 5499d243..8901ab31 100644 --- a/sources/Component/Health/HealthComponent.cpp +++ b/sources/Component/Health/HealthComponent.cpp @@ -10,15 +10,15 @@ namespace BBM { - HealthComponent::HealthComponent(WAL::Entity &entity, unsigned int healthPoint, std::function callback) - : WAL::Component(entity), - _healthPoint(healthPoint), - onDeath(std::move(callback)) + HealthComponent::HealthComponent(WAL::Entity &entity, unsigned int healthPoint, const WAL::Callback &onDeath) + : WAL::Component(entity), + _healthPoint(healthPoint), + onDeath(onDeath) {} WAL::Component *HealthComponent::clone(WAL::Entity &entity) const { - return new HealthComponent(entity); + return new HealthComponent(entity, this->_healthPoint, this->onDeath); } void HealthComponent::addHealthPoint(unsigned int healthPoint) diff --git a/sources/Component/Health/HealthComponent.hpp b/sources/Component/Health/HealthComponent.hpp index d8ff7531..29c202d4 100644 --- a/sources/Component/Health/HealthComponent.hpp +++ b/sources/Component/Health/HealthComponent.hpp @@ -36,7 +36,7 @@ namespace BBM WAL::Component *clone(WAL::Entity &entity) const override; //! @brief Constructor - explicit HealthComponent(WAL::Entity &entity, unsigned int healthPoint = 1, std::function callback = {}); + HealthComponent(WAL::Entity &entity, unsigned int healthPoint, const WAL::Callback &onDeath = WAL::Callback()); //! @brief A Health component can't be instantiated, it should be derived. HealthComponent(const HealthComponent &) = default; diff --git a/sources/Component/Timer/TimerComponent.cpp b/sources/Component/Timer/TimerComponent.cpp new file mode 100644 index 00000000..1695ee39 --- /dev/null +++ b/sources/Component/Timer/TimerComponent.cpp @@ -0,0 +1,26 @@ +// +// Created by Zoe Roux on 5/31/21. +// + +#include "TimerComponent.hpp" + +#include + +namespace BBM +{ + TimerComponent::TimerComponent(WAL::Entity &entity, std::chrono::nanoseconds delay) + : WAL::Component(entity), + ringIn(delay) + {} + + TimerComponent::TimerComponent(WAL::Entity &entity, std::chrono::nanoseconds delay, const WAL::Callback &callback) + : WAL::Component(entity), + ringIn(delay), + callback(callback) + {} + + WAL::Component *TimerComponent::clone(WAL::Entity &entity) const + { + return new TimerComponent(entity, this->ringIn, this->callback); + } +} \ No newline at end of file diff --git a/sources/Component/Timer/TimerComponent.hpp b/sources/Component/Timer/TimerComponent.hpp new file mode 100644 index 00000000..b0ad2454 --- /dev/null +++ b/sources/Component/Timer/TimerComponent.hpp @@ -0,0 +1,36 @@ +// +// Created by Zoe Roux on 5/31/21. +// + +#pragma once + +#include +#include +#include +#include "Models/Callback.hpp" + +namespace BBM +{ + //! @brief + class TimerComponent : public WAL::Component + { + public: + //! @brief The callback to call when the timer ring. + WAL::Callback callback; + //! @brief The ring delay of this timer component. + std::chrono::nanoseconds ringIn; + + Component *clone(WAL::Entity &entity) const override; + + //! @brief A default constructor + TimerComponent(WAL::Entity &entity, std::chrono::nanoseconds delay); + //! @brief Create a timer with a callback. + TimerComponent(WAL::Entity &entity, std::chrono::nanoseconds delay, const WAL::Callback &callback); + //! @brief A timer component is copy constructable + TimerComponent(const TimerComponent &) = default; + //! @brief A default destructor + ~TimerComponent() override = default; + //! @brief A component is not assignable. + TimerComponent &operator=(const TimerComponent &) = delete; + }; +} diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index 3f8ba259..5e8a9a2e 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -28,6 +28,11 @@ namespace BBM mov->_velocity.z = 0; } + void MapGenerator::wallDestroyed(WAL::Entity &entity) + { + entity.scheduleDeletion(); + } + const std::string MapGenerator::assetsPath = "./assets/"; const std::string MapGenerator::wallAssetsPath = MapGenerator::assetsPath + "map/"; const std::string MapGenerator::imageExtension = ".png"; @@ -143,7 +148,7 @@ namespace BBM scene->addEntity("Breakable Block") .addComponent(coords) - .addComponent(1) + .addComponent(1, &MapGenerator::wallDestroyed) .addComponent( WAL::Callback(), &MapGenerator::wallCollide, 0.25, .75) diff --git a/sources/Map/Map.hpp b/sources/Map/Map.hpp index 82af402a..4a961cbc 100644 --- a/sources/Map/Map.hpp +++ b/sources/Map/Map.hpp @@ -162,6 +162,7 @@ namespace BBM static void wallCollide(WAL::Entity &entity, const WAL::Entity &wall, CollisionComponent::CollidedAxis collidedAxis); + static void wallDestroyed(WAL::Entity &entity); //! @param width Width of the map diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 6371c648..08a51d76 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -9,21 +9,25 @@ #include #include #include -#include -#include +#include "System/Keyboard/KeyboardSystem.hpp" +#include "System/Controllable/ControllableSystem.hpp" +#include "Component/Movable/MovableComponent.hpp" +#include "Component/Controllable/ControllableComponent.hpp" +#include "Component/Keyboard/KeyboardComponent.hpp" +#include "System/Gamepad/GamepadSystem.hpp" #include -#include #include -#include -#include -#include #include "Component/Renderer/CameraComponent.hpp" #include "Component/Renderer/Drawable3DComponent.hpp" #include "Runner.hpp" #include "Models/GameState.hpp" #include -#include +#include +#include +#include +#include #include +#include #include "Component/Animation/AnimationsComponent.hpp" #include "System/Animation/AnimationsSystem.hpp" #include "Map/Map.hpp" @@ -44,9 +48,13 @@ namespace BBM void addSystems(WAL::Wal &wal) { - wal.addSystem() + wal.addSystem() + .addSystem() .addSystem() .addSystem() + .addSystem() + .addSystem() + .addSystem() .addSystem() .addSystem(); } @@ -72,6 +80,7 @@ namespace BBM .addComponent(RAY::ModelAnimations("assets/player/player.iqm"), 3) .addComponent(0, 1) .addComponent() + .addComponent() .addComponent(1, [](WAL::Entity &entity) { auto &animation = entity.getComponent(); animation.setAnimIndex(5); diff --git a/sources/System/BombHolder/BombHolderSystem.cpp b/sources/System/BombHolder/BombHolderSystem.cpp new file mode 100644 index 00000000..2d46b3b8 --- /dev/null +++ b/sources/System/BombHolder/BombHolderSystem.cpp @@ -0,0 +1,67 @@ +// +// Created by Zoe Roux on 5/31/21. +// + +#include "Component/Timer/TimerComponent.hpp" +#include "System/Event/EventSystem.hpp" +#include "Component/Renderer/Drawable3DComponent.hpp" +#include "BombHolderSystem.hpp" +#include "Component/Health/HealthComponent.hpp" + +using namespace std::chrono_literals; +namespace RAY3D = RAY::Drawables::Drawables3D; + +namespace BBM +{ + std::chrono::nanoseconds BombHolderSystem::explosionTimer = 3s; + float BombHolderSystem::explosionRadius = 3; + + BombHolderSystem::BombHolderSystem(WAL::Wal &wal) + : System(wal) + {} + + void BombHolderSystem::_bombExplosion(WAL::Entity &bomb, WAL::Wal &wal) + { + bomb.scheduleDeletion(); + auto &bombPosition = bomb.getComponent(); + wal.getSystem().dispatchEvent([&bombPosition](WAL::Entity &entity){ + auto *health = entity.tryGetComponent(); + auto *pos = entity.tryGetComponent(); + + if (!health || !pos) + return; + if (pos->position.distance(bombPosition.position) > BombHolderSystem::explosionRadius) + return; + // TODO do a raycast here to only remove health to entities that are not behind others. + health->takeDmg(1); + }); + } + + void BombHolderSystem::_spawnBomb(Vector3f position) + { + this->_wal.scene->scheduleNewEntity("Bomb") + .addComponent(position) + .addComponent(BombHolderSystem::explosionTimer, &BombHolderSystem::_bombExplosion) + .addComponent("assets/bombs/bomb.obj", + std::make_pair(MAP_DIFFUSE, "assets/bombs/bomb_normal.png")); + } + + void BombHolderSystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) + { + auto &holder = entity.get(); + auto &position = entity.get(); + auto &controllable = entity.get(); + + if (controllable.bomb && holder.bombCount > 0) { + holder.bombCount--; + this->_spawnBomb(position.position); + } + if (holder.bombCount < holder.maxBombCount) { + holder.nextBombRefill -= dtime; + if (holder.nextBombRefill <= 0ns) { + holder.nextBombRefill = holder.refillRate; + holder.bombCount++; + } + } + } +} \ No newline at end of file diff --git a/sources/System/BombHolder/BombHolderSystem.hpp b/sources/System/BombHolder/BombHolderSystem.hpp new file mode 100644 index 00000000..fd3d4e78 --- /dev/null +++ b/sources/System/BombHolder/BombHolderSystem.hpp @@ -0,0 +1,43 @@ +// +// Created by Zoe Roux on 5/31/21. +// + +#pragma once + +#include +#include +#include "Models/Vector3.hpp" +#include "Component/Position/PositionComponent.hpp" +#include "Component/BombHolder/BombHolderComponent.hpp" +#include "Component/Controllable/ControllableComponent.hpp" + +namespace BBM +{ + //! @brief The system that allow one to place bombs. + class BombHolderSystem : public WAL::System + { + private: + //! @brief Spawn a bomb at the specified position. + void _spawnBomb(Vector3f position); + + //! @brief The method triggered when the bomb explode. + static void _bombExplosion(WAL::Entity &bomb, WAL::Wal &); + public: + //! @brief The explosion time of new bombs. + static std::chrono::nanoseconds explosionTimer; + //! @brief The radius of the explosion. + static float explosionRadius; + + //! @inherit + void onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) override; + + //! @brief A default constructor + explicit BombHolderSystem(WAL::Wal &wal); + //! @brief A bomb holder system is copy constructable + BombHolderSystem(const BombHolderSystem &) = default; + //! @brief A default destructor + ~BombHolderSystem() override = default; + //! @brief A bomb holder system is not assignable. + BombHolderSystem &operator=(const BombHolderSystem &) = delete; + }; +} diff --git a/sources/System/Event/EventSystem.cpp b/sources/System/Event/EventSystem.cpp new file mode 100644 index 00000000..af20674f --- /dev/null +++ b/sources/System/Event/EventSystem.cpp @@ -0,0 +1,28 @@ +// +// Created by Zoe Roux on 6/1/21. +// + +#include "EventSystem.hpp" + +namespace BBM +{ + EventSystem::EventSystem(WAL::Wal &wal) + : System(wal) + {} + + void EventSystem::dispatchEvent(const std::function &event) + { + this->_events.emplace_back(event); + } + + void EventSystem::onUpdate(WAL::ViewEntity<> &entity, std::chrono::nanoseconds) + { + for (auto &event : this->_events) + event(entity); + } + + void EventSystem::onSelfUpdate() + { + this->_events.clear(); + } +} \ No newline at end of file diff --git a/sources/System/Event/EventSystem.hpp b/sources/System/Event/EventSystem.hpp new file mode 100644 index 00000000..0a4c205f --- /dev/null +++ b/sources/System/Event/EventSystem.hpp @@ -0,0 +1,36 @@ +// +// Created by Zoe Roux on 6/1/21. +// + +#pragma once + +#include +#include +#include + +namespace BBM +{ + class EventSystem : public WAL::System<> + { + private: + //! @brief The list of events that occurred in the last update. + std::vector> _events; + public: + //! @brief Inform the system that a new event has occurred and it should run the given method on every entities. + void dispatchEvent(const std::function& event); + + //! @inherit + void onUpdate(WAL::ViewEntity<> &entity, std::chrono::nanoseconds dtime) override; + //! @inherit + void onSelfUpdate() override; + + //! @brief A default constructor + explicit EventSystem(WAL::Wal &wal); + //! @brief An event system is copy constructable. + EventSystem(const EventSystem &) = default; + //! @brief A default destructor + ~EventSystem() override = default; + //! @brief An event system is not assignable. + EventSystem &operator=(const EventSystem &) = delete; + }; +} diff --git a/sources/System/Keyboard/KeyboardSystem.cpp b/sources/System/Keyboard/KeyboardSystem.cpp index ccc207ab..740b9e3a 100644 --- a/sources/System/Keyboard/KeyboardSystem.cpp +++ b/sources/System/Keyboard/KeyboardSystem.cpp @@ -16,7 +16,7 @@ namespace BBM : System(wal) {} - void KeyboardSystem::onFixedUpdate(WAL::ViewEntity &entity) + void KeyboardSystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds) { const auto &keyboard = entity.get(); auto &controllable = entity.get(); @@ -28,7 +28,7 @@ namespace BBM }; for (auto key : keyPressedMap) - key.second = Keyboard::isDown(key.first); + key.second = Keyboard::isPressed(key.first); controllable.move = Vector2f(); if (Keyboard::isDown(keyboard.keyRight)) controllable.move.x += 1; diff --git a/sources/System/Keyboard/KeyboardSystem.hpp b/sources/System/Keyboard/KeyboardSystem.hpp index cf7309e1..e95bfcda 100644 --- a/sources/System/Keyboard/KeyboardSystem.hpp +++ b/sources/System/Keyboard/KeyboardSystem.hpp @@ -17,7 +17,7 @@ namespace BBM { public: //! @inherit - void onFixedUpdate(WAL::ViewEntity &entity) override; + void onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds) override; //! @brief A default constructor explicit KeyboardSystem(WAL::Wal &wal); diff --git a/sources/System/Timer/TimerSystem.cpp b/sources/System/Timer/TimerSystem.cpp new file mode 100644 index 00000000..f6c82c2b --- /dev/null +++ b/sources/System/Timer/TimerSystem.cpp @@ -0,0 +1,25 @@ +// +// Created by Zoe Roux on 5/31/21. +// + +#include "TimerSystem.hpp" +#include "Component/Timer/TimerComponent.hpp" + +using namespace std::chrono_literals; + +namespace BBM +{ + TimerSystem::TimerSystem(WAL::Wal &wal) + : System(wal) + {} + + void TimerSystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) + { + auto &timer = entity.get(); + timer.ringIn -= dtime; + if (timer.ringIn <= 0ns) { + timer.setDisable(true); + timer.callback(entity, this->_wal); + } + } +} \ No newline at end of file diff --git a/sources/System/Timer/TimerSystem.hpp b/sources/System/Timer/TimerSystem.hpp new file mode 100644 index 00000000..c7b20bc2 --- /dev/null +++ b/sources/System/Timer/TimerSystem.hpp @@ -0,0 +1,28 @@ +// +// Created by Zoe Roux on 5/31/21. +// + +#pragma once + +#include +#include +#include + +namespace BBM +{ + class TimerSystem : public WAL::System + { + public: + //! @inherit + void onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) override; + + //! @brief A default constructor + TimerSystem(WAL::Wal &); + //! @brief A timer system is copy constructable. + TimerSystem(const TimerSystem &) = default; + //! @brief A default destructor + ~TimerSystem() override = default; + //! @breief A timer system is assignable. + TimerSystem &operator=(const TimerSystem &) = default; + }; +} 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;