From 7313a9d4e05defb52d000d7b5aead9eb3b6e1d5e Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Mon, 17 May 2021 16:26:21 +0200 Subject: [PATCH] Creating the game loop --- lib/wal/sources/Entity/Entity.cpp | 13 ++++++-- lib/wal/sources/Entity/Entity.hpp | 13 +++++--- lib/wal/sources/Renderer/Renderer.cpp | 8 +++++ lib/wal/sources/Renderer/Renderer.hpp | 4 ++- lib/wal/sources/Scene/Scene.cpp | 9 ++++++ lib/wal/sources/Scene/Scene.hpp | 3 ++ lib/wal/sources/System/System.hpp | 5 +-- lib/wal/sources/Wal.cpp | 44 +++++++++++++++++++++++++-- lib/wal/sources/Wal.hpp | 9 ++++++ 9 files changed, 95 insertions(+), 13 deletions(-) diff --git a/lib/wal/sources/Entity/Entity.cpp b/lib/wal/sources/Entity/Entity.cpp index 859e2e3e..e5ca8b29 100644 --- a/lib/wal/sources/Entity/Entity.cpp +++ b/lib/wal/sources/Entity/Entity.cpp @@ -46,10 +46,17 @@ namespace WAL Entity &Entity::addComponent(const Component &component) { - // TODO handle duplicates -// if (this->hasComponent()) -// throw DuplicateError("A component of the type \"" + std::string(typeid(T).name()) + "\" already exists."); + 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)); 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(); + } } \ No newline at end of file diff --git a/lib/wal/sources/Entity/Entity.hpp b/lib/wal/sources/Entity/Entity.hpp index 7a501661..b8e2e05e 100644 --- a/lib/wal/sources/Entity/Entity.hpp +++ b/lib/wal/sources/Entity/Entity.hpp @@ -49,19 +49,22 @@ namespace WAL }); if (existing == this->_components.end()) throw NotFoundError("No component could be found with the type \"" + std::string(type.name()) + "\"."); - return *reinterpret_cast(existing->get()); + return *static_cast(existing->get()); } + //! @brief Check if this entity has a component. + //! @tparam T The type of the component template bool hasComponent() const { 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; - }); - return existing != this->_components.end(); + return this->hasComponent(type); } + //! @brief Check if this entity has a component. + //! @param type The type of the component + bool hasComponent(const std::type_info &type) 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. //! @return This entity is returned diff --git a/lib/wal/sources/Renderer/Renderer.cpp b/lib/wal/sources/Renderer/Renderer.cpp index 28b61e34..a77f2515 100644 --- a/lib/wal/sources/Renderer/Renderer.cpp +++ b/lib/wal/sources/Renderer/Renderer.cpp @@ -3,3 +3,11 @@ // #include "Renderer.hpp" + +namespace WAL +{ + void Renderer::render() + { + + } +} \ No newline at end of file diff --git a/lib/wal/sources/Renderer/Renderer.hpp b/lib/wal/sources/Renderer/Renderer.hpp index 697f76ad..af6fbd27 100644 --- a/lib/wal/sources/Renderer/Renderer.hpp +++ b/lib/wal/sources/Renderer/Renderer.hpp @@ -7,8 +7,10 @@ namespace WAL { + //! @brief The renderer class used to display things. class Renderer { - + public: + void render(); }; } diff --git a/lib/wal/sources/Scene/Scene.cpp b/lib/wal/sources/Scene/Scene.cpp index 2158ac61..bde3f639 100644 --- a/lib/wal/sources/Scene/Scene.cpp +++ b/lib/wal/sources/Scene/Scene.cpp @@ -3,3 +3,12 @@ // #include "Scene.hpp" + +namespace WAL +{ + std::vector &Scene::getEntities() + { + return this->_entity; + } +} + diff --git a/lib/wal/sources/Scene/Scene.hpp b/lib/wal/sources/Scene/Scene.hpp index 52a85c4f..29ea2c9a 100644 --- a/lib/wal/sources/Scene/Scene.hpp +++ b/lib/wal/sources/Scene/Scene.hpp @@ -16,5 +16,8 @@ namespace WAL private: //! @brief The list of registered entities std::vector _entity; + public: + //! @brief Get the list of entities. + std::vector &getEntities(); }; } diff --git a/lib/wal/sources/System/System.hpp b/lib/wal/sources/System/System.hpp index 5da1d236..b0cc02d4 100644 --- a/lib/wal/sources/System/System.hpp +++ b/lib/wal/sources/System/System.hpp @@ -2,6 +2,7 @@ #pragma once +#include #include "Entity/Entity.hpp" namespace WAL @@ -16,12 +17,12 @@ namespace WAL System(System &&) = default; //! @brief Get the name of the component corresponding to this system. - virtual std::string getComponentName() const = 0; + virtual std::type_info &getComponent() const = 0; //! @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, float dtime) = 0; + virtual void onUpdate(Entity &entity, std::chrono::nanoseconds dtime) = 0; //! @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. diff --git a/lib/wal/sources/Wal.cpp b/lib/wal/sources/Wal.cpp index b5f62458..0e4921ff 100644 --- a/lib/wal/sources/Wal.cpp +++ b/lib/wal/sources/Wal.cpp @@ -5,8 +5,11 @@ #include #include "Wal.hpp" +using namespace std::chrono_literals; + namespace WAL { + std::chrono::nanoseconds WAL::_timestep = 8ms; SceneManager &WAL::getSceneManger() { @@ -16,12 +19,49 @@ namespace WAL void WAL::run() { auto lastTick = std::chrono::steady_clock::now(); + std::chrono::nanoseconds dtime(0); while (!this->_shouldClose) { auto now = std::chrono::steady_clock::now(); - auto dtime = now - lastTick; + dtime += now - lastTick; lastTick = now; - // see https://gist.github.com/mariobadr/673bbd5545242fcf9482 + + this->_update(dtime); + while (dtime > WAL::_timestep) { + dtime -= WAL::_timestep; + this->_fixedUpdate(); + } + this->_renderer->render(); + } + } + + void WAL::_update(std::chrono::nanoseconds dtime) + { + auto &entities = this->_scenes.getCurrent().getEntities(); + + for (auto &system : this->_systems) { + for (auto &entity : entities) { + auto &cmp = system->getComponent(); + if (!entity.hasComponent(cmp)) + continue; + // TODO handle dependencies. + system->onUpdate(entity, dtime); + } + } + } + + void WAL::_fixedUpdate() + { + auto &entities = this->_scenes.getCurrent().getEntities(); + + for (auto &system : this->_systems) { + for (auto &entity : entities) { + auto &cmp = system->getComponent(); + if (!entity.hasComponent(cmp)) + continue; + // TODO handle dependencies. + system->onFixedUpdate(entity); + } } } } \ No newline at end of file diff --git a/lib/wal/sources/Wal.hpp b/lib/wal/sources/Wal.hpp index 19456fd6..e4c9f291 100644 --- a/lib/wal/sources/Wal.hpp +++ b/lib/wal/sources/Wal.hpp @@ -31,6 +31,15 @@ namespace WAL std::unique_ptr _renderer; //! @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; + + //! @brief Call the onUpdate of every system with every component + void _update(std::chrono::nanoseconds dtime); + + //! @brief Call the onFixedUpdate of every system with every component + void _fixedUpdate(); public: //! @brief Create a new system in place. //! @return The wal instance used to call this function is returned. This allow method chaining.