diff --git a/CMakeLists.txt b/CMakeLists.txt index f6f5ff40..dfb4cd6f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,8 +89,9 @@ add_executable(unit_tests EXCLUDE_FROM_ALL tests/EngineTests.cpp tests/CallbackTest.cpp tests/MoveTests.cpp + tests/ViewTest.cpp tests/CollisionTest.cpp - ) +) target_include_directories(unit_tests PUBLIC sources) target_link_libraries(unit_tests PUBLIC wal ray) diff --git a/assets/map/upper_floor_hole.mtl b/assets/map/upper_floor_hole.mtl new file mode 100644 index 00000000..829daba3 --- /dev/null +++ b/assets/map/upper_floor_hole.mtl @@ -0,0 +1,13 @@ +# Blender MTL File: 'None' +# Material Count: 1 + +newmtl floor +Ns 225.000000 +Ka 1.000000 1.000000 1.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 +map_Kd upper_floor_hole.png diff --git a/assets/map/upper_floor_hole.obj b/assets/map/upper_floor_hole.obj new file mode 100644 index 00000000..2042783c --- /dev/null +++ b/assets/map/upper_floor_hole.obj @@ -0,0 +1,54 @@ +# Blender v2.92.0 OBJ File: '' +# www.blender.org +mtllib upper_floor_hole.mtl +o floor +v -0.500000 -0.499144 0.500854 +v -0.500000 -0.500854 -0.499144 +v 0.500000 -0.499144 0.500855 +v 0.500000 -0.500855 -0.499144 +v 0.500000 0.500854 0.499144 +v 0.500000 0.499144 -0.500854 +v -0.500000 0.500855 0.499144 +v -0.500000 0.499144 -0.500855 +vt 0.000977 0.667790 +vt 0.000977 0.333151 +vt 0.333659 0.667790 +vt 0.333659 0.333151 +vt 0.666341 0.667790 +vt 0.666341 0.333151 +vt 0.333659 0.667790 +vt 0.333659 1.002429 +vt 0.000977 0.667790 +vt 0.000977 1.002429 +vt 0.666341 0.667790 +vt 0.666341 1.002429 +vt 0.333659 0.667790 +vt 0.333659 1.002429 +vt 0.666341 0.333151 +vt 0.999024 0.333151 +vt 0.666341 0.667790 +vt 0.999024 0.667790 +vt 0.999024 1.002429 +vt 0.666341 1.002429 +vt 0.999024 0.667790 +vt 0.666341 0.667790 +vn -0.0000 -1.0000 0.0017 +vn 1.0000 -0.0000 0.0000 +vn 0.0000 1.0000 -0.0017 +vn -1.0000 0.0000 -0.0000 +vn 0.0000 -0.0017 -1.0000 +vn -0.0000 0.0017 1.0000 +usemtl floor +s 1 +f 1/1/1 2/2/1 3/3/1 +f 3/3/1 2/2/1 4/4/1 +f 3/3/2 4/4/2 5/5/2 +f 5/5/2 4/4/2 6/6/2 +f 5/7/3 6/8/3 7/9/3 +f 7/9/3 6/8/3 8/10/3 +f 7/11/4 8/12/4 1/13/4 +f 1/13/4 8/12/4 2/14/4 +f 2/15/5 8/16/5 4/17/5 +f 4/17/5 8/16/5 6/18/5 +f 7/19/6 1/20/6 5/21/6 +f 5/21/6 1/20/6 3/22/6 diff --git a/assets/map/upper_floor_hole.png b/assets/map/upper_floor_hole.png new file mode 100644 index 00000000..43da7cd6 Binary files /dev/null and b/assets/map/upper_floor_hole.png differ diff --git a/build_web.sh b/build_web.sh index b5975bba..0fde576d 100755 --- a/build_web.sh +++ b/build_web.sh @@ -8,4 +8,4 @@ fi source ./emsdk/emsdk_env.sh mkdir -p build_web emcmake cmake -S . -B build_web -DPLATFORM=Web && -cmake --build build_web \ No newline at end of file +cd build_web && make -j $2 \ No newline at end of file diff --git a/lib/wal/CMakeLists.txt b/lib/wal/CMakeLists.txt index d216b9f3..9c30796f 100644 --- a/lib/wal/CMakeLists.txt +++ b/lib/wal/CMakeLists.txt @@ -7,7 +7,6 @@ add_library(wal sources/Entity/Entity.hpp sources/Component/Component.hpp sources/System/System.hpp - sources/Wal.cpp sources/Wal.hpp sources/Scene/Scene.cpp sources/Scene/Scene.hpp @@ -15,8 +14,10 @@ add_library(wal sources/Exception/WalError.hpp sources/Entity/Entity.cpp sources/Component/Component.cpp - sources/System/System.cpp sources/Models/Callback.hpp - sources/Models/TypeHolder.hpp) + sources/View/View.hpp + sources/System/ISystem.hpp + sources/Models/TypeHolder.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 56627a16..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 @@ -10,18 +11,20 @@ namespace WAL { unsigned Entity::nextID = 0; - Entity::Entity(std::string name) + Entity::Entity(Scene &scene, std::string name) : _uid(Entity::nextID++), + _scene(scene), _name(std::move(name)) { } Entity::Entity(const Entity &other) : _uid(Entity::nextID++), + _scene(other._scene), _name(other._name), _disabled(other._disabled) { for (const auto &cmp : other._components) - this->addComponent(*cmp); + this->addComponent(*cmp.second); } unsigned Entity::getUid() const @@ -46,25 +49,31 @@ namespace WAL Entity &Entity::addComponent(const Component &component) { - if (this->hasComponent(typeid(component))) - throw DuplicateError("A component of the type \"" + std::string(typeid(component).name()) + "\" already exists."); - this->_components.emplace_back(component.clone(*this)); + const std::type_index &type = typeid(component); + if (this->hasComponent(type)) + 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); return *this; } bool Entity::hasComponent(const std::type_info &type) const { - auto existing = std::find_if(this->_components.begin(), this->_components.end(), [&type] (const auto &cmp) { - return typeid(*cmp) == type; - }); - return existing != this->_components.end(); + return this->hasComponent(static_cast(type)); } bool Entity::hasComponent(const std::type_index &type) const { - auto existing = std::find_if(this->_components.begin(), this->_components.end(), [&type] (const auto &cmp) { - return std::type_index(typeid(*cmp)) == type; - }); - return existing != this->_components.end(); + 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 b64bfb82..25234f31 100644 --- a/lib/wal/sources/Entity/Entity.hpp +++ b/lib/wal/sources/Entity/Entity.hpp @@ -5,7 +5,7 @@ #pragma once #include -#include +#include #include #include #include "Component/Component.hpp" @@ -14,6 +14,8 @@ namespace WAL { + class Scene; + //! @brief An entity of the WAL's ECS. class Entity { @@ -25,10 +27,20 @@ namespace WAL //! @brief Is this entity enabled? bool _disabled = false; //! @brief The list of the components of this entity - std::vector> _components = {}; + std::unordered_map> _components = {}; //! @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; public: //! @brief Get the ID of the entity. unsigned getUid() const; @@ -42,17 +54,55 @@ namespace WAL void setDisable(bool disabled); //! @brief Get a component of a specific type + //! @tparam The type of the component //! @throw NotFoundError if the component could not be found + //! @return The component of the requested type. template T &getComponent() { - const std::type_info &type = typeid(T); - auto existing = std::find_if(this->_components.begin(), this->_components.end(), [&type] (const auto &cmp) { - return typeid(*cmp) == type; - }); + T *ret = this->tryGetComponent(); + if (ret == nullptr) + throw NotFoundError("No component could be found with the type \"" + std::string(typeid(T).name()) + "\"."); + return *ret; + } + + //! @brief Get a component of a specific type or null if not found. + //! @tparam The type of the component + //! @return The component or nullptr if not found. + template + T *tryGetComponent() + { + const std::type_index &type = typeid(T); + auto existing = this->_components.find(type); if (existing == this->_components.end()) - throw NotFoundError("No component could be found with the type \"" + std::string(type.name()) + "\"."); - return *static_cast(existing->get()); + return nullptr; + return static_cast(existing->second.get()); + } + + //! @brief Get a component of a specific type + //! @tparam The type of the component + //! @throw NotFoundError if the component could not be found + //! @return The component of the requested type. + template + const T &getComponent() const + { + const T *ret = this->tryGetComponent(); + if (ret == nullptr) + throw NotFoundError("No component could be found with the type \"" + std::string(typeid(T).name()) + "\"."); + return *ret; + } + + //! @brief Get a component of a specific type or null if not found. + //! @tparam The type of the component + //! @return The component or nullptr if not found. + template + const T *tryGetComponent() const + { + const std::type_index &type = typeid(T); + auto existing = this->_components.find(type); + if (existing == this->_components.end()) + return nullptr; + return static_cast(existing->second.get()); } //! @brief Check if this entity has a component. @@ -75,24 +125,14 @@ namespace WAL //! @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. //! @return This entity is returned - template + template Entity &addComponent(Types &&...params) { - if (this->hasComponent()) - throw DuplicateError("A component of the type \"" + std::string(typeid(T).name()) + "\" already exists."); - this->_components.push_back(std::make_unique(*this, std::forward(params)...)); - return *this; - } - - //! @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. - //! @return This entity is returned - template - Entity &addComponent(Types &&...params) - { - if (this->hasComponent()) - throw DuplicateError("A component of the type \"" + std::string(typeid(T).name()) + "\" already exists."); - this->_components.push_back(std::make_unique(*this, TypeHolder(), std::forward(params)...)); + const std::type_index &type = typeid(T); + 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); return *this; } @@ -107,17 +147,16 @@ namespace WAL Entity &removeComponent() { const std::type_info &type = typeid(T); - auto existing = std::find_if(this->_components.begin(), this->_components.end(), [&type] (const auto &cmp) { - return typeid(*cmp) == type; - }); + auto existing = this->_components.find(type); 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); return *this; } //! @brief A default constructor - explicit Entity(std::string name); + explicit Entity(Scene &wal, std::string name); //! @brief An entity is copyable Entity(const Entity &); //! @brief An entity is movable. diff --git a/lib/wal/sources/Models/Callback.hpp b/lib/wal/sources/Models/Callback.hpp index be2c092f..dc12a18b 100644 --- a/lib/wal/sources/Models/Callback.hpp +++ b/lib/wal/sources/Models/Callback.hpp @@ -24,10 +24,14 @@ namespace WAL //! @brief Add a method to be called when this callback is invoked. //! @param callback The list of arguments of the callback method //! @return A unique ID for this callback. That can be used to remove the callback later. - int addCallback(std::function callback) + template + int addCallback(Func callback) { int id = this->_nextID++; - this->_functions[id] = std::move(callback); + if constexpr(std::is_same_v>) + this->_functions[id] = std::move(callback); + else + this->_functions[id] = std::function(callback); return id; } @@ -53,8 +57,9 @@ namespace WAL //! @brief A default assignment operator Callback &operator=(const Callback &) = default; - //! @brief Implicitly transform a function into a callback. - Callback(std::function callback) // NOLINT(google-explicit-constructor) + //! @brief Implicitly transform a callable into a callback. + template + Callback(Func callback) // NOLINT(google-explicit-constructor) { this->addCallback(callback); } diff --git a/lib/wal/sources/Scene/Scene.cpp b/lib/wal/sources/Scene/Scene.cpp index 3c07f3c8..77526662 100644 --- a/lib/wal/sources/Scene/Scene.cpp +++ b/lib/wal/sources/Scene/Scene.cpp @@ -3,15 +3,46 @@ // #include "Scene.hpp" +#include namespace WAL { - std::vector &Scene::getEntities() + int Scene::_nextID = 0; + + std::list &Scene::getEntities() { return this->_entities; } + Scene &Scene::operator=(const Scene &) { return *this; } + + Entity &Scene::addEntity(const std::string &name) + { + return this->_entities.emplace_back(*this, name); + } + + void Scene::_componentAdded(Entity &entity, const std::type_index &type) + { + for (auto &view : this->_views) { + if (std::find(view->getTypes().begin(), view->getTypes().end(), type) == view->getTypes().end()) + continue; + 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); + } + } + + void Scene::_componentRemoved(const Entity &entity, const std::type_index &type) + { + for (auto &view : this->_views) { + if (std::find(view->getTypes().begin(), view->getTypes().end(), type) == view->getTypes().end()) + continue; + view->erase(entity); + } + } } // 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 bddf1e5c..aab47566 100644 --- a/lib/wal/sources/Scene/Scene.hpp +++ b/lib/wal/sources/Scene/Scene.hpp @@ -6,7 +6,9 @@ #pragma once #include +#include #include +#include #include "Entity/Entity.hpp" namespace WAL @@ -15,18 +17,43 @@ namespace WAL class Scene { private: + static int _nextID; + //! @brief An ID representing this scene. + int _id = _nextID++; + //! @brief The list of registered entities - std::vector _entities = {}; + std::list _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(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, const std::type_index &type); public: //! @brief Get the list of entities. - std::vector &getEntities(); + std::list &getEntities(); - //! @brief Add a new entity to the scene, you can use this method with the same arguments as the entity's constructor. - //! @return The current scene is returned to allow you to chain call. - template - Entity &addEntity(Params &&...params) + //! @brief Add a new entity to the scene. + //! @param name The name of the created entity. + //! @return The created entity is returned. + Entity &addEntity(const std::string &name); + + template + View &view() { - return this->_entities.emplace_back(std::forward(params)...); + static std::unordered_map>> cache; + auto existing = cache.find(this->_id); + if (existing != cache.end() && !existing->second.expired()) + return *existing->second.lock(); + auto view = std::make_shared>(this->_entities); + this->_views.emplace_back(view); + cache.emplace(this->_id, view); + return *view; } //! @brief A default constructor @@ -38,5 +65,7 @@ namespace WAL //! @brief A scene is assignable Scene &operator=(const Scene &); Scene(Scene &&) = default; + + friend Entity; }; } // namespace WAL \ No newline at end of file diff --git a/lib/wal/sources/System/ISystem.hpp b/lib/wal/sources/System/ISystem.hpp new file mode 100644 index 00000000..ab8dc3f3 --- /dev/null +++ b/lib/wal/sources/System/ISystem.hpp @@ -0,0 +1,32 @@ +// +// Created by Zoe Roux on 2021-06-04. +// + + +#pragma once + +#include "Entity/Entity.hpp" +#include "View/View.hpp" +#include + +namespace WAL +{ + //! @brief A base class that represent a system. + class ISystem + { + public: + //! @brief Update the whole system (every entities that this system is responsible can be updated. + //! @param dtime The delta time since the last call to this method. + virtual void update(std::chrono::nanoseconds dtime) = 0; + + //! @brief An alternative of update that is called every 8ms (120 times per seconds). If the system slow down, it will try to catch up. + //! @remark This should be used for Physics, AI and everything that could be imprecise due to float rounding. + virtual void fixedUpdate() = 0; + + //! @brief Get a view containing every entity this system should update. + virtual IView &getView() = 0; + + //! @brief A virtual default destructor. + virtual ~ISystem() = default; + }; +} \ No newline at end of file diff --git a/lib/wal/sources/System/System.cpp b/lib/wal/sources/System/System.cpp deleted file mode 100644 index 0dd69f30..00000000 --- a/lib/wal/sources/System/System.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// -// Created by Zoe Roux on 5/17/21. -// - -#include "System.hpp" -#include -#include - -namespace WAL -{ - System::System(std::vector dependencies) - : _dependencies(std::move(dependencies)) - {} - - void System::onUpdate(Entity &entity, std::chrono::nanoseconds dtime) - {} - - void System::onFixedUpdate(Entity &entity) - {} - - void System::onSelfUpdate() - {} - - const std::vector &System::getDependencies() const - { - return this->_dependencies; - } -} // 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 59c82c4a..58f49970 100644 --- a/lib/wal/sources/System/System.hpp +++ b/lib/wal/sources/System/System.hpp @@ -6,40 +6,71 @@ #include #include +#include +#include #include "Entity/Entity.hpp" +#include "Wal.hpp" +#include "View/View.hpp" +#include "ISystem.hpp" +#include namespace WAL { //! @brief A base system of WAL - class System + //! @tparam Dependencies The list of dependencies this system has. + template + class System : public ISystem { - private: - //! @brief The list of dependencies of this system - std::vector _dependencies = {}; public: //! @brief A virtual, default, destructor - virtual ~System() = default; + ~System() override = default; //! @brief A system can be moved - System(System &&) = default; + System(System &&) noexcept = default; - //! @brief Get the name of the component corresponding to this system. - const std::vector &getDependencies() const; + //! @brief Get a view of all entities containing every dependencies of this system. + View &getView() override + { + return this->_wal.scene->template view(); + } //! @brief Update the corresponding component of the given entity //! @param entity The entity to update. //! @param dtime The delta time. - virtual void onUpdate(Entity &entity, std::chrono::nanoseconds dtime); + virtual void onUpdate(ViewEntity &entity, std::chrono::nanoseconds dtime) {} //! @brief An alternative of onUpdate that is called every 8ms (120 times per seconds). If the system slow down, it will try to catch up. //! @remark This should be used for Physics, AI and everything that could be imprecise due to float rounding. //! @param entity The entity to update. - virtual void onFixedUpdate(Entity &entity); + virtual void onFixedUpdate(ViewEntity &entity) {} //! @brief A method called after all entities that this system manage has been updated. - virtual void onSelfUpdate(); + virtual void onSelfUpdate() {} + + + //! @brief Update the whole system (every entities that this system is responsible can be updated. + //! @param dtime The delta time since the last call to this method. + void update(std::chrono::nanoseconds dtime) final + { + for (auto &entity : this->getView()) + this->onUpdate(entity, dtime); + this->onSelfUpdate(); + } + + //! @brief An alternative of update that is called every 8ms (120 times per seconds). If the system slow down, it will try to catch up. + //! @remark This should be used for Physics, AI and everything that could be imprecise due to float rounding. + void fixedUpdate() final + { + for (auto &entity : this->getView()) + this->onFixedUpdate(entity); + } protected: + //! @brief A reference to the ECS. + Wal &_wal; + //! @brief A system can't be instantiated, it should be derived. - explicit System(std::vector dependencies); + explicit System(Wal &wal) + : _wal(wal) + {} //! @brief A system can't be instantiated, it should be derived. System(const System &) = default; //! @brief A system can't be instantiated, it should be derived. diff --git a/lib/wal/sources/View/View.hpp b/lib/wal/sources/View/View.hpp new file mode 100644 index 00000000..15b31e09 --- /dev/null +++ b/lib/wal/sources/View/View.hpp @@ -0,0 +1,222 @@ +// +// Created by Zoe Roux on 2021-06-03. +// + + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "Entity/Entity.hpp" + +namespace WAL +{ + template + class ViewEntity + { + private: + std::tuple, std::reference_wrapper...> &_value; + public: + explicit ViewEntity(std::tuple, std::reference_wrapper...> &value) + : _value(value) + {} + + Entity *operator->() + { + return &(std::get<0>(this->_value).get()); + } + + Entity &operator*() + { + return std::get<0>(this->_value); + } + + operator Entity &() + { + return std::get<0>(this->_value); + } + + template + T &get() + { + return std::get>(this->_value); + } + + template + auto &get() + { + return std::get(this->_value); + } + }; + + template + class ViewIterator + { + private: + It _it; + std::optional> _entity; + + public: + ViewEntity &operator*() + { + if (!this->_entity) + this->_entity.emplace(*this->_it); + return *this->_entity; + } + + ViewEntity *operator->() + { + if (!this->_entity) + this->_entity =(*this->_it); + return &this->_entity; + } + + ViewIterator &operator++() + { + this->_it++; + this->_entity = std::nullopt; + return *this; + } + + ViewIterator operator++(int) + { + ViewIterator copy = *this; + this->_it++; + this->_entity = std::nullopt; + return *this; + } + + bool operator==(const ViewIterator &other) const + { + return this->_it == other._it; + } + + bool operator!=(const ViewIterator &other) const + { + return !this->operator==(other); + } + + explicit ViewIterator(It current) + : _it(current), + _entity(std::nullopt) + {} + }; + + //! @brief A basic view used to manipulate view without knowing their type at compile time. + class IView + { + public: + //! @brief The list of types that every entity of the view has. + virtual const std::vector &getTypes() const = 0; + + virtual void emplace_back(Entity &) = 0; + + virtual void erase(const Entity &) = 0; + + //! @brief A default destructor + virtual ~IView() = default; + }; + + //! @brief A view allowing one to easily access entities containing a set list of component. + //! A view is always updated and only references to entities are kept. + template + class View : public IView + { + private: + using entity_type = std::tuple, std::reference_wrapper...>; + + //! @brief The list of entities in the view. + std::vector _entities = {}; + //! @brief The list of types that every entity of the view has. + std::vector _types = {}; + public: + using iterator = ViewIterator::iterator, Components...>; + + iterator begin() + { + return iterator(this->_entities.begin()); + } + + iterator end() + { + return iterator(this->_entities.end()); + } + + std::size_t size() const + { + return this->_entities.size(); + } + + ViewEntity front() + { + return *iterator(this->_entities.begin()); + } + + ViewEntity back() + { + return *iterator(--this->_entities.end()); + } + + const std::vector &getTypes() const override + { + return this->_types; + } + + void emplace_back(Entity &entity) override + { + auto tuple = std::make_tuple(entity.tryGetComponent()...); + if (std::apply([](const auto *...component) {return ((component == nullptr) || ...);}, tuple)) + return; + std::apply([&](auto *...component) { + this->_entities.emplace_back(entity, *component...); + }, tuple); + } + + 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; + })); + } + + //! @brief Construct a view from a list of entities. + //! Those entities are never copied but references to them are kept internally. + explicit View(std::list &scene) + { + this->_types = {typeid(Components)...}; + for (auto &entity : scene) + this->emplace_back(entity); + } + + //! @brief Copying a view is not possible since a view must be managed by a scene. + View(const View &) = delete; + //! @brief A default destructor + ~View() override = default; + //! @brief A view is not assignable. + View &operator=(const View &) = delete; + }; +} + +namespace std +{ + template + struct tuple_size<::WAL::ViewEntity> + : public std::integral_constant + {}; + + template + struct tuple_element<0, ::WAL::ViewEntity> + { + using type = WAL::Entity &; + }; + + template + struct tuple_element> + { + using type = typename std::tuple_element>::type; + }; +} \ No newline at end of file diff --git a/lib/wal/sources/Wal.cpp b/lib/wal/sources/Wal.cpp deleted file mode 100644 index 371c5774..00000000 --- a/lib/wal/sources/Wal.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// -// Created by Zoe Roux on 2021-05-14. -// - -#include -#include -#include "Wal.hpp" - -namespace WAL -{ - std::chrono::nanoseconds Wal::timestep = std::chrono::milliseconds(8); - - void Wal::_update(std::chrono::nanoseconds dtime) - { - auto &entities = this->scene->getEntities(); - - for (auto &system : this->_systems) { - for (auto &entity : entities) { - if (!Wal::_hasDependencies(entity, *system)) - continue; - system->onUpdate(entity, dtime); - } - system->onSelfUpdate(); - } - } - - void Wal::_fixedUpdate() - { - auto &entities = this->scene->getEntities(); - - for (auto &system : this->_systems) { - for (auto &entity : entities) { - if (!Wal::_hasDependencies(entity, *system)) - continue; - system->onFixedUpdate(entity); - } - } - } - - bool Wal::_hasDependencies(const Entity &entity, const System &system) - { - // TODO use an hashmap to cache results. - const auto &dependency = system.getDependencies(); - for (const auto &dependency : system.getDependencies()) { - if (!entity.hasComponent(dependency)) - return false; - } - return true; - } -} // namespace WAL \ No newline at end of file diff --git a/lib/wal/sources/Wal.hpp b/lib/wal/sources/Wal.hpp index 3785081a..de6bb394 100644 --- a/lib/wal/sources/Wal.hpp +++ b/lib/wal/sources/Wal.hpp @@ -10,10 +10,9 @@ #include #include #include "Exception/WalError.hpp" -#include "Scene/Scene.hpp" -#include "Entity/Entity.hpp" -#include "System/System.hpp" +#include "System/ISystem.hpp" #include "Models/Callback.hpp" +#include "Scene/Scene.hpp" #if defined(PLATFORM_WEB) #include @@ -21,31 +20,71 @@ namespace WAL { + class Entity; + //! @brief The main WAL class, it is used to setup and run the ECS. class Wal { private: //! @brief The list of registered systems - std::vector> _systems = {}; + std::vector> _systems = {}; - //! @brief Call the onUpdate of every system with every component - void _update(std::chrono::nanoseconds dtime); + //! @brief Start the game loop + //! @param callback A callback called after each update of the game. It allow you to update the engine based on a specific game state. (you can also update the game state here) + //! @param state An initial game state. If not specified, it will be defaulted. + //! @tparam T A type used to track your game state. It must be default constructable. + template + void _run(const Callback &callback, T state = T()) + { + auto lastTick = std::chrono::steady_clock::now(); + std::chrono::nanoseconds fBehind(0); - //! @brief Call the onFixedUpdate of every system with every component - void _fixedUpdate(); + while (!this->shouldClose) { + auto now = std::chrono::steady_clock::now(); + std::chrono::nanoseconds dtime = now - lastTick; + fBehind += dtime; + lastTick = now; - //! @brief Check if an entity met a system's dependencies. - //! @param entity The entity to check - //! @param system The system that will list dependencies - //! @return True if all dependencies are met, false otherwise. - static bool _hasDependencies(const Entity &entity, const System &system); + while (fBehind > Wal::timestep) { + fBehind -= Wal::timestep; + for (auto &system : this->_systems) + system->fixedUpdate(); + } + for (auto &system : this->_systems) + system->update(dtime); + callback(*this, state); + } + } + +#if defined(PLATFORM_WEB) + template + static void _runIteration(void *param) + { + static auto [wal, callback, state] = *reinterpret_cast &, T &> *>(param); + static auto lastTick = std::chrono::steady_clock::now(); + static std::chrono::nanoseconds fBehind(0); + + auto now = std::chrono::steady_clock::now(); + std::chrono::nanoseconds dtime = now - lastTick; + fBehind += dtime; + lastTick = now; + while (fBehind > Wal::timestep) { + fBehind -= Wal::timestep; + for (auto &system : wal._systems) + system->fixedUpdate(); + } + for (auto &system : wal._systems) + system->update(dtime); + callback(wal, state); + } +#endif public: //! @brief The scene that contains entities. std::shared_ptr scene; //! @brief True if the engine should close after the end of the current tick. bool shouldClose = false; //! @brief The time between each fixed update. - static std::chrono::nanoseconds timestep; + static constexpr std::chrono::nanoseconds timestep = std::chrono::milliseconds(32); //! @brief Create a new system in place. //! @return The wal instance used to call this function is returned. This allow method chaining. @@ -58,7 +97,7 @@ namespace WAL }); if (existing != this->_systems.end()) throw DuplicateError("A system of the type \"" + std::string(type.name()) + "\" already exists."); - this->_systems.push_back(std::make_unique(std::forward(params)...)); + this->_systems.push_back(std::make_unique(*this, std::forward(params)...)); return *this; } @@ -105,23 +144,6 @@ namespace WAL return *this; } - //! @brief Start the game loop - //! @param callback A callback called after each update of the game. It allow you to update the engine based on a specific game state. (you can also update the game state here) - //! @param state An initial game state. If not specified, it will be defaulted. - //! @tparam T A type used to track your game state. It must be default constructable. - template - void run(const std::function &callback, T state = T()) - { - Callback update(callback); - - #if defined(PLATFORM_WEB) - std::tuple iterationParams(this, &update, &state); - return emscripten_set_main_loop_arg((em_arg_callback_func)runIteration, (void *)&iterationParams, 0, 1); - #else - return this->run(update, state); - #endif - } - //! @brief Start the game loop //! @param callback A callback called after each update of the game. It allow you to update the engine based on a specific game state. (you can also update the game state here) //! @param state An initial game state. If not specified, it will be defaulted. @@ -129,48 +151,14 @@ namespace WAL template void run(const Callback &callback, T state = T()) { - auto lastTick = std::chrono::steady_clock::now(); - std::chrono::nanoseconds fBehind(0); - - while (!this->shouldClose) { - auto now = std::chrono::steady_clock::now(); - std::chrono::nanoseconds dtime = now - lastTick; - fBehind += dtime; - lastTick = now; - - while (fBehind > Wal::timestep) { - fBehind -= Wal::timestep; - this->_fixedUpdate(); - } - this->_update(dtime); - callback(*this, state); - } + #if defined(PLATFORM_WEB) + std::tuple &, T &> iterationParams(*this, callback, state); + return emscripten_set_main_loop_arg((em_arg_callback_func)_runIteration, (void *)&iterationParams, 0, 1); + #else + return this->_run(callback, state); + #endif } - #if defined(PLATFORM_WEB) - template - static void runIteration(void *param) - { - static auto iterationParams = reinterpret_cast *, T *> *>(param); - static const Callback callback = *((Callback *)std::get<1>(*iterationParams)); - static T *state = (T *)std::get<2>(*iterationParams); - static Wal *wal = (Wal *)std::get<0>(*iterationParams); - static auto lastTick = std::chrono::steady_clock::now(); - static std::chrono::nanoseconds fBehind(0); - - auto now = std::chrono::steady_clock::now(); - std::chrono::nanoseconds dtime = now - lastTick; - fBehind += dtime; - lastTick = now; - while (fBehind > Wal::timestep) { - fBehind -= Wal::timestep; - wal->_fixedUpdate(); - } - wal->_update(dtime); - callback(*wal, *state); - } - #endif - //! @brief A default constructor Wal() = default; //! @brief A WAL can't be copy constructed diff --git a/sources/Component/Collision/CollisionComponent.cpp b/sources/Component/Collision/CollisionComponent.cpp index 22cbdef8..df727b2d 100644 --- a/sources/Component/Collision/CollisionComponent.cpp +++ b/sources/Component/Collision/CollisionComponent.cpp @@ -16,14 +16,6 @@ namespace BBM return new CollisionComponent(entity); } - CollisionComponent::CollisionComponent(WAL::Entity &entity, std::function onCollide, std::function onCollided, Vector3f bound) - : WAL::Component(entity), onCollide(onCollide), onCollided(onCollided), bound(bound) - { } - - CollisionComponent::CollisionComponent(WAL::Entity &entity, std::function onCollide, std::function onCollided, float boundSize) - : WAL::Component(entity), onCollide(onCollide), onCollided(onCollided), bound({boundSize, boundSize, boundSize}) - { } - CollisionComponent::CollisionComponent(WAL::Entity &entity, WAL::Callback onCollide, WAL::Callback onCollided, Vector3f bound) : WAL::Component(entity), onCollide(onCollide), onCollided(onCollided), bound(bound) { } diff --git a/sources/Component/Collision/CollisionComponent.hpp b/sources/Component/Collision/CollisionComponent.hpp index 4636c79a..5bfe7e16 100644 --- a/sources/Component/Collision/CollisionComponent.hpp +++ b/sources/Component/Collision/CollisionComponent.hpp @@ -27,12 +27,6 @@ namespace BBM //! @brief A component can't be instantiated, it should be derived. explicit CollisionComponent(WAL::Entity &entity); - //! @brief Constructor with a callback function - CollisionComponent(WAL::Entity &entity, std::function onCollide, std::function onCollided, Vector3f bound); - - //! @brief Constructor with a callback function, same boundSize for all axis - CollisionComponent(WAL::Entity &entity, std::function onCollide, std::function onCollided, float boundSize = 0); - //! @brief Constructor with a WAL::Callback CollisionComponent(WAL::Entity &entity, WAL::Callback onCollide, WAL::Callback onCollided,Vector3f bound); diff --git a/sources/Component/Movable/MovableComponent.cpp b/sources/Component/Movable/MovableComponent.cpp index 51f0707d..26a8fd11 100644 --- a/sources/Component/Movable/MovableComponent.cpp +++ b/sources/Component/Movable/MovableComponent.cpp @@ -20,11 +20,6 @@ namespace BBM this->_acceleration += force; } - void MovableComponent::resetVelocity(void) - { - this->_velocity = {0, 0, 0}; - } - const Vector3f &MovableComponent::getVelocity(void) const { return _velocity; diff --git a/sources/Component/Movable/MovableComponent.hpp b/sources/Component/Movable/MovableComponent.hpp index 13c8bf90..6fecf89e 100644 --- a/sources/Component/Movable/MovableComponent.hpp +++ b/sources/Component/Movable/MovableComponent.hpp @@ -23,9 +23,6 @@ namespace BBM //! @param force The force to add to this entity's acceleration. The force is added instantly and in one go. void addForce(Vector3f force); - //! @brief Set velocity to 0 - void resetVelocity(void); - //! @brief Get velocity const Vector3f &getVelocity(void) const; @@ -42,5 +39,6 @@ namespace BBM MovableComponent &operator=(const MovableComponent &) = delete; friend class MovableSystem; + friend class MapGenerator; }; } // namespace WAL \ No newline at end of file diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index 6c2dc83c..c4709164 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -3,12 +3,33 @@ // Edited by Benjamin Henry on 5/26/21. // +#include #include "Map.hpp" +#include namespace RAY3D = RAY::Drawables::Drawables3D; namespace BBM { + void MapGenerator::wallCollide(WAL::Entity &entity, const WAL::Entity &wall) + { + auto *mov = entity.tryGetComponent(); + if (!mov) + return; + auto &pos = entity.getComponent(); + 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; + } + const std::string MapGenerator::assetsPath = "./assets/"; const std::string MapGenerator::wallAssetsPath = MapGenerator::assetsPath + "map/"; const std::string MapGenerator::imageExtension = ".png"; @@ -20,20 +41,20 @@ namespace BBM const std::string MapGenerator::stairsPath = MapGenerator::wallAssetsPath + "stairs"; const std::string MapGenerator::bumperPath = MapGenerator::wallAssetsPath + "bumper"; const std::string MapGenerator::holePath = MapGenerator::wallAssetsPath + "hole"; + const std::string MapGenerator::secondFloorHolePath = MapGenerator::secondFloorPath + "_hole"; void MapGenerator::generateUnbreakableBlock(int width, int height, std::shared_ptr scene) { - static const std::string UnbreakableObj = unbreakableWallPath + objExtension; - static const std::string UnbreakablePng = unbreakableWallPath + imageExtension; + static const std::string unbreakableObj = unbreakableWallPath + objExtension; + static const std::string unbreakablePng = unbreakableWallPath + imageExtension; for (int i = 0; i < width + 1; i++) { for (int j = 0; j < height + 1; j++) { if (!(i % 2) && !(j % 2)) { scene->addEntity("Unbreakable Wall") - .addComponent(Vector3f(i, 0, j)) - //.addComponent(1) - .addComponent(UnbreakableObj, - std::make_pair(MAP_DIFFUSE, UnbreakablePng)); + .addComponent(i, 0, j) + .addComponent(WAL::Callback(), &MapGenerator::wallCollide, .75) + .addComponent(unbreakableObj, std::make_pair(MAP_DIFFUSE, unbreakablePng)); } } } @@ -46,25 +67,25 @@ namespace BBM scene->addEntity("Bottom Wall") .addComponent(Vector3f((width + 1) / 2, 0, -1)) - //.addComponent(1) + .addComponent(WAL::Callback(), &MapGenerator::wallCollide, .75) .addComponent(unbreakableObj, std::make_pair(MAP_DIFFUSE, unbreakablePnj), RAY::Vector3(width + 3, 1, 1)); scene->addEntity("Upper Wall") .addComponent(Vector3f((width + 1) / 2, 0, height + 1)) - //.addComponent(1) + .addComponent(WAL::Callback(), &MapGenerator::wallCollide, .75) .addComponent(unbreakableObj, std::make_pair(MAP_DIFFUSE, unbreakablePnj), RAY::Vector3(width + 3, 1, 1)); scene->addEntity("Left Wall") .addComponent(Vector3f(width + 1, 0, height / 2)) - //.addComponent(1) + .addComponent(WAL::Callback(), &MapGenerator::wallCollide, .75) .addComponent(unbreakableObj, std::make_pair(MAP_DIFFUSE, unbreakablePnj), RAY::Vector3(1, 1, height + 1)); scene->addEntity("Right Wall") .addComponent(Vector3f(-1, 0, height / 2)) - //.addComponent(1) + .addComponent(WAL::Callback(), &MapGenerator::wallCollide, .75) .addComponent(unbreakableObj, std::make_pair(MAP_DIFFUSE, unbreakablePnj), RAY::Vector3(1, 1, height + 1)); @@ -80,8 +101,7 @@ namespace BBM if (map[std::make_tuple(i, 0, j)] != HOLE && map[std::make_tuple(i, -1, j)] != BUMPER) scene->addEntity("Unbreakable Wall") .addComponent(Vector3f(i, -1, j)) - //.addComponent(1) - .addComponent(floorObj, + .addComponent(floorObj, std::make_pair(MAP_DIFFUSE, floorPng)); } } @@ -115,7 +135,7 @@ namespace BBM scene->addEntity("Breakable Block") .addComponent(coords) .addComponent(1) - //.addComponent(1) + .addComponent(WAL::Callback(), &MapGenerator::wallCollide, .75) .addComponent(breakableObj, std::make_pair(MAP_DIFFUSE, breakablePng)); } @@ -126,7 +146,7 @@ namespace BBM scene->addEntity("Floor") .addComponent(Vector3f(coords)) - //.addComponent(1) + //.addComponent(1) .addComponent(floorObj, std::make_pair(MAP_DIFFUSE, floorPng)); } @@ -137,7 +157,6 @@ namespace BBM scene->addEntity("Upper Floor") .addComponent(Vector3f(coords)) - //.addComponent(1) .addComponent(floorObj, std::make_pair(MAP_DIFFUSE, floorPng)); } @@ -149,7 +168,7 @@ namespace BBM scene->addEntity("Unbreakable Block") .addComponent(coords) - //.addComponent(1) + .addComponent(WAL::Callback(), &MapGenerator::wallCollide, .75) .addComponent(UnbreakableObj, std::make_pair(MAP_DIFFUSE, UnbreakablePng)); } @@ -158,10 +177,17 @@ namespace BBM { static const std::string holeObj = holePath + objExtension; static const std::string holePng = holePath + imageExtension; + static const std::string secondFloorObj = secondFloorHolePath + objExtension; + static const std::string secondFloorPng = secondFloorHolePath + imageExtension; - scene->addEntity("Hole Block") - .addComponent(Vector3f(coords.x, coords.y - 1, coords.z)) - .addComponent(holeObj, std::make_pair(MAP_DIFFUSE, holePng)); + WAL::Entity &holeEntity = scene->addEntity("Hole Block"); + + holeEntity.addComponent(Vector3f(coords.x, coords.y - 1, coords.z)); + + if (coords.y == 0) + holeEntity.addComponent(holeObj, std::make_pair(MAP_DIFFUSE, holePng)); + else + holeEntity.addComponent(secondFloorObj, std::make_pair(MAP_DIFFUSE, secondFloorPng)); /*.addComponent([](WAL::Entity &other, const WAL::Entity &entity) { if (other.hasComponent()) { auto &health = other.getComponent(); @@ -193,7 +219,7 @@ namespace BBM scene->addEntity("Stairs Block") .addComponent(coords) - //.addComponent(1) + //.addComponent(1) .addComponent(stairsObj, std::make_pair(MAP_DIFFUSE, stairsPng)); } diff --git a/sources/Map/Map.hpp b/sources/Map/Map.hpp index f08f25bd..f6b082a8 100644 --- a/sources/Map/Map.hpp +++ b/sources/Map/Map.hpp @@ -14,7 +14,6 @@ #include #include #include "Component/Renderer/Drawable3DComponent.hpp" -#include "System/Renderer/RenderSystem.hpp" #include "Scene/Scene.hpp" #include "Model/Model.hpp" #include "Component/Component.hpp" @@ -154,7 +153,11 @@ namespace BBM static const std::string holePath; + static const std::string secondFloorHolePath; + public: + static void wallCollide(WAL::Entity &entity, const WAL::Entity &wall); + //! @param width Width of the map //! @param height Height of the map diff --git a/sources/Models/Vector2.hpp b/sources/Models/Vector2.hpp index 629a11b8..37728478 100644 --- a/sources/Models/Vector2.hpp +++ b/sources/Models/Vector2.hpp @@ -120,6 +120,14 @@ namespace BBM return std::sqrt(std::pow(this->x - o.x, 2) + std::pow(this->y - o.y, 2)); } + double angle(const Vector2 &o) const + { + float dot = this->x * o.x + this->y * o.y; + float det = this->x * o.y - this->y * o.x; + return (std::atan2(det, dot) * (180.0f / M_PI)); + //return (std::atan(std::abs(o.y - this->y) / std::abs(o.x - this->x))); + } + double magnitude() const { return std::sqrt(std::pow(this->x, 2) + std::pow(this->y, 2)); diff --git a/sources/Models/Vector3.hpp b/sources/Models/Vector3.hpp index dc1752f1..d4ba7337 100644 --- a/sources/Models/Vector3.hpp +++ b/sources/Models/Vector3.hpp @@ -71,7 +71,13 @@ namespace BBM } template - Vector3 &operator*=(T2 d) + Vector3 operator-(const Vector3 &vec) const + { + return Vector3(this->x - vec.x, this->y - vec.y, this->z - vec.z); + } + + template + Vector3 &operator*=(const T2 d) { this->x *= d; this->y *= d; @@ -80,7 +86,7 @@ namespace BBM } template - Vector3 operator*(T2 d) const + Vector3 operator*(const T2 d) const { return Vector3(this->x * d, this->y * d, this->z * d); } diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 5e0449e9..5077b06f 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -8,8 +8,6 @@ #include "System/Renderer/RenderSystem.hpp" #include #include -#include -#include #include #include #include @@ -19,9 +17,7 @@ #include #include #include -#include "Models/Vector2.hpp" #include "Component/Renderer/CameraComponent.hpp" -#include "Component/Renderer/Drawable2DComponent.hpp" #include "Component/Renderer/Drawable3DComponent.hpp" #include "Runner.hpp" #include "Models/GameState.hpp" @@ -32,7 +28,6 @@ #include "System/Animation/AnimationsSystem.hpp" #include "Map/Map.hpp" -namespace RAY2D = RAY::Drawables::Drawables2D; namespace RAY3D = RAY::Drawables::Drawables3D; namespace BBM @@ -51,10 +46,8 @@ namespace BBM { wal.addSystem() .addSystem() - .addSystem() - .addSystem() .addSystem() - .addSystem(wal) + .addSystem() .addSystem(); } @@ -62,7 +55,9 @@ namespace BBM { RAY::TraceLog::setLevel(LOG_WARNING); RAY::Window &window = RAY::Window::getInstance(600, 400, "Bomberman", FLAG_WINDOW_RESIZABLE); - wal.addSystem(wal, window); + wal.addSystem() + .addSystem() + .addSystem(window); } std::shared_ptr loadGameScene() @@ -81,22 +76,15 @@ namespace BBM auto &animation = entity.getComponent(); animation.setAnimIndex(5); }); - scene->addEntity("cube") - .addComponent(-5, 0, -5) - .addComponent(Vector3f(-5, 0, -5), Vector3f(3, 3, 3), RED) - .addComponent() - .addComponent() - .addComponent([](WAL::Entity &, const WAL::Entity &){}, - [](WAL::Entity &actual, const WAL::Entity &) { - try { - auto &mov = actual.getComponent(); - mov.resetVelocity(); - } catch (std::exception &e) { }; - }, 3); - scene->addEntity("camera") .addComponent(8, 20, 7) .addComponent(Vector3f(8, 0, 8)); +// scene->addEntity("cube") +// .addComponent(5, 0, 5) +// .addComponent(Vector3f(-5, 0, -5), Vector3f(3, 3, 3), RED) +// .addComponent() +// .addComponent() +// .addComponent(WAL::Callback(), &MapGenerator::wallCollide, 3); std::srand(std::time(nullptr)); MapGenerator::loadMap(16, 16, MapGenerator::createMap(16, 16), scene); return scene; diff --git a/sources/System/Animation/AnimationsSystem.cpp b/sources/System/Animation/AnimationsSystem.cpp index cce35719..5aaa4597 100644 --- a/sources/System/Animation/AnimationsSystem.cpp +++ b/sources/System/Animation/AnimationsSystem.cpp @@ -11,18 +11,14 @@ namespace BBM { - AnimationsSystem::AnimationsSystem() - : WAL::System({ - typeid(Drawable3DComponent), - typeid(AnimationsComponent) - }) - { - } + AnimationsSystem::AnimationsSystem(WAL::Wal &wal) + : System(wal) + {} - void AnimationsSystem::onUpdate(WAL::Entity &entity, std::chrono::nanoseconds) + void AnimationsSystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds) { - auto &model = entity.getComponent(); - auto &anim = entity.getComponent(); + auto &model = entity.get(); + auto &anim = entity.get(); if (anim.isDisabled()) return; diff --git a/sources/System/Animation/AnimationsSystem.hpp b/sources/System/Animation/AnimationsSystem.hpp index fb08b2ef..6ace28d8 100644 --- a/sources/System/Animation/AnimationsSystem.hpp +++ b/sources/System/Animation/AnimationsSystem.hpp @@ -5,22 +5,24 @@ #pragma once #include +#include "Component/Renderer/Drawable3DComponent.hpp" +#include "Component/Animation/AnimationsComponent.hpp" namespace BBM { - class AnimationsSystem : public WAL::System + class AnimationsSystem : public WAL::System { public: //! @inherit - void onUpdate(WAL::Entity &entity, std::chrono::nanoseconds) override; + void onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds) override; //! @brief A default constructor - AnimationsSystem(); + explicit AnimationsSystem(WAL::Wal &wal); //! @brief A Controllable system is copy constructable AnimationsSystem(const AnimationsSystem &) = default; //! @brief A default destructor ~AnimationsSystem() override = default; - //! @brief A Controllable system is assignable. - AnimationsSystem &operator=(const AnimationsSystem &) = default; + //! @brief A system is not assignable. + AnimationsSystem &operator=(const AnimationsSystem &) = delete; }; } \ No newline at end of file diff --git a/sources/System/Animator/AnimatorSystem.cpp b/sources/System/Animator/AnimatorSystem.cpp index a9dd38c4..f03aeb9b 100644 --- a/sources/System/Animator/AnimatorSystem.cpp +++ b/sources/System/Animator/AnimatorSystem.cpp @@ -17,30 +17,20 @@ using Key = RAY::Controller::Keyboard::Key; namespace BBM { - AnimatorSystem::AnimatorSystem() - : WAL::System({ - typeid(AnimatorComponent), - typeid(ControllableComponent) - }) + AnimatorSystem::AnimatorSystem(WAL::Wal &wal) + : System(wal) {} - void AnimatorSystem::onFixedUpdate(WAL::Entity &entity) + void AnimatorSystem::onFixedUpdate(WAL::ViewEntity &entity) { - if (!entity.hasComponent()) - return; - const std::vector> moveDiag = {{-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}}; - const std::vector rotationAngle = {0.0f, 45.0f, 90.0f, 135.0f, 180.0f, 225.0f, 270.0f, 315.0f}; - const auto &controllable = entity.getComponent(); - auto drawable = entity.getComponent().drawable.get(); - auto &animation = entity.getComponent(); + const auto &controllable = entity.get(); + auto drawable = entity.get().drawable.get(); + auto &animation = entity.get(); auto anim = dynamic_cast(drawable); - for (int i = 0; i != moveDiag.size(); i++) { - if (controllable.move.x == moveDiag[i][0] && controllable.move.y == moveDiag[i][1]) { - if (anim) - anim->setRotationAngle(rotationAngle[i]); - animation.setAnimIndex(0); - return; - } + if (anim && controllable.move != Vector2f(0, 0)) { + anim->setRotationAngle(controllable.move.angle(Vector2f(-1, 0))); + animation.setAnimIndex(0); + return; } animation.setAnimIndex(1); } diff --git a/sources/System/Animator/AnimatorSystem.hpp b/sources/System/Animator/AnimatorSystem.hpp index 3aae4d6c..fcddfc13 100644 --- a/sources/System/Animator/AnimatorSystem.hpp +++ b/sources/System/Animator/AnimatorSystem.hpp @@ -4,19 +4,21 @@ #pragma once +#include +#include "Component/Animation/AnimationsComponent.hpp" #include "System/System.hpp" namespace BBM { //! @brief A system to handle Animator entities. - class AnimatorSystem : public WAL::System + class AnimatorSystem : public WAL::System { public: //! @inherit - void onFixedUpdate(WAL::Entity &entity) override; + void onFixedUpdate(WAL::ViewEntity &entity) override; //! @brief A default constructor - AnimatorSystem(); + AnimatorSystem(WAL::Wal &wal); //! @brief An Animator system is copy constructable AnimatorSystem(const AnimatorSystem &) = default; //! @brief A default destructor diff --git a/sources/System/Collision/CollisionSystem.cpp b/sources/System/Collision/CollisionSystem.cpp index 24971304..6a3e36cd 100644 --- a/sources/System/Collision/CollisionSystem.cpp +++ b/sources/System/Collision/CollisionSystem.cpp @@ -6,14 +6,13 @@ #include "Component/Position/PositionComponent.hpp" #include "Component/Collision/CollisionComponent.hpp" #include "System/Collision/CollisionSystem.hpp" +#include "Scene/Scene.hpp" namespace BBM { CollisionSystem::CollisionSystem(WAL::Wal &wal) - : WAL::System({typeid(PositionComponent), typeid(CollisionComponent)}), _wal(wal) - { - - } + : System(wal) + { } bool CollisionSystem::collide(Vector3f minA, Vector3f maxA, Vector3f minB, Vector3f maxB) { @@ -24,25 +23,20 @@ namespace BBM return (overlapX && overlapY && overlapZ); } - void CollisionSystem::onFixedUpdate(WAL::Entity &entity) + void CollisionSystem::onFixedUpdate(WAL::ViewEntity &entity) { - auto &posA = entity.getComponent(); - auto &col = entity.getComponent(); + auto &posA = entity.get(); + auto &col = entity.get(); Vector3f position = posA.position; - if (entity.hasComponent(typeid(MovableComponent))) - position += entity.getComponent().getVelocity(); + if (auto *movable = entity->tryGetComponent()) + position += movable->getVelocity(); Vector3f minA = Vector3f::min(position, position + col.bound); Vector3f maxA = Vector3f::max(position, position + col.bound); - for (auto &other : _wal.scene->getEntities()) { - if (&other == &entity) + for (auto &[other, posB, colB] : this->getView()) { + if (other.getUid() == entity->getUid()) continue; - if (!other.hasComponent() || - !other.hasComponent()) - continue; - auto colB = other.getComponent(); - auto posB = other.getComponent().position; - Vector3f minB = Vector3f::min(posB, posB + colB.bound); - Vector3f maxB = Vector3f::max(posB, posB + colB.bound); + Vector3f minB = Vector3f::min(posB.position, posB.position + colB.bound); + Vector3f maxB = Vector3f::max(posB.position, posB.position + colB.bound); if (collide(minA, maxA, minB, maxB)) { col.onCollide(entity, other); colB.onCollided(entity, other); diff --git a/sources/System/Collision/CollisionSystem.hpp b/sources/System/Collision/CollisionSystem.hpp index b3d78b55..2c0f5491 100644 --- a/sources/System/Collision/CollisionSystem.hpp +++ b/sources/System/Collision/CollisionSystem.hpp @@ -9,27 +9,26 @@ #include "Wal.hpp" #include "System/System.hpp" #include "Models/Vector3.hpp" +#include "Component/Collision/CollisionComponent.hpp" +#include "Component/Position/PositionComponent.hpp" namespace BBM { //! @brief A system to handle collisions. - class CollisionSystem : public WAL::System + class CollisionSystem : public WAL::System { - private: - //! @brief reference to the ECS engine to get other entities - WAL::Wal &_wal; public: //! @inherit - void onFixedUpdate(WAL::Entity &entity) override; + void onFixedUpdate(WAL::ViewEntity &entity) override; //! @brief A default constructor - CollisionSystem(WAL::Wal &wal); + explicit CollisionSystem(WAL::Wal &wal); //! @brief A Collision system is copy constructable CollisionSystem(const CollisionSystem &) = default; //! @brief A default destructor ~CollisionSystem() override = default; - //! @brief A Collision system is assignable. - CollisionSystem &operator=(const CollisionSystem &) = default; + //! @brief A system is not assignable. + CollisionSystem &operator=(const CollisionSystem &) = delete; //! @brief check AABB collision static bool collide(Vector3f minA, Vector3f maxA, Vector3f minB, Vector3f maxB); diff --git a/sources/System/Controllable/ControllableSystem.cpp b/sources/System/Controllable/ControllableSystem.cpp index 41c54895..f14c46b3 100644 --- a/sources/System/Controllable/ControllableSystem.cpp +++ b/sources/System/Controllable/ControllableSystem.cpp @@ -10,17 +10,14 @@ namespace BBM { - ControllableSystem::ControllableSystem() - : WAL::System({ - typeid(ControllableComponent), - typeid(MovableComponent) - }) + ControllableSystem::ControllableSystem(WAL::Wal &wal) + : System(wal) {} - void ControllableSystem::onFixedUpdate(WAL::Entity &entity) + void ControllableSystem::onFixedUpdate(WAL::ViewEntity &entity) { - auto &controllable = entity.getComponent(); - auto &movable = entity.getComponent(); + auto &controllable = entity.get(); + auto &movable = entity.get(); Vector2f move = controllable.move.normalized() * ControllableSystem::speed; movable.addForce(Vector3f(move.x, controllable.jump, move.y)); diff --git a/sources/System/Controllable/ControllableSystem.hpp b/sources/System/Controllable/ControllableSystem.hpp index ec6eef9d..25a9e837 100644 --- a/sources/System/Controllable/ControllableSystem.hpp +++ b/sources/System/Controllable/ControllableSystem.hpp @@ -5,27 +5,29 @@ #pragma once +#include "Component/Movable/MovableComponent.hpp" +#include "Component/Controllable/ControllableComponent.hpp" #include "System/System.hpp" namespace BBM { //! @brief A system to handle Controllable entities. - class ControllableSystem : public WAL::System + class ControllableSystem : public WAL::System { public: //! @brief The speed applied to every controllable entities. static constexpr const float speed = .25f; //! @inherit - void onFixedUpdate(WAL::Entity &entity) override; + void onFixedUpdate(WAL::ViewEntity &entity) override; //! @brief A default constructor - ControllableSystem(); + explicit ControllableSystem(WAL::Wal &wal); //! @brief A Controllable system is copy constructable ControllableSystem(const ControllableSystem &) = default; //! @brief A default destructor ~ControllableSystem() override = default; - //! @brief A Controllable system is assignable. - ControllableSystem &operator=(const ControllableSystem &) = default; + //! @brief A system is not assignable. + ControllableSystem &operator=(const ControllableSystem &) = delete; }; } diff --git a/sources/System/Gamepad/GamepadSystem.cpp b/sources/System/Gamepad/GamepadSystem.cpp index 5df6bd96..f6d67d99 100644 --- a/sources/System/Gamepad/GamepadSystem.cpp +++ b/sources/System/Gamepad/GamepadSystem.cpp @@ -13,17 +13,14 @@ using Gamepad = RAY::Controller::GamePad; namespace BBM { - GamepadSystem::GamepadSystem() - : WAL::System({ - typeid(GamepadComponent), - typeid(ControllableComponent) - }) + GamepadSystem::GamepadSystem(WAL::Wal &wal) + : System(wal) {} - void GamepadSystem::onFixedUpdate(WAL::Entity &entity) + void GamepadSystem::onFixedUpdate(WAL::ViewEntity &entity) { - const auto &gamepadComponent = entity.getComponent(); - auto &controllable = entity.getComponent(); + const auto &gamepadComponent = entity.get(); + auto &controllable = entity.get(); Gamepad gamepad(gamepadComponent.getID()); const std::map keyPressedMap = { diff --git a/sources/System/Gamepad/GamepadSystem.hpp b/sources/System/Gamepad/GamepadSystem.hpp index 9c8c705f..61efdd5e 100644 --- a/sources/System/Gamepad/GamepadSystem.hpp +++ b/sources/System/Gamepad/GamepadSystem.hpp @@ -6,23 +6,25 @@ #include "System/System.hpp" #include +#include "Component/Gamepad/GamepadComponent.hpp" +#include "Component/Controllable/ControllableComponent.hpp" namespace BBM { //! @brief A system to handle Gamepad entities. - class GamepadSystem : public WAL::System + class GamepadSystem : public WAL::System { public: //! @inherit - void onFixedUpdate(WAL::Entity &entity) override; + void onFixedUpdate(WAL::ViewEntity &entity) override; //! @brief A default constructor - GamepadSystem(); + explicit GamepadSystem(WAL::Wal &wal); //! @brief A Gamepad system is copy constructable GamepadSystem(const GamepadSystem &) = default; //! @brief A default destructor ~GamepadSystem() override = default; - //! @brief A Gamepad system is assignable. - GamepadSystem &operator=(const GamepadSystem &) = default; + //! @brief A system is not assignable. + GamepadSystem &operator=(const GamepadSystem &) = delete; }; } diff --git a/sources/System/GridCentered/GridCenteredSystem.cpp b/sources/System/GridCentered/GridCenteredSystem.cpp index 5dcca1a9..3c86175b 100644 --- a/sources/System/GridCentered/GridCenteredSystem.cpp +++ b/sources/System/GridCentered/GridCenteredSystem.cpp @@ -8,18 +8,14 @@ namespace BBM { - GridCenteredSystem::GridCenteredSystem() - : WAL::System({ - typeid(GridCenteredComponent), - typeid(MovableComponent), -// typeid(PositionComponent) - }) + GridCenteredSystem::GridCenteredSystem(WAL::Wal &wal) + : System(wal) {} - void GridCenteredSystem::onFixedUpdate(WAL::Entity &entity) + void GridCenteredSystem::onFixedUpdate(WAL::ViewEntity &entity) { - auto &grid = entity.getComponent(); - auto &movement = entity.getComponent(); + auto &grid = entity.get(); + auto &movement = entity.get(); // movement.addForce(grid.force * ) } } \ No newline at end of file diff --git a/sources/System/GridCentered/GridCenteredSystem.hpp b/sources/System/GridCentered/GridCenteredSystem.hpp index e84e65fb..6ab97339 100644 --- a/sources/System/GridCentered/GridCenteredSystem.hpp +++ b/sources/System/GridCentered/GridCenteredSystem.hpp @@ -5,22 +5,23 @@ #pragma once #include +#include "Component/Position/PositionComponent.hpp" namespace BBM { //! @brief The system handling GridCenteredComponent - class GridCenteredSystem : public WAL::System + class GridCenteredSystem : public WAL::System { public: - void onFixedUpdate(WAL::Entity &entity) override; + void onFixedUpdate(WAL::ViewEntity &entity) override; //! @brief A default constructor - GridCenteredSystem(); + explicit GridCenteredSystem(WAL::Wal &wal); //! @brief A GridCenteredSystem is copyable. GridCenteredSystem(const GridCenteredSystem &) = default; //! @brief A default destructor ~GridCenteredSystem() override = default; - //! @brief A GridCenteredSystem is assignable - GridCenteredSystem &operator=(const GridCenteredSystem &) = default; + //! @brief A system is not assignable + GridCenteredSystem &operator=(const GridCenteredSystem &) = delete; }; } diff --git a/sources/System/Health/HealthSystem.cpp b/sources/System/Health/HealthSystem.cpp index 25cabc8e..4419e9e1 100644 --- a/sources/System/Health/HealthSystem.cpp +++ b/sources/System/Health/HealthSystem.cpp @@ -11,15 +11,13 @@ namespace BBM { - HealthSystem::HealthSystem() - : WAL::System({ - typeid(HealthComponent) - }) + HealthSystem::HealthSystem(WAL::Wal &wal) + : System(wal) {} - void HealthSystem::onFixedUpdate(WAL::Entity &entity) + void HealthSystem::onFixedUpdate(WAL::ViewEntity &entity) { - auto &health = entity.getComponent(); + auto &health = entity.get(); if (health.getHealthPoint() == 0) { health.onDeath(entity); diff --git a/sources/System/Health/HealthSystem.hpp b/sources/System/Health/HealthSystem.hpp index 15ca2062..f1cd2397 100644 --- a/sources/System/Health/HealthSystem.hpp +++ b/sources/System/Health/HealthSystem.hpp @@ -5,24 +5,25 @@ #pragma once +#include "Component/Health/HealthComponent.hpp" #include "System/System.hpp" namespace BBM { //! @brief A system to handle Health entities. - class HealthSystem : public WAL::System + class HealthSystem : public WAL::System { public: //! @inherit - void onFixedUpdate(WAL::Entity &entity) override; + void onFixedUpdate(WAL::ViewEntity &entity) override; //! @brief A default constructor - HealthSystem(); + explicit HealthSystem(WAL::Wal &wal); //! @brief A Health system is copy constructable HealthSystem(const HealthSystem &) = default; //! @brief A default destructor ~HealthSystem() override = default; - //! @brief A Health system is assignable. - HealthSystem &operator=(const HealthSystem &) = default; + //! @brief A system is not assignable. + HealthSystem &operator=(const HealthSystem &) = delete; }; } diff --git a/sources/System/Keyboard/KeyboardSystem.cpp b/sources/System/Keyboard/KeyboardSystem.cpp index 13ad9804..ccc207ab 100644 --- a/sources/System/Keyboard/KeyboardSystem.cpp +++ b/sources/System/Keyboard/KeyboardSystem.cpp @@ -3,28 +3,23 @@ // Edited by Benjamin Henry on 2021-05-20. // -#include #include "KeyboardSystem.hpp" #include "Component/Keyboard/KeyboardComponent.hpp" #include "Component/Controllable/ControllableComponent.hpp" -#include "Entity/Entity.hpp" #include "Controllers/Keyboard.hpp" using Keyboard = RAY::Controller::Keyboard; namespace BBM { - KeyboardSystem::KeyboardSystem() - : WAL::System({ - typeid(KeyboardComponent), - typeid(ControllableComponent) - }) + KeyboardSystem::KeyboardSystem(WAL::Wal &wal) + : System(wal) {} - void KeyboardSystem::onFixedUpdate(WAL::Entity &entity) + void KeyboardSystem::onFixedUpdate(WAL::ViewEntity &entity) { - const auto &keyboard = entity.getComponent(); - auto &controllable = entity.getComponent(); + const auto &keyboard = entity.get(); + auto &controllable = entity.get(); const std::map keyPressedMap = { {keyboard.keyJump, controllable.jump}, diff --git a/sources/System/Keyboard/KeyboardSystem.hpp b/sources/System/Keyboard/KeyboardSystem.hpp index f17c5f15..cf7309e1 100644 --- a/sources/System/Keyboard/KeyboardSystem.hpp +++ b/sources/System/Keyboard/KeyboardSystem.hpp @@ -7,23 +7,25 @@ #include "System/System.hpp" #include +#include "Component/Keyboard/KeyboardComponent.hpp" +#include "Component/Controllable/ControllableComponent.hpp" namespace BBM { //! @brief A system to handle keyboard entities. - class KeyboardSystem : public WAL::System + class KeyboardSystem : public WAL::System { public: //! @inherit - void onFixedUpdate(WAL::Entity &entity) override; + void onFixedUpdate(WAL::ViewEntity &entity) override; //! @brief A default constructor - KeyboardSystem(); + explicit KeyboardSystem(WAL::Wal &wal); //! @brief A keyboard system is copy constructable KeyboardSystem(const KeyboardSystem &) = default; //! @brief A default destructor ~KeyboardSystem() override = default; - //! @brief A keyboard system is assignable. - KeyboardSystem &operator=(const KeyboardSystem &) = default; + //! @brief A system is not assignable. + KeyboardSystem &operator=(const KeyboardSystem &) = delete; }; } diff --git a/sources/System/Movable/MovableSystem.cpp b/sources/System/Movable/MovableSystem.cpp index 1c439345..eff5a79a 100644 --- a/sources/System/Movable/MovableSystem.cpp +++ b/sources/System/Movable/MovableSystem.cpp @@ -8,17 +8,14 @@ namespace BBM { - MovableSystem::MovableSystem() - : WAL::System({ - typeid(MovableComponent), - typeid(PositionComponent) - }) + MovableSystem::MovableSystem(WAL::Wal &wal) + : System(wal) {} - void MovableSystem::onFixedUpdate(WAL::Entity &entity) + void MovableSystem::onFixedUpdate(WAL::ViewEntity &entity) { - auto &movable = entity.getComponent(); - auto &position = entity.getComponent(); + auto &movable = entity.get(); + auto &position = entity.get(); position.position += movable._velocity; movable._velocity = movable._acceleration; diff --git a/sources/System/Movable/MovableSystem.hpp b/sources/System/Movable/MovableSystem.hpp index 51a56ea9..e109da13 100644 --- a/sources/System/Movable/MovableSystem.hpp +++ b/sources/System/Movable/MovableSystem.hpp @@ -5,25 +5,27 @@ #pragma once +#include "Component/Movable/MovableComponent.hpp" +#include "Component/Position/PositionComponent.hpp" #include "System/System.hpp" #include "Entity/Entity.hpp" namespace BBM { //! @brief A system to handle movable entities. This system update velocity based on accelerations and positions based on velocity. - class MovableSystem : public WAL::System + class MovableSystem : public WAL::System { public: //! @inherit - void onFixedUpdate(WAL::Entity &entity) override; + void onFixedUpdate(WAL::ViewEntity &entity) override; //! @brief A default constructor - MovableSystem(); + explicit MovableSystem(WAL::Wal &wal); //! @brief A movable system is copy constructable MovableSystem(const MovableSystem &) = default; //! @brief A default destructor ~MovableSystem() override = default; - //! @brief A movable system is assignable. - MovableSystem &operator=(const MovableSystem &) = default; + //! @brief A system is not assignable. + MovableSystem &operator=(const MovableSystem &) = delete; }; } // namespace WAL diff --git a/sources/System/Renderer/RenderSystem.cpp b/sources/System/Renderer/RenderSystem.cpp index 57f99b83..cdabb452 100644 --- a/sources/System/Renderer/RenderSystem.cpp +++ b/sources/System/Renderer/RenderSystem.cpp @@ -8,17 +8,12 @@ #include "Component/Renderer/CameraComponent.hpp" #include "Component/Position/PositionComponent.hpp" #include "Component/Renderer/Drawable2DComponent.hpp" -#include "Drawables/ADrawable2D.hpp" #include "Drawables/ADrawable3D.hpp" namespace BBM { RenderSystem::RenderSystem(WAL::Wal &wal, RAY::Window &window, bool debugMode) - : WAL::System({ - typeid(CameraComponent), - typeid(PositionComponent) - }), - _wal(wal), + : System(wal), _window(window), _camera(Vector3f(), Vector3f(), Vector3f(0, 1, 0), 50, CAMERA_PERSPECTIVE), _debugMode(debugMode) @@ -33,26 +28,14 @@ namespace BBM this->_window.clear(); this->_window.useCamera(this->_camera); - for (auto &entity : this->_wal.scene->getEntities()) { - if (!entity.hasComponent() - || !entity.hasComponent()) - continue; - auto &drawable = entity.getComponent(); - auto &pos = entity.getComponent(); - + for (auto &[_, pos, drawable] : this->_wal.scene->view()) { drawable.drawable->setPosition(pos.position); drawable.drawable->drawOn(this->_window); } this->_window.unuseCamera(); // TODO sort entities based on the Z axis - for (auto &entity : this->_wal.scene->getEntities()) { - if (!entity.hasComponent() - || !entity.hasComponent()) - continue; - auto &drawable = entity.getComponent(); - auto &pos = entity.getComponent(); - + for (auto &[_, pos, drawable] : this->_wal.scene->view()) { drawable.drawable->setPosition(Vector2f(pos.position.x, pos.position.y)); drawable.drawable->drawOn(this->_window); } @@ -61,10 +44,10 @@ namespace BBM this->_window.endDrawing(); } - void RenderSystem::onUpdate(WAL::Entity &entity, std::chrono::nanoseconds dtime) + void RenderSystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) { - const auto &pos = entity.getComponent(); - const auto &cam = entity.getComponent(); + const auto &pos = entity.get(); + const auto &cam = entity.get(); _camera.setPosition(pos.position); _camera.setTarget(cam.target); } diff --git a/sources/System/Renderer/RenderSystem.hpp b/sources/System/Renderer/RenderSystem.hpp index e3852944..e770de02 100644 --- a/sources/System/Renderer/RenderSystem.hpp +++ b/sources/System/Renderer/RenderSystem.hpp @@ -4,6 +4,8 @@ #pragma once +#include "Component/Renderer/CameraComponent.hpp" +#include "Component/Position/PositionComponent.hpp" #include "System/System.hpp" #include "Camera/Camera2D.hpp" #include "Window.hpp" @@ -11,10 +13,8 @@ namespace BBM { - class RenderSystem : public WAL::System + class RenderSystem : public WAL::System { - //! @brief The ECS to update. - WAL::Wal &_wal; //! @brief The window to render on RAY::Window &_window; @@ -34,7 +34,7 @@ namespace BBM void onSelfUpdate() override; //! @inherit - void onUpdate(WAL::Entity &entity, std::chrono::nanoseconds dtime) override; + void onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) override; //! @brief ctor RenderSystem(WAL::Wal &wal, RAY::Window &window, bool debugMode = true); diff --git a/tests/CallbackTest.cpp b/tests/CallbackTest.cpp index 534ca9f4..30d67e76 100644 --- a/tests/CallbackTest.cpp +++ b/tests/CallbackTest.cpp @@ -4,6 +4,8 @@ #include #include +#include +#include #include "Entity/Entity.hpp" #include "Models/Callback.hpp" @@ -36,6 +38,7 @@ TEST_CASE("Callback multiple arguments", "[Callback]") callback.addCallback([](const std::string& str, int a, unsigned *value, Entity &entity) { throw std::runtime_error(""); }); - Entity entity("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 69c75207..394b1ccc 100644 --- a/tests/CollisionTest.cpp +++ b/tests/CollisionTest.cpp @@ -5,12 +5,12 @@ #include #include "Entity/Entity.hpp" #include "Component/Position/PositionComponent.hpp" -#include "Component/Movable/MovableComponent.hpp" -#include "System/Movable/MovableSystem.hpp" -#include "System/Collision/CollisionSystem.hpp" #include "Wal.hpp" #define private public +#include "System/Collision/CollisionSystem.hpp" +#include "System/Movable/MovableSystem.hpp" +#include "Component/Movable/MovableComponent.hpp" #include "Component/Collision/CollisionComponent.hpp" using namespace WAL; @@ -21,7 +21,7 @@ TEST_CASE("Collision test", "[Component][System]") { Wal wal; CollisionSystem collision(wal); - wal.scene = std::shared_ptr(new Scene); + wal.scene = std::make_shared(); wal.scene->addEntity("player") .addComponent() .addComponent([](Entity &actual, const Entity &) { @@ -32,15 +32,15 @@ TEST_CASE("Collision test", "[Component][System]") pos.position.z = 1; } catch (std::exception &e) {}; }, [](Entity &, const Entity &){}, 5.0); - Entity &entity = wal.scene->getEntities()[0]; + Entity &entity = wal.scene->getEntities().front(); REQUIRE(entity.getComponent().position == Vector3f()); entity.getComponent().bound.x = 5; entity.getComponent().bound.y = 5; entity.getComponent().bound.z = 5; - collision.onUpdate(entity, std::chrono::nanoseconds(1)); - collision.onFixedUpdate(entity); + collision.update(std::chrono::nanoseconds(1)); + collision.fixedUpdate(); REQUIRE(entity.getComponent().position.x == 0.0); REQUIRE(entity.getComponent().position.y == 0.0); REQUIRE(entity.getComponent().position.z == 0.0); @@ -48,10 +48,10 @@ TEST_CASE("Collision test", "[Component][System]") wal.scene->addEntity("block") .addComponent(2,2,2) .addComponent(1); - Entity &player = wal.scene->getEntities()[0]; - collision.onUpdate(entity, std::chrono::nanoseconds(1)); + Entity &player = wal.scene->getEntities().front(); + collision.update(std::chrono::nanoseconds(1)); REQUIRE(player.hasComponent(typeid(PositionComponent))); - collision.onFixedUpdate(player); + collision.fixedUpdate(); REQUIRE(wal.scene->getEntities().size() == 2); REQUIRE(player.hasComponent(typeid(PositionComponent))); REQUIRE(player.getComponent().position.x == 1.0); @@ -64,8 +64,8 @@ TEST_CASE("Collsion test with movable", "[Component][System]") { Wal wal; CollisionSystem collision(wal); - MovableSystem movable; - wal.scene = std::shared_ptr(new Scene); + MovableSystem movable(wal); + wal.scene = std::make_shared(); wal.scene->addEntity("player") .addComponent() .addComponent([](Entity &actual, const Entity &) {}, [](Entity &actual, const Entity &) {}, 5.0) @@ -76,10 +76,10 @@ TEST_CASE("Collsion test with movable", "[Component][System]") .addComponent([](Entity &actual, const Entity &){}, [](Entity &actual, const Entity &) { try { auto &mov = actual.getComponent(); - mov.resetVelocity(); + mov._velocity = Vector3f(); } catch (std::exception &e) {}; }, 1); - Entity &entity = wal.scene->getEntities()[0]; + Entity &entity = wal.scene->getEntities().front(); REQUIRE(entity.getComponent().position == Vector3f()); entity.getComponent().bound.x = 5; @@ -87,10 +87,10 @@ TEST_CASE("Collsion test with movable", "[Component][System]") entity.getComponent().bound.z = 5; entity.getComponent().addForce({1, 1, 1}); - collision.onUpdate(entity, std::chrono::nanoseconds(1)); - collision.onFixedUpdate(entity); - movable.onUpdate(entity, std::chrono::nanoseconds(1)); - movable.onFixedUpdate(entity); + collision.update(std::chrono::nanoseconds(1)); + collision.fixedUpdate(); + movable.update(std::chrono::nanoseconds(1)); + movable.fixedUpdate(); REQUIRE(entity.getComponent().position.x == 0.0); REQUIRE(entity.getComponent().position.y == 0.0); REQUIRE(entity.getComponent().position.z == 0.0); diff --git a/tests/EngineTests.cpp b/tests/EngineTests.cpp index 804b6050..9e356adf 100644 --- a/tests/EngineTests.cpp +++ b/tests/EngineTests.cpp @@ -31,7 +31,7 @@ TEST_CASE("Create system", "[Engine][System]") TEST_CASE("Create system by reference", "[Engine][System]") { Wal wal; - MovableSystem system; + MovableSystem system(wal); wal.addSystem(system); REQUIRE_THROWS_AS(wal.addSystem(), DuplicateError); } \ No newline at end of file diff --git a/tests/EntityTests.cpp b/tests/EntityTests.cpp index f58fd0c1..3520f862 100644 --- a/tests/EntityTests.cpp +++ b/tests/EntityTests.cpp @@ -5,13 +5,16 @@ #include "Entity/Entity.hpp" #include "Component/Position/PositionComponent.hpp" #include +#include +#include using namespace WAL; using namespace BBM; TEST_CASE("Component", "[Entity]") { - Entity entity("Bob"); + Scene scene; + Entity entity(scene, "Bob"); entity.addComponent(2, 3, 4); SECTION("Check value") { @@ -31,13 +34,15 @@ TEST_CASE("Component", "[Entity]") TEST_CASE("ComponentNotFound", "[Entity]") { - Entity entity("Bob"); + Scene scene; + Entity entity(scene, "Bob"); REQUIRE_THROWS_AS(entity.getComponent(), NotFoundError); } TEST_CASE("Add component by reference", "[Entity]") { - Entity entity("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 cd37d22a..b19a68fc 100644 --- a/tests/MoveTests.cpp +++ b/tests/MoveTests.cpp @@ -4,13 +4,13 @@ #include "Entity/Entity.hpp" #include "Component/Position/PositionComponent.hpp" -#include "System/Movable/MovableSystem.hpp" -#include "System/Controllable/ControllableSystem.hpp" #include #include -#include #define private public +#include "System/Controllable/ControllableSystem.hpp" +#include "System/Movable/MovableSystem.hpp" +#include #include using namespace WAL; @@ -19,32 +19,33 @@ using namespace BBM; TEST_CASE("Move test", "[Component][System]") { - Scene scene; - scene.addEntity("player") + Wal wal; + wal.scene = std::make_shared(); + wal.scene->addEntity("player") .addComponent() .addComponent() .addComponent(); - Entity &entity = scene.getEntities()[0]; + Entity &entity = wal.scene->getEntities().front(); REQUIRE(entity.getComponent().position == Vector3f()); entity.getComponent().move = Vector2f(1, 1); - ControllableSystem controllable; - controllable.onUpdate(entity, std::chrono::nanoseconds(1)); - controllable.onFixedUpdate(entity); + ControllableSystem controllable(wal); + controllable.update(std::chrono::nanoseconds(1)); + controllable.fixedUpdate(); REQUIRE(entity.getComponent()._acceleration.x > 0); REQUIRE(entity.getComponent()._acceleration.z > 0); - MovableSystem movable; - movable.onUpdate(entity, std::chrono::nanoseconds(1)); - movable.onFixedUpdate(entity); + MovableSystem movable(wal); + movable.update(std::chrono::nanoseconds(1)); + movable.fixedUpdate(); REQUIRE(entity.getComponent()._velocity.x > 0); REQUIRE(entity.getComponent()._velocity.z > 0); REQUIRE(entity.getComponent()._acceleration.x == 0); REQUIRE(entity.getComponent()._acceleration.z == 0); - movable.onUpdate(entity, std::chrono::nanoseconds(1)); - movable.onFixedUpdate(entity); + movable.update(std::chrono::nanoseconds(1)); + movable.fixedUpdate(); REQUIRE(entity.getComponent().position.x > 0); REQUIRE(entity.getComponent().position.z > 0); diff --git a/tests/ViewTest.cpp b/tests/ViewTest.cpp new file mode 100644 index 00000000..569d42ad --- /dev/null +++ b/tests/ViewTest.cpp @@ -0,0 +1,126 @@ +// +// Created by Zoe Roux on 6/3/21. +// + +#include "Entity/Entity.hpp" +#include "Component/Position/PositionComponent.hpp" +#include +#include +#include + +using namespace WAL; +using namespace BBM; + +TEST_CASE("View creation", "[View]") +{ + Scene scene; + scene.addEntity("player") + .addComponent() + .addComponent(); + scene.addEntity("Box") + .addComponent(); + REQUIRE(scene.view().size() == 2); + REQUIRE(scene.view().size() == 1); + Entity &entity = *scene.getEntities().begin(); + Entity &firstView = scene.view().front(); + REQUIRE(&entity == &firstView); +} + +TEST_CASE("View update", "[View]") +{ + Scene scene; + scene.addEntity("player") + .addComponent() + .addComponent(); + auto &view = scene.view(); + auto &entity = scene.addEntity("Box") + .addComponent(); + REQUIRE(view.size() == 2); + entity.removeComponent(); + REQUIRE(view.size() == 1); +} + +TEST_CASE("View cache", "[View]") +{ + Scene scene; + scene.addEntity("player") + .addComponent() + .addComponent(); + auto &view = scene.view(); + REQUIRE(&view == &scene.view()); +} + +TEST_CASE("View cache switch", "[View]") +{ + Scene scene; + scene.addEntity("player") + .addComponent() + .addComponent(); + auto &view = scene.view(); + Scene scene2; + scene2.addEntity("box") + .addComponent(); + + REQUIRE(&view == &scene.view()); + REQUIRE(view.front()->getName() == "player"); + REQUIRE(scene2.view().front()->getName() == "box"); +} + +TEST_CASE("View entity iteration", "[View]") +{ + Scene scene; + scene.addEntity("player") + .addComponent() + .addComponent(); + scene.addEntity("Box") + .addComponent(); + int i = 0; + for (Entity &entity : scene.view()) { + if (i == 0) + REQUIRE(entity.getName() == "player"); + else + REQUIRE(entity.getName() == "Box"); + i++; + } + REQUIRE(i == 2); +} + +TEST_CASE("ViewEntity<> iteration", "[View]") +{ + Scene scene; + scene.addEntity("player") + .addComponent(1, 1, 1) + .addComponent(); + scene.addEntity("Box") + .addComponent(1, 1, 1); + int i = 0; + for (auto entity : scene.view()) { + if (i == 0) + REQUIRE(entity->getName() == "player"); + else + REQUIRE(entity->getName() == "Box"); + REQUIRE(entity.get().position == Vector3f(1, 1, 1)); + i++; + } + REQUIRE(i == 2); +} + +TEST_CASE("View [entity, component] iteration", "[View]") +{ + Scene scene; + scene.addEntity("player") + .addComponent(1, 1, 1) + .addComponent(); + scene.addEntity("Box") + .addComponent(1, 1, 1); + int i = 0; + for (auto &[entity, position] : scene.view()) { + if (i == 0) + REQUIRE(entity.getName() == "player"); + else + REQUIRE(entity.getName() == "Box"); + REQUIRE(position.position == Vector3f(1, 1, 1)); + i++; + } + REQUIRE(i == 2); +} \ No newline at end of file