diff options
author | WBoerenkamps <wrj.boerenkamps@student.avans.nl> | 2024-12-05 00:03:10 +0100 |
---|---|---|
committer | WBoerenkamps <wrj.boerenkamps@student.avans.nl> | 2024-12-05 00:03:10 +0100 |
commit | 8aa43f634c1a89f05681ffc5f3cd0a3477e50e71 (patch) | |
tree | a1321d75328da0952ba7bf294a8036f50debb60f | |
parent | d9e46281c1e24a5f23d779d314e5df87fa3317a3 (diff) | |
parent | cfb67ffddb9f4bb0357c2b9df4239bfee7364c5a (diff) |
added loopTimer to mediator and fixed update loop
60 files changed, 570 insertions, 305 deletions
@@ -17,11 +17,10 @@ GENERATE_LATEX = NO LAYOUT_FILE = src/doc/layout.xml TAB_SIZE = 2 -HTML_INDEX_NUM_ENTRIES = 2 +HTML_INDEX_NUM_ENTRIES = 999 HTML_EXTRA_STYLESHEET = src/doc/style.css SHOW_HEADERFILE = NO -USE_MDFILE_AS_MAINPAGE = ./readme.md REPEAT_BRIEF = NO EXTRACT_STATIC = YES @@ -29,6 +28,7 @@ HIDE_UNDOC_NAMESPACES = YES HIDE_UNDOC_CLASSES = YES QUIET = YES +WARNINGS = NO # set these to NO for user-only docs INTERNAL_DOCS = YES diff --git a/contributing.md b/contributing.md index b0f623b..7dedaa7 100644 --- a/contributing.md +++ b/contributing.md @@ -635,15 +635,21 @@ that you can click on to open them. </summary><table><tr><th>Good</th><th>Bad</th></tr><tr><td> ```cpp + void Foo::bar() { } + void Foo::set_value(int value) { this->value = value; + this->bar(); } ``` </td><td> ```cpp + void Foo::bar() { } + void Foo::set_value(int new_value) { value = new_value; + bar(); } ``` </td></tr></table></details> @@ -868,6 +874,8 @@ that you can click on to open them. # Documentation +[Doxygen commands](https://www.doxygen.nl/manual/commands.html) + - All documentation is written in U.S. English - <details><summary> Doxygen commands are used with a backslash instead of an at-sign. @@ -953,6 +961,52 @@ that you can click on to open them. Foo & operator=(Foo &&) = delete; ``` </td></tr></table></details> +- Do not use markdown headings in Doxygen + +## Documenting features + +Engine features are small 'building blocks' that the user (game developer) may +reference when building a game with the engine. Features do not necessarily map +1-1 to engine components or systems. If a component or system has a single, +distinct feature it should be named after that feature, not the component or +system itself. + +The sources for these pages are located under `src/doc/feature/`, and have the +following format: + +- A feature description which explains— + - the purpose and function of the feature (focus on what it enables or + achieves for the user) + - additional information about when to implement the feature, such as specific + use cases or scenarios +- A list of 'see also' references to relevant classes and/or types +- A **minimal** example to demonstrate how the feature is used. The example + should be written such that the following is clear to the reader: + - Which headers need to be included to utilize the feature + - *Why* the example works, not what is happening in the example + - Where is this code supposed to be called (e.g. inside scene/script + functions) + - Which restrictions should be kept in mind (e.g. copy/move semantics, max + component instances, speed considerations) + +Features should be documented as clear and concise as possible, so the following +points should be kept in mind: + +- <details><summary> + If a page expands on an example from another page, directly reference the + other page using a cross-reference (`\ref`) in a `\note` block at the top of + the page. + </summary> + + ``` + \note This page builds on top of the example shown in \ref feature_script + ``` + </details> +- When explaining the usage of specific functions, qualify them such that + Doxygen is able to add a cross-reference or manually add a reference using the + `\ref` command. +- Users will likely copy-paste examples as-is, so do this yourself to check if + the example code actually works! # Libraries @@ -960,4 +1014,6 @@ that you can click on to open them. subdirectory - When adding new submodules, please set the `shallow` option to `true` in the [.gitmodules](./.gitmodules) file +- When adding new libraries, please update the library version table in + [readme\.md](./readme.md) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c3f29da..97b21f0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -40,5 +40,6 @@ install( target_link_libraries(test_main PRIVATE gtest + PRIVATE gmock PUBLIC crepe ) diff --git a/src/crepe/CMakeLists.txt b/src/crepe/CMakeLists.txt index 7e176e7..da9d492 100644 --- a/src/crepe/CMakeLists.txt +++ b/src/crepe/CMakeLists.txt @@ -1,13 +1,10 @@ target_sources(crepe PUBLIC Particle.cpp - ComponentManager.cpp Component.cpp Collider.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES - ComponentManager.h - ComponentManager.hpp Component.h Collider.h ValueBroker.h @@ -16,6 +13,7 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES add_subdirectory(api) add_subdirectory(facade) +add_subdirectory(manager) add_subdirectory(system) add_subdirectory(util) diff --git a/src/crepe/api/BehaviorScript.cpp b/src/crepe/api/BehaviorScript.cpp index 7bbace0..d22afdf 100644 --- a/src/crepe/api/BehaviorScript.cpp +++ b/src/crepe/api/BehaviorScript.cpp @@ -4,12 +4,12 @@ using namespace crepe; -BehaviorScript::BehaviorScript(game_object_id_t id, ComponentManager & mgr) +BehaviorScript::BehaviorScript(game_object_id_t id, Mediator & mediator) : Component(id), - component_manager(mgr) {} + mediator(mediator) {} template <> BehaviorScript & GameObject::add_component<BehaviorScript>() { ComponentManager & mgr = this->component_manager; - return mgr.add_component<BehaviorScript>(this->id, mgr); + return mgr.add_component<BehaviorScript>(this->id, mgr.mediator); } diff --git a/src/crepe/api/BehaviorScript.h b/src/crepe/api/BehaviorScript.h index d556fe5..3909b96 100644 --- a/src/crepe/api/BehaviorScript.h +++ b/src/crepe/api/BehaviorScript.h @@ -23,14 +23,13 @@ class BehaviorScript : public Component { protected: /** * \param id Parent \c GameObject id - * \param component_manager Reference to component manager (passed through to \c Script - * instance) + * \param mediator Mediator reference * * \note Calls to this constructor (should) always pass through \c GameObject::add_component, * which has an exception for this specific component type. This was done so the user does * not have to pass references used within \c Script to each \c BehaviorScript instance. */ - BehaviorScript(game_object_id_t id, ComponentManager & component_manager); + BehaviorScript(game_object_id_t id, Mediator & mediator); //! Only ComponentManager is allowed to instantiate BehaviorScript friend class ComponentManager; @@ -55,8 +54,8 @@ protected: friend class ScriptSystem; protected: - //! Reference to component manager (passed to Script) - ComponentManager & component_manager; + //! Reference mediator + Mediator & mediator; }; /** diff --git a/src/crepe/api/BehaviorScript.hpp b/src/crepe/api/BehaviorScript.hpp index bd59337..b9bb1e2 100644 --- a/src/crepe/api/BehaviorScript.hpp +++ b/src/crepe/api/BehaviorScript.hpp @@ -13,14 +13,12 @@ template <class T, typename... Args> BehaviorScript & BehaviorScript::set_script(Args &&... args) { dbg_trace(); static_assert(std::is_base_of<Script, T>::value); - Script * s = new T(std::forward<Args>(args)...); + this->script = std::unique_ptr<Script>(new T(std::forward<Args>(args)...)); - s->game_object_id = this->game_object_id; - s->active = this->active; - s->component_manager = this->component_manager; - s->event_manager = EventManager::get_instance(); + this->script->game_object_id = this->game_object_id; + this->script->active = this->active; + this->script->mediator = this->mediator; - this->script = std::unique_ptr<Script>(s); return *this; } diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index 50c51ed..7da9dca 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -9,13 +9,10 @@ target_sources(crepe PUBLIC Texture.cpp AssetManager.cpp Sprite.cpp - SaveManager.cpp Config.cpp Metadata.cpp - SceneManager.cpp Camera.cpp Animator.cpp - EventManager.cpp IKeyListener.cpp IMouseListener.cpp LoopManager.cpp @@ -41,15 +38,10 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES Texture.h AssetManager.h AssetManager.hpp - SaveManager.h Scene.h Metadata.h - SceneManager.h - SceneManager.hpp Camera.h Animator.h - EventManager.h - EventManager.hpp EventHandler.h EventHandler.hpp Event.h diff --git a/src/crepe/api/GameObject.hpp b/src/crepe/api/GameObject.hpp index 17b17d7..a6b45b0 100644 --- a/src/crepe/api/GameObject.hpp +++ b/src/crepe/api/GameObject.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../ComponentManager.h" +#include "../manager/ComponentManager.h" #include "GameObject.h" diff --git a/src/crepe/api/IKeyListener.h b/src/crepe/api/IKeyListener.h index 328a4c2..6ded107 100644 --- a/src/crepe/api/IKeyListener.h +++ b/src/crepe/api/IKeyListener.h @@ -1,8 +1,9 @@ #pragma once +#include "../manager/EventManager.h" + #include "Event.h" #include "EventHandler.h" -#include "EventManager.h" namespace crepe { diff --git a/src/crepe/api/IMouseListener.h b/src/crepe/api/IMouseListener.h index 15e1619..9e4fdf7 100644 --- a/src/crepe/api/IMouseListener.h +++ b/src/crepe/api/IMouseListener.h @@ -1,8 +1,9 @@ #pragma once +#include "../manager/EventManager.h" + #include "Event.h" #include "EventHandler.h" -#include "EventManager.h" namespace crepe { diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index 9bedbcc..040cb93 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -1,22 +1,19 @@ -#include <iostream> - #include "../facade/SDLContext.h" + #include "../system/AnimatorSystem.h" #include "../system/CollisionSystem.h" #include "../system/ParticleSystem.h" #include "../system/PhysicsSystem.h" #include "../system/RenderSystem.h" #include "../system/ScriptSystem.h" +#include "../manager/EventManager.h" -#include "../api/EventManager.h" #include "LoopManager.h" -#include "LoopTimer.h" using namespace crepe; using namespace std; LoopManager::LoopManager() { - this->loop_timer = make_unique<LoopTimer>(); this->load_system<AnimatorSystem>(); this->load_system<CollisionSystem>(); this->load_system<ParticleSystem>(); @@ -26,12 +23,11 @@ LoopManager::LoopManager() { EventManager::get_instance().subscribe<ShutDownEvent>([this](const ShutDownEvent& event) { return this->on_shutdown(event); }); - + this->loop_timer = make_unique<LoopTimer>(); + this->mediator.loop_timer = *loop_timer; } -void LoopManager::process_input() { - SDLContext::get_instance().handle_events(this->game_running); -} +void LoopManager::process_input() { this->sdl_context.handle_events(this->game_running); } void LoopManager::start() { this->setup(); @@ -59,15 +55,17 @@ void LoopManager::loop() { } void LoopManager::setup() { + + this->game_running = true; this->loop_timer->start(); - this->loop_timer->set_target_fps(60); + this->loop_timer->set_target_fps(200); } void LoopManager::render() { - if (this->game_running) { - this->get_system<RenderSystem>().update(); - } + if (!this->game_running) return; + + this->get_system<RenderSystem>().update(); } bool LoopManager::on_shutdown(const ShutDownEvent & e){ this->game_running = false; diff --git a/src/crepe/api/LoopManager.h b/src/crepe/api/LoopManager.h index eb2b525..17bddd1 100644 --- a/src/crepe/api/LoopManager.h +++ b/src/crepe/api/LoopManager.h @@ -2,9 +2,12 @@ #include <memory> -#include "../ComponentManager.h" +#include "../facade/SDLContext.h" +#include "../manager/ComponentManager.h" +#include "../manager/SceneManager.h" #include "../system/System.h" -#include "api/SceneManager.h" +#include "manager/SceneManager.h" + #include "api/Event.h" #include "api/LoopTimer.h" @@ -84,14 +87,20 @@ private: bool game_running = false; private: + //! Global context + Mediator mediator; + //! Component manager instance - ComponentManager component_manager{}; + ComponentManager component_manager{mediator}; //! Scene manager instance - SceneManager scene_manager{component_manager}; + SceneManager scene_manager{mediator}; -private: + //! SDL context \todo no more singletons! + SDLContext & sdl_context = SDLContext::get_instance(); //! loop timer instance std::unique_ptr<LoopTimer> loop_timer; +private: + //! callback function for shutdown event bool on_shutdown(const ShutDownEvent & e); /** diff --git a/src/crepe/api/LoopManager.hpp b/src/crepe/api/LoopManager.hpp index 9cf470b..266758a 100644 --- a/src/crepe/api/LoopManager.hpp +++ b/src/crepe/api/LoopManager.hpp @@ -38,8 +38,11 @@ void LoopManager::load_system() { static_assert(is_base_of<System, T>::value, "load_system must recieve a derivative class of System"); - System * system = new T(this->component_manager); - this->systems[typeid(T)] = unique_ptr<System>(system); + const type_info & type = typeid(T); + if (this->systems.contains(type)) + throw runtime_error(format("LoopManager: {} is already initialized", type.name())); + System * system = new T(this->mediator); + this->systems[type] = unique_ptr<System>(system); } } // namespace crepe diff --git a/src/crepe/api/LoopTimer.cpp b/src/crepe/api/LoopTimer.cpp index 15011ca..07f0f75 100644 --- a/src/crepe/api/LoopTimer.cpp +++ b/src/crepe/api/LoopTimer.cpp @@ -13,8 +13,10 @@ LoopTimer::LoopTimer() { dbg_trace(); } void LoopTimer::start() { this->last_frame_time = std::chrono::steady_clock::now(); + this->elapsed_time = std::chrono::milliseconds(0); - this->elapsed_fixed_time = std::chrono::milliseconds(0); + // by starting the elapsed_fixed_time at (0 - fixed_delta_time) in milliseconds it calls a fixed update at the start of the loop. + this->elapsed_fixed_time = -std::chrono::duration_cast<std::chrono::milliseconds>(fixed_delta_time); this->delta_time = std::chrono::milliseconds(0); } diff --git a/src/crepe/api/Scene.h b/src/crepe/api/Scene.h index f6fdb2a..9f1e8ce 100644 --- a/src/crepe/api/Scene.h +++ b/src/crepe/api/Scene.h @@ -2,6 +2,7 @@ #include <string> +#include "../manager/Mediator.h" #include "../util/OptionalRef.h" namespace crepe { @@ -34,6 +35,9 @@ public: */ virtual std::string get_name() const = 0; + // TODO: Late references should ALWAYS be private! This is currently kept as-is so unit tests + // keep passing, but this reference should not be directly accessible by the user!!! + protected: /** * \name Late references @@ -46,8 +50,8 @@ protected: * * \{ */ - //! Reference to the ComponentManager - OptionalRef<ComponentManager> component_manager; + //! Mediator reference + OptionalRef<Mediator> mediator; //! \} }; diff --git a/src/crepe/api/Script.cpp b/src/crepe/api/Script.cpp index fcbe4c7..4091fd4 100644 --- a/src/crepe/api/Script.cpp +++ b/src/crepe/api/Script.cpp @@ -1,11 +1,17 @@ +#include <string> + +#include "../manager/SceneManager.h" + #include "Script.h" using namespace crepe; +using namespace std; Script::~Script() { - EventManager & evmgr = this->event_manager; + Mediator & mediator = this->mediator; + EventManager & mgr = mediator.event_manager; for (auto id : this->listeners) { - evmgr.unsubscribe(id); + mgr.unsubscribe(id); } } @@ -13,3 +19,9 @@ template <> void Script::subscribe(const EventHandler<CollisionEvent> & callback) { this->subscribe_internal(callback, this->game_object_id); } + +void Script::set_next_scene(const string & name) { + Mediator & mediator = this->mediator; + SceneManager & mgr = mediator.scene_manager; + mgr.set_next_scene(name); +} diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index a0870cb..1b339b0 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -2,11 +2,11 @@ #include <vector> +#include "../manager/EventManager.h" +#include "../manager/Mediator.h" #include "../types.h" #include "../util/OptionalRef.h" -#include "EventManager.h" - namespace crepe { class ScriptSystem; @@ -106,6 +106,12 @@ protected: template <typename EventType> void subscribe(const EventHandler<EventType> & callback); + /** + * \brief Set the next scene using SceneManager + * \see SceneManager::set_next_scene + */ + void set_next_scene(const std::string & name); + //! \} private: @@ -160,10 +166,8 @@ private: game_object_id_t game_object_id; //! Reference to parent component OptionalRef<bool> active; - //! Reference to component manager instance - OptionalRef<ComponentManager> component_manager; - //! Reference to event manager instance - OptionalRef<EventManager> event_manager; + //! Mediator reference + OptionalRef<Mediator> mediator; //! \} private: diff --git a/src/crepe/api/Script.hpp b/src/crepe/api/Script.hpp index a2463bf..45f1ff1 100644 --- a/src/crepe/api/Script.hpp +++ b/src/crepe/api/Script.hpp @@ -1,6 +1,6 @@ #pragma once -#include "../ComponentManager.h" +#include "../manager/ComponentManager.h" #include "BehaviorScript.h" #include "Script.h" @@ -20,7 +20,8 @@ T & Script::get_component() const { template <typename T> RefVector<T> Script::get_components() const { - ComponentManager & mgr = this->component_manager; + Mediator & mediator = this->mediator; + ComponentManager & mgr = mediator.component_manager; return mgr.get_components_by_id<T>(this->game_object_id); } @@ -33,7 +34,8 @@ void Script::logf(Args &&... args) { template <typename EventType> void Script::subscribe_internal(const EventHandler<EventType> & callback, event_channel_t channel) { - EventManager & mgr = this->event_manager; + Mediator & mediator = this->mediator; + EventManager & mgr = mediator.event_manager; subscription_t listener = mgr.subscribe<EventType>( [this, callback](const EventType & data) -> bool { bool & active = this->active; diff --git a/src/crepe/manager/CMakeLists.txt b/src/crepe/manager/CMakeLists.txt new file mode 100644 index 0000000..517b8a2 --- /dev/null +++ b/src/crepe/manager/CMakeLists.txt @@ -0,0 +1,20 @@ +target_sources(crepe PUBLIC + ComponentManager.cpp + EventManager.cpp + Manager.cpp + SaveManager.cpp + SceneManager.cpp +) + +target_sources(crepe PUBLIC FILE_SET HEADERS FILES + ComponentManager.h + ComponentManager.hpp + EventManager.h + EventManager.hpp + Manager.h + Mediator.h + SaveManager.h + SceneManager.h + SceneManager.hpp +) + diff --git a/src/crepe/ComponentManager.cpp b/src/crepe/manager/ComponentManager.cpp index 5b73009..80cf8b4 100644 --- a/src/crepe/ComponentManager.cpp +++ b/src/crepe/manager/ComponentManager.cpp @@ -1,13 +1,16 @@ -#include "api/GameObject.h" -#include "util/Log.h" +#include "../api/GameObject.h" +#include "../types.h" +#include "../util/Log.h" #include "ComponentManager.h" -#include "types.h" using namespace crepe; using namespace std; -ComponentManager::ComponentManager() { dbg_trace(); } +ComponentManager::ComponentManager(Mediator & mediator) : Manager(mediator) { + mediator.component_manager = *this; + dbg_trace(); +} ComponentManager::~ComponentManager() { dbg_trace(); } void ComponentManager::delete_all_components_of_id(game_object_id_t id) { diff --git a/src/crepe/ComponentManager.h b/src/crepe/manager/ComponentManager.h index 480124f..ad37586 100644 --- a/src/crepe/ComponentManager.h +++ b/src/crepe/manager/ComponentManager.h @@ -5,8 +5,10 @@ #include <unordered_map> #include <vector> -#include "Component.h" -#include "types.h" +#include "../Component.h" +#include "../types.h" + +#include "Manager.h" namespace crepe { @@ -17,7 +19,7 @@ class GameObject; * * This class manages all components. It provides methods to add, delete and get components. */ -class ComponentManager { +class ComponentManager : public Manager { // TODO: This relation should be removed! I (loek) believe that the scene manager should // create/destroy components because the GameObject's are stored in concrete Scene classes, // which will in turn call GameObject's destructor, which will in turn call @@ -26,7 +28,7 @@ class ComponentManager { friend class SceneManager; public: - ComponentManager(); // dbg_trace + ComponentManager(Mediator & mediator); ~ComponentManager(); // dbg_trace /** diff --git a/src/crepe/ComponentManager.hpp b/src/crepe/manager/ComponentManager.hpp index ffb38ec..ffb38ec 100644 --- a/src/crepe/ComponentManager.hpp +++ b/src/crepe/manager/ComponentManager.hpp diff --git a/src/crepe/api/EventManager.cpp b/src/crepe/manager/EventManager.cpp index 20f0dd3..20f0dd3 100644 --- a/src/crepe/api/EventManager.cpp +++ b/src/crepe/manager/EventManager.cpp diff --git a/src/crepe/api/EventManager.h b/src/crepe/manager/EventManager.h index 1a33023..d634f54 100644 --- a/src/crepe/api/EventManager.h +++ b/src/crepe/manager/EventManager.h @@ -5,8 +5,8 @@ #include <unordered_map> #include <vector> -#include "Event.h" -#include "EventHandler.h" +#include "../api/Event.h" +#include "../api/EventHandler.h" namespace crepe { diff --git a/src/crepe/api/EventManager.hpp b/src/crepe/manager/EventManager.hpp index a5f4556..a5f4556 100644 --- a/src/crepe/api/EventManager.hpp +++ b/src/crepe/manager/EventManager.hpp diff --git a/src/crepe/manager/Manager.cpp b/src/crepe/manager/Manager.cpp new file mode 100644 index 0000000..1182785 --- /dev/null +++ b/src/crepe/manager/Manager.cpp @@ -0,0 +1,5 @@ +#include "Manager.h" + +using namespace crepe; + +Manager::Manager(Mediator & mediator) : mediator(mediator) {} diff --git a/src/crepe/manager/Manager.h b/src/crepe/manager/Manager.h new file mode 100644 index 0000000..84d80fe --- /dev/null +++ b/src/crepe/manager/Manager.h @@ -0,0 +1,24 @@ +#pragma once + +#include "Mediator.h" + +namespace crepe { + +/** + * \brief Base manager class + * + * Managers are used for various tasks that fall outside the ECS system category. All managers + * are required to register themselves to the mediator passed to the constructor, and this + * mutable reference is saved for convenience, even though not all managers use the mediator + * directly. + */ +class Manager { +public: + Manager(Mediator & mediator); + virtual ~Manager() = default; + +protected: + Mediator & mediator; +}; + +} // namespace crepe diff --git a/src/crepe/manager/Mediator.h b/src/crepe/manager/Mediator.h new file mode 100644 index 0000000..cd96614 --- /dev/null +++ b/src/crepe/manager/Mediator.h @@ -0,0 +1,34 @@ +#pragma once + +#include "../util/OptionalRef.h" + +// TODO: remove these singletons: +#include "EventManager.h" +#include "SaveManager.h" + +namespace crepe { + +class ComponentManager; +class SceneManager; +class LoopTimer; +/** + * Struct to pass references to classes that would otherwise need to be singletons down to + * other classes within the engine hierarchy. Made to prevent constant changes to subclasses to + * pass specific references through dependency injection. All references on this struct + * *should* be explicitly checked for availability as this struct does not guarantee anything. + * + * \note Dereferencing members of this struct should be deferred. If you are a user of this + * class, keep a reference to this mediator instead of just picking references from it when you + * receive an instance. + * + * \warning This class should never be directly accessible from the API + */ +struct Mediator { + OptionalRef<ComponentManager> component_manager; + OptionalRef<SceneManager> scene_manager; + OptionalRef<SaveManager> save_manager = SaveManager::get_instance(); + OptionalRef<EventManager> event_manager = EventManager::get_instance(); + OptionalRef<LoopTimer> loop_timer; +}; + +} // namespace crepe diff --git a/src/crepe/api/SaveManager.cpp b/src/crepe/manager/SaveManager.cpp index c5f43ea..d4ed1c1 100644 --- a/src/crepe/api/SaveManager.cpp +++ b/src/crepe/manager/SaveManager.cpp @@ -1,9 +1,9 @@ +#include "../ValueBroker.h" +#include "../api/Config.h" #include "../facade/DB.h" #include "../util/Log.h" -#include "Config.h" #include "SaveManager.h" -#include "ValueBroker.h" using namespace std; using namespace crepe; diff --git a/src/crepe/api/SaveManager.h b/src/crepe/manager/SaveManager.h index 3d8c852..3d8c852 100644 --- a/src/crepe/api/SaveManager.h +++ b/src/crepe/manager/SaveManager.h diff --git a/src/crepe/api/SceneManager.cpp b/src/crepe/manager/SceneManager.cpp index 1f783ad..50a9fbb 100644 --- a/src/crepe/api/SceneManager.cpp +++ b/src/crepe/manager/SceneManager.cpp @@ -1,14 +1,15 @@ #include <algorithm> #include <memory> -#include "../ComponentManager.h" - +#include "ComponentManager.h" #include "SceneManager.h" using namespace crepe; using namespace std; -SceneManager::SceneManager(ComponentManager & mgr) : component_manager(mgr) {} +SceneManager::SceneManager(Mediator & mediator) : Manager(mediator) { + mediator.scene_manager = *this; +} void SceneManager::set_next_scene(const string & name) { next_scene = name; } @@ -26,7 +27,7 @@ void SceneManager::load_next_scene() { unique_ptr<Scene> & scene = *it; // Delete all components of the current scene - ComponentManager & mgr = this->component_manager; + ComponentManager & mgr = this->mediator.component_manager; mgr.delete_all_components(); // Load the new scene diff --git a/src/crepe/api/SceneManager.h b/src/crepe/manager/SceneManager.h index f6f62cd..e0955c2 100644 --- a/src/crepe/api/SceneManager.h +++ b/src/crepe/manager/SceneManager.h @@ -3,7 +3,9 @@ #include <memory> #include <vector> -#include "Scene.h" +#include "../api/Scene.h" + +#include "Manager.h" namespace crepe { @@ -15,10 +17,9 @@ class ComponentManager; * This class manages scenes. It can add new scenes and load them. It also manages the current scene * and the next scene. */ -class SceneManager { +class SceneManager : public Manager { public: - //! \param mgr Reference to the ComponentManager - SceneManager(ComponentManager & mgr); + SceneManager(Mediator & mediator); public: /** @@ -44,8 +45,6 @@ private: std::vector<std::unique_ptr<Scene>> scenes; //! Next scene to load std::string next_scene; - //! Reference to the ComponentManager - ComponentManager & component_manager; }; } // namespace crepe diff --git a/src/crepe/api/SceneManager.hpp b/src/crepe/manager/SceneManager.hpp index 5c8e417..dff4e51 100644 --- a/src/crepe/api/SceneManager.hpp +++ b/src/crepe/manager/SceneManager.hpp @@ -12,7 +12,7 @@ void SceneManager::add_scene(Args &&... args) { Scene * scene = new T(std::forward<Args>(args)...); unique_ptr<Scene> unique_scene(scene); - unique_scene->component_manager = this->component_manager; + unique_scene->mediator = this->mediator; this->scenes.emplace_back(std::move(unique_scene)); diff --git a/src/crepe/system/AnimatorSystem.cpp b/src/crepe/system/AnimatorSystem.cpp index 4c40940..8bb6465 100644 --- a/src/crepe/system/AnimatorSystem.cpp +++ b/src/crepe/system/AnimatorSystem.cpp @@ -1,15 +1,15 @@ #include <cstdint> -#include "api/Animator.h" -#include "facade/SDLContext.h" +#include "../api/Animator.h" +#include "../facade/SDLContext.h" +#include "../manager/ComponentManager.h" #include "AnimatorSystem.h" -#include "ComponentManager.h" using namespace crepe; void AnimatorSystem::update() { - ComponentManager & mgr = this->component_manager; + ComponentManager & mgr = this->mediator.component_manager; RefVector<Animator> animations = mgr.get_components_by_type<Animator>(); diff --git a/src/crepe/system/ParticleSystem.cpp b/src/crepe/system/ParticleSystem.cpp index 0e62a57..b14c52f 100644 --- a/src/crepe/system/ParticleSystem.cpp +++ b/src/crepe/system/ParticleSystem.cpp @@ -2,17 +2,17 @@ #include <cstdlib> #include <ctime> -#include "api/ParticleEmitter.h" -#include "api/Transform.h" +#include "../api/ParticleEmitter.h" +#include "../api/Transform.h" +#include "../manager/ComponentManager.h" -#include "ComponentManager.h" #include "ParticleSystem.h" using namespace crepe; void ParticleSystem::update() { // Get all emitters - ComponentManager & mgr = this->component_manager; + ComponentManager & mgr = this->mediator.component_manager; RefVector<ParticleEmitter> emitters = mgr.get_components_by_type<ParticleEmitter>(); for (ParticleEmitter & emitter : emitters) { diff --git a/src/crepe/system/PhysicsSystem.cpp b/src/crepe/system/PhysicsSystem.cpp index 514a4b3..bebcf3d 100644 --- a/src/crepe/system/PhysicsSystem.cpp +++ b/src/crepe/system/PhysicsSystem.cpp @@ -1,17 +1,17 @@ #include <cmath> -#include "../ComponentManager.h" #include "../api/Config.h" #include "../api/Rigidbody.h" #include "../api/Transform.h" #include "../api/Vector2.h" +#include "../manager/ComponentManager.h" #include "PhysicsSystem.h" using namespace crepe; void PhysicsSystem::update() { - ComponentManager & mgr = this->component_manager; + ComponentManager & mgr = this->mediator.component_manager; RefVector<Rigidbody> rigidbodies = mgr.get_components_by_type<Rigidbody>(); RefVector<Transform> transforms = mgr.get_components_by_type<Transform>(); diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp index 11c9669..92dba43 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -5,12 +5,12 @@ #include <stdexcept> #include <vector> -#include "../ComponentManager.h" #include "../api/Camera.h" #include "../api/ParticleEmitter.h" #include "../api/Sprite.h" #include "../api/Transform.h" #include "../facade/SDLContext.h" +#include "../manager/ComponentManager.h" #include "RenderSystem.h" @@ -22,7 +22,7 @@ void RenderSystem::clear_screen() { this->context.clear_screen(); } void RenderSystem::present_screen() { this->context.present_screen(); } const Camera & RenderSystem::update_camera() { - ComponentManager & mgr = this->component_manager; + ComponentManager & mgr = this->mediator.component_manager; RefVector<Camera> cameras = mgr.get_components_by_type<Camera>(); @@ -62,7 +62,7 @@ void RenderSystem::update() { bool RenderSystem::render_particle(const Sprite & sprite, const Camera & cam, const double & scale) { - ComponentManager & mgr = this->component_manager; + ComponentManager & mgr = this->mediator.component_manager; vector<reference_wrapper<ParticleEmitter>> emitters = mgr.get_components_by_id<ParticleEmitter>(sprite.game_object_id); @@ -102,7 +102,7 @@ void RenderSystem::render_normal(const Sprite & sprite, const Camera & cam, } void RenderSystem::render() { - ComponentManager & mgr = this->component_manager; + ComponentManager & mgr = this->mediator.component_manager; const Camera & cam = this->update_camera(); RefVector<Sprite> sprites = mgr.get_components_by_type<Sprite>(); diff --git a/src/crepe/system/ScriptSystem.cpp b/src/crepe/system/ScriptSystem.cpp index 20a83f7..d6b2ca1 100644 --- a/src/crepe/system/ScriptSystem.cpp +++ b/src/crepe/system/ScriptSystem.cpp @@ -1,6 +1,6 @@ -#include "../ComponentManager.h" #include "../api/BehaviorScript.h" #include "../api/Script.h" +#include "../manager/ComponentManager.h" #include "ScriptSystem.h" @@ -10,7 +10,7 @@ using namespace crepe; void ScriptSystem::update() { dbg_trace(); - ComponentManager & mgr = this->component_manager; + ComponentManager & mgr = this->mediator.component_manager; RefVector<BehaviorScript> behavior_scripts = mgr.get_components_by_type<BehaviorScript>(); for (BehaviorScript & behavior_script : behavior_scripts) { diff --git a/src/crepe/system/System.cpp b/src/crepe/system/System.cpp index 937a423..f68549b 100644 --- a/src/crepe/system/System.cpp +++ b/src/crepe/system/System.cpp @@ -4,4 +4,4 @@ using namespace crepe; -System::System(ComponentManager & mgr) : component_manager(mgr) { dbg_trace(); } +System::System(const Mediator & mediator) : mediator(mediator) { dbg_trace(); } diff --git a/src/crepe/system/System.h b/src/crepe/system/System.h index 28ea20e..063dfbf 100644 --- a/src/crepe/system/System.h +++ b/src/crepe/system/System.h @@ -1,5 +1,7 @@ #pragma once +#include "../manager/Mediator.h" + namespace crepe { class ComponentManager; @@ -7,9 +9,8 @@ class ComponentManager; /** * \brief Base ECS system class * - * This class is used as the base for all system classes. Classes derived from - * System must implement the System::update() method and copy Script::Script - * with the `using`-syntax. + * This class is used as the base for all system classes. Classes derived from System must + * implement the System::update() method and copy Script::Script with the `using`-syntax. */ class System { public: @@ -19,11 +20,11 @@ public: virtual void update() = 0; public: - System(ComponentManager &); + System(const Mediator & m); virtual ~System() = default; protected: - ComponentManager & component_manager; + const Mediator & mediator; }; } // namespace crepe diff --git a/src/doc/features.dox b/src/doc/features.dox index 96b7c6c..21a040a 100644 --- a/src/doc/features.dox +++ b/src/doc/features.dox @@ -17,12 +17,12 @@ feature. \par Features - Scripting - - \ref feature_script <br>\copybrief feature_script + - \ref feature_script \n\copybrief feature_script - Game flow management - - \ref feature_scene <br>\copybrief feature_scene + - \ref feature_scene \n\copybrief feature_scene - Entity - - \ref feature_gameobject <br>\copybrief feature_gameobject + - \ref feature_gameobject \n\copybrief feature_gameobject */ diff --git a/src/doc/index.dox b/src/doc/index.dox index 5ec7889..7796f34 100644 --- a/src/doc/index.dox +++ b/src/doc/index.dox @@ -8,3 +8,10 @@ Welcome to the documentation for the crêpe game engine. \see feature */ + +/** + +\namespace crepe +\brief Engine namespace + +*/ diff --git a/src/doc/layout.xml b/src/doc/layout.xml index fb4cc0c..6336655 100644 --- a/src/doc/layout.xml +++ b/src/doc/layout.xml @@ -11,7 +11,7 @@ <tab type="modulelist" visible="yes" title="" intro=""/> <tab type="modulemembers" visible="yes" title="" intro=""/> </tab> - <tab type="namespaces" visible="no" title=""> + <tab type="namespaces" visible="yes" title=""> <tab type="namespacelist" visible="yes" title="" intro=""/> <tab type="namespacemembers" visible="yes" title="" intro=""/> </tab> @@ -56,10 +56,10 @@ <interfaces title=""/> <publicslots title=""/> <signals title=""/> - <publicmethods title=""/> - <publicstaticmethods title=""/> <publicattributes title=""/> <publicstaticattributes title=""/> + <publicmethods title=""/> + <publicstaticmethods title=""/> <protectedtypes title=""/> <protectedslots title=""/> <protectedmethods title=""/> @@ -102,11 +102,12 @@ </class> <namespace> <briefdescription visible="yes"/> + <detaileddescription title=""/> <memberdecl> <nestednamespaces visible="yes" title=""/> <constantgroups visible="yes" title=""/> <interfaces visible="yes" title=""/> - <classes visible="yes" title=""/> + <classes visible="no" title=""/> <concepts visible="yes" title=""/> <structs visible="yes" title=""/> <exceptions visible="yes" title=""/> @@ -119,7 +120,6 @@ <properties title=""/> <membergroups visible="yes"/> </memberdecl> - <detaileddescription title=""/> <memberdef> <inlineclasses title=""/> <typedefs title=""/> diff --git a/src/doc/style.css b/src/doc/style.css index daabd39..c12240c 100644 --- a/src/doc/style.css +++ b/src/doc/style.css @@ -1,6 +1,6 @@ #titlearea, -address { - display: none; -} +address, +a[href="namespaces.html"] +{ display: none; } h2.groupheader { margin-top: revert; } diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index b126add..232c763 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -12,5 +12,7 @@ target_sources(test_main PUBLIC ValueBrokerTest.cpp DBTest.cpp Vector2Test.cpp - loopTimerTest.cpp + LoopManagerTest.cpp + LoopTimerTest.cpp + ) diff --git a/src/test/DBTest.cpp b/src/test/DBTest.cpp index e80814c..99dedff 100644 --- a/src/test/DBTest.cpp +++ b/src/test/DBTest.cpp @@ -1,6 +1,7 @@ -#include <crepe/facade/DB.h> #include <gtest/gtest.h> +#include <crepe/facade/DB.h> + using namespace std; using namespace crepe; using namespace testing; diff --git a/src/test/ECSTest.cpp b/src/test/ECSTest.cpp index af9d6f2..3e6c61c 100644 --- a/src/test/ECSTest.cpp +++ b/src/test/ECSTest.cpp @@ -2,18 +2,20 @@ #define protected public -#include <crepe/ComponentManager.h> #include <crepe/api/GameObject.h> #include <crepe/api/Metadata.h> #include <crepe/api/Transform.h> #include <crepe/api/Vector2.h> +#include <crepe/manager/ComponentManager.h> using namespace std; using namespace crepe; class ECSTest : public ::testing::Test { + Mediator m; + public: - ComponentManager mgr{}; + ComponentManager mgr{m}; }; TEST_F(ECSTest, createGameObject) { diff --git a/src/test/EventTest.cpp b/src/test/EventTest.cpp index b0e6c9c..dccd554 100644 --- a/src/test/EventTest.cpp +++ b/src/test/EventTest.cpp @@ -1,10 +1,11 @@ - -#include "api/Event.h" -#include "api/EventManager.h" -#include "api/IKeyListener.h" -#include "api/IMouseListener.h" #include <gmock/gmock.h> #include <gtest/gtest.h> + +#include <crepe/api/Event.h> +#include <crepe/api/IKeyListener.h> +#include <crepe/api/IMouseListener.h> +#include <crepe/manager/EventManager.h> + using namespace std; using namespace std::chrono_literals; using namespace crepe; @@ -36,10 +37,7 @@ public: }; TEST_F(EventManagerTest, EventSubscription) { - EventHandler<KeyPressEvent> key_handler = [](const KeyPressEvent & e) { - std::cout << "Key Event Triggered" << std::endl; - return true; - }; + EventHandler<KeyPressEvent> key_handler = [](const KeyPressEvent & e) { return true; }; // Subscribe to KeyPressEvent EventManager::get_instance().subscribe<KeyPressEvent>(key_handler, 1); diff --git a/src/test/LoopManagerTest.cpp b/src/test/LoopManagerTest.cpp new file mode 100644 index 0000000..af6cb1c --- /dev/null +++ b/src/test/LoopManagerTest.cpp @@ -0,0 +1,44 @@ +#include <gtest/gtest.h> +#include <chrono> +#include <thread> +#define private public +#define protected public +#include "api/LoopTimer.h" +#include "api/LoopManager.h" + +using namespace std::chrono; +using namespace crepe; + +class LoopManagerTest : public ::testing::Test { +protected: + LoopManager loop_manager; + + void SetUp() override { + // Setting up loop manager and start the loop + loop_manager.loop_timer->set_target_fps(60); + } +}; + +//Test to check if exactly 5 fixed updates are done every second (50Hz) +TEST_F(LoopManagerTest, FixedUpdate) { + loop_manager.loop_timer->fixed_delta_time = std::chrono::milliseconds(20); + loop_manager.loop_timer->set_target_fps(50); + int fixed_update_count = 0; + loop_manager.loop_timer->start(); + // We want to simulate the game loop for about 1 second + auto start_time = steady_clock::now(); + + // Simulate the game loop for 1 second + while (duration_cast<milliseconds>(steady_clock::now() - start_time) < std::chrono::milliseconds(1000)) { + loop_manager.loop_timer->update(); + // Simulate processing fixed updates while there's lag to advance + while (loop_manager.loop_timer->get_lag() >= loop_manager.loop_timer->get_fixed_delta_time()) { + fixed_update_count++; + loop_manager.loop_timer->advance_fixed_update(); + } + + loop_manager.loop_timer->enforce_frame_rate(); + } + // gameloop is 99 because it first takes 20 millisecond to build the lag to execute the fixed loop + ASSERT_EQ(fixed_update_count, 50); +} diff --git a/src/test/loopTimerTest.cpp b/src/test/LoopTimerTest.cpp index 9bbbff3..6e3f118 100644 --- a/src/test/loopTimerTest.cpp +++ b/src/test/LoopTimerTest.cpp @@ -57,3 +57,25 @@ TEST_F(LoopTimerTest, DeltaTimeCalculation) { ASSERT_LE(delta_time, (elapsed_time + 2) / 1000.0); } +TEST_F(LoopTimerTest, getCurrentTime) { + // Set the target FPS to 60 (16.67 ms per frame) + loop_timer.set_target_fps(60); + + auto start_time = steady_clock::now(); + + // Sleep for 500 milliseconds + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + loop_timer.update(); + + auto end_time = steady_clock::now(); + + // Get the elapsed time in seconds as a double + auto elapsed_time = duration_cast<std::chrono::duration<double>>(end_time - start_time).count(); + + ASSERT_NEAR(loop_timer.get_current_time(), elapsed_time, 0.001); + + +} + + diff --git a/src/test/ParticleTest.cpp b/src/test/ParticleTest.cpp index 976f9a1..a659fe5 100644 --- a/src/test/ParticleTest.cpp +++ b/src/test/ParticleTest.cpp @@ -1,12 +1,12 @@ -#include "api/Texture.h" -#include <crepe/ComponentManager.h> #include <crepe/Particle.h> #include <crepe/api/Config.h> #include <crepe/api/GameObject.h> #include <crepe/api/ParticleEmitter.h> #include <crepe/api/Rigidbody.h> #include <crepe/api/Sprite.h> +#include <crepe/api/Texture.h> #include <crepe/api/Transform.h> +#include <crepe/manager/ComponentManager.h> #include <crepe/system/ParticleSystem.h> #include <gtest/gtest.h> #include <math.h> @@ -16,9 +16,11 @@ using namespace std::chrono_literals; using namespace crepe; class ParticlesTest : public ::testing::Test { + Mediator m; + public: - ComponentManager component_manager; - ParticleSystem particle_system{component_manager}; + ComponentManager component_manager{m}; + ParticleSystem particle_system{m}; void SetUp() override { ComponentManager & mgr = this->component_manager; diff --git a/src/test/PhysicsTest.cpp b/src/test/PhysicsTest.cpp index 33b6020..43af8e4 100644 --- a/src/test/PhysicsTest.cpp +++ b/src/test/PhysicsTest.cpp @@ -1,8 +1,8 @@ -#include <crepe/ComponentManager.h> #include <crepe/api/Config.h> #include <crepe/api/GameObject.h> #include <crepe/api/Rigidbody.h> #include <crepe/api/Transform.h> +#include <crepe/manager/ComponentManager.h> #include <crepe/system/PhysicsSystem.h> #include <gtest/gtest.h> @@ -11,9 +11,11 @@ using namespace std::chrono_literals; using namespace crepe; class PhysicsTest : public ::testing::Test { + Mediator m; + public: - ComponentManager component_manager; - PhysicsSystem system{component_manager}; + ComponentManager component_manager{m}; + PhysicsSystem system{m}; void SetUp() override { ComponentManager & mgr = this->component_manager; diff --git a/src/test/RenderSystemTest.cpp b/src/test/RenderSystemTest.cpp index bb5b81a..c105dcb 100644 --- a/src/test/RenderSystemTest.cpp +++ b/src/test/RenderSystemTest.cpp @@ -1,4 +1,3 @@ -#include "types.h" #include <functional> #include <gtest/gtest.h> #include <memory> @@ -7,12 +6,12 @@ #define private public #define protected public -#include "crepe/api/Camera.h" -#include <crepe/ComponentManager.h> +#include <crepe/api/Camera.h> #include <crepe/api/Color.h> #include <crepe/api/GameObject.h> #include <crepe/api/Sprite.h> #include <crepe/api/Texture.h> +#include <crepe/manager/ComponentManager.h> #include <crepe/system/RenderSystem.h> @@ -21,9 +20,11 @@ using namespace crepe; using namespace testing; class RenderSystemTest : public Test { + Mediator m; + public: - ComponentManager mgr{}; - RenderSystem sys{mgr}; + ComponentManager mgr{m}; + RenderSystem sys{m}; GameObject entity1 = this->mgr.new_object("name"); GameObject entity2 = this->mgr.new_object("name"); GameObject entity3 = this->mgr.new_object("name"); diff --git a/src/test/SceneManagerTest.cpp b/src/test/SceneManagerTest.cpp index 62b7d33..9bb260c 100644 --- a/src/test/SceneManagerTest.cpp +++ b/src/test/SceneManagerTest.cpp @@ -1,12 +1,13 @@ -#include "types.h" -#include <crepe/ComponentManager.h> +#include <gtest/gtest.h> + #include <crepe/api/GameObject.h> #include <crepe/api/Metadata.h> #include <crepe/api/Scene.h> -#include <crepe/api/SceneManager.h> #include <crepe/api/Transform.h> #include <crepe/api/Vector2.h> -#include <gtest/gtest.h> +#include <crepe/manager/ComponentManager.h> +#include <crepe/manager/SceneManager.h> +#include <crepe/types.h> using namespace std; using namespace crepe; @@ -14,7 +15,8 @@ using namespace crepe; class ConcreteScene1 : public Scene { public: void load_scene() { - ComponentManager & mgr = this->component_manager; + Mediator & mediator = this->mediator; + ComponentManager & mgr = mediator.component_manager; GameObject object1 = mgr.new_object("scene_1", "tag_scene_1", vec2{0, 0}, 0, 1); GameObject object2 = mgr.new_object("scene_1", "tag_scene_1", vec2{1, 0}, 0, 1); GameObject object3 = mgr.new_object("scene_1", "tag_scene_1", vec2{2, 0}, 0, 1); @@ -26,7 +28,8 @@ public: class ConcreteScene2 : public Scene { public: void load_scene() { - ComponentManager & mgr = this->component_manager; + Mediator & mediator = this->mediator; + ComponentManager & mgr = mediator.component_manager; GameObject object1 = mgr.new_object("scene_2", "tag_scene_2", vec2{0, 0}, 0, 1); GameObject object2 = mgr.new_object("scene_2", "tag_scene_2", vec2{0, 1}, 0, 1); GameObject object3 = mgr.new_object("scene_2", "tag_scene_2", vec2{0, 2}, 0, 1); @@ -41,7 +44,8 @@ public: ConcreteScene3(const string & name) : name(name) {} void load_scene() { - ComponentManager & mgr = this->component_manager; + Mediator & mediator = this->mediator; + ComponentManager & mgr = mediator.component_manager; GameObject object1 = mgr.new_object("scene_3", "tag_scene_3", vec2{0, 0}, 0, 1); } @@ -52,9 +56,11 @@ private: }; class SceneManagerTest : public ::testing::Test { + Mediator m; + public: - ComponentManager component_mgr{}; - SceneManager scene_mgr{component_mgr}; + ComponentManager component_mgr{m}; + SceneManager scene_mgr{m}; }; TEST_F(SceneManagerTest, loadScene) { diff --git a/src/test/ScriptEventTest.cpp b/src/test/ScriptEventTest.cpp new file mode 100644 index 0000000..5da31e7 --- /dev/null +++ b/src/test/ScriptEventTest.cpp @@ -0,0 +1,50 @@ +#include <gtest/gtest.h> + +// stupid hack to allow access to private/protected members under test +#define private public +#define protected public + +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/Event.h> +#include <crepe/api/GameObject.h> +#include <crepe/api/Script.h> +#include <crepe/api/Vector2.h> +#include <crepe/manager/ComponentManager.h> +#include <crepe/manager/EventManager.h> +#include <crepe/system/ScriptSystem.h> + +#include "ScriptTest.h" + +using namespace std; +using namespace crepe; +using namespace testing; + +class ScriptEventTest : public ScriptTest { +public: + EventManager & event_manager = mediator.event_manager; + + class MyEvent : public Event {}; +}; + +TEST_F(ScriptEventTest, Inactive) { + BehaviorScript & behaviorscript = this->behaviorscript; + MyScript & script = this->script; + EventManager & evmgr = this->event_manager; + + unsigned event_count = 0; + script.subscribe<MyEvent>([&](const MyEvent &) { + event_count++; + return true; + }); + + system.update(); + behaviorscript.active = false; + EXPECT_EQ(0, event_count); + + evmgr.trigger_event<MyEvent>(); + EXPECT_EQ(0, event_count); + + behaviorscript.active = true; + evmgr.trigger_event<MyEvent>(); + EXPECT_EQ(1, event_count); +} diff --git a/src/test/ScriptSceneTest.cpp b/src/test/ScriptSceneTest.cpp new file mode 100644 index 0000000..9ee1e52 --- /dev/null +++ b/src/test/ScriptSceneTest.cpp @@ -0,0 +1,30 @@ +#include <gtest/gtest.h> + +// stupid hack to allow access to private/protected members under test +#define private public +#define protected public + +#include "ScriptTest.h" +#include <crepe/manager/SceneManager.h> + +using namespace std; +using namespace crepe; +using namespace testing; + +class ScriptSceneTest : public ScriptTest { +public: + SceneManager scene_manager{mediator}; + + class MyScene : public Scene {}; +}; + +TEST_F(ScriptSceneTest, Inactive) { + BehaviorScript & behaviorscript = this->behaviorscript; + MyScript & script = this->script; + + const char * non_default_value = "foo"; + ASSERT_NE(non_default_value, scene_manager.next_scene); + + script.set_next_scene(non_default_value); + EXPECT_EQ(non_default_value, scene_manager.next_scene); +} diff --git a/src/test/ScriptTest.cpp b/src/test/ScriptTest.cpp index 78d5061..1d2d6dd 100644 --- a/src/test/ScriptTest.cpp +++ b/src/test/ScriptTest.cpp @@ -1,129 +1,77 @@ +#include <gmock/gmock.h> #include <gtest/gtest.h> // stupid hack to allow access to private/protected members under test #define private public #define protected public -#include <crepe/ComponentManager.h> -#include <crepe/api/BehaviorScript.h> -#include <crepe/api/Event.h> -#include <crepe/api/EventManager.h> +#include "ScriptTest.h" #include <crepe/api/GameObject.h> -#include <crepe/api/Script.h> -#include <crepe/api/Vector2.h> -#include <crepe/system/ScriptSystem.h> using namespace std; using namespace crepe; using namespace testing; -class MyEvent : public Event {}; - -class ScriptTest : public Test { -public: - ComponentManager component_manager{}; - ScriptSystem system{component_manager}; - EventManager & event_manager = EventManager::get_instance(); - - class MyScript : public Script { - // NOTE: default (private) visibility of init and update shouldn't cause - // issues! - void init() { - this->init_count++; - - subscribe<MyEvent>([this](const MyEvent &) { - this->event_count++; - return true; - }); - - // init should never be called more than once - EXPECT_LE(this->init_count, 1); - } - void update() { this->update_count++; } - - public: - unsigned init_count = 0; - unsigned update_count = 0; - unsigned event_count = 0; - }; - - OptionalRef<BehaviorScript> behaviorscript; - OptionalRef<MyScript> script; - - void SetUp() override { - auto & mgr = this->component_manager; - GameObject entity = mgr.new_object("name"); - BehaviorScript & component = entity.add_component<BehaviorScript>(); - - this->behaviorscript = component; - ASSERT_TRUE(this->behaviorscript); - EXPECT_EQ(component.script.get(), nullptr); - component.set_script<MyScript>(); - ASSERT_NE(component.script.get(), nullptr); - - this->script = *(MyScript *) component.script.get(); - ASSERT_TRUE(this->script); - - // sanity - MyScript & script = this->script; - ASSERT_EQ(script.init_count, 0); - ASSERT_EQ(script.update_count, 0); - ASSERT_EQ(script.event_count, 0); - } -}; +void ScriptTest::SetUp() { + auto & mgr = this->component_manager; + GameObject entity = mgr.new_object("name"); + BehaviorScript & component = entity.add_component<BehaviorScript>(); + + this->behaviorscript = component; + ASSERT_TRUE(this->behaviorscript); + EXPECT_EQ(component.script.get(), nullptr); + component.set_script<NiceMock<MyScript>>(); + ASSERT_NE(component.script.get(), nullptr); + + this->script = *(MyScript *) component.script.get(); + ASSERT_TRUE(this->script); +} TEST_F(ScriptTest, Default) { MyScript & script = this->script; - EXPECT_EQ(0, script.init_count); - EXPECT_EQ(0, script.update_count); - EXPECT_EQ(0, script.event_count); + EXPECT_CALL(script, init()).Times(0); + EXPECT_CALL(script, update()).Times(0); } TEST_F(ScriptTest, UpdateOnce) { MyScript & script = this->script; - system.update(); - EXPECT_EQ(1, script.init_count); - EXPECT_EQ(1, script.update_count); - EXPECT_EQ(0, script.event_count); + { + InSequence seq; + + EXPECT_CALL(script, init()).Times(1); + EXPECT_CALL(script, update()).Times(1); + system.update(); + } + + { + InSequence seq; + + EXPECT_CALL(script, init()).Times(0); + EXPECT_CALL(script, update()).Times(1); + system.update(); + } } TEST_F(ScriptTest, UpdateInactive) { BehaviorScript & behaviorscript = this->behaviorscript; MyScript & script = this->script; - behaviorscript.active = false; - system.update(); - EXPECT_EQ(0, script.init_count); - EXPECT_EQ(0, script.update_count); - EXPECT_EQ(0, script.event_count); - - behaviorscript.active = true; - system.update(); - EXPECT_EQ(1, script.init_count); - EXPECT_EQ(1, script.update_count); - EXPECT_EQ(0, script.event_count); -} + { + InSequence seq; -TEST_F(ScriptTest, EventInactive) { - BehaviorScript & behaviorscript = this->behaviorscript; - MyScript & script = this->script; - EventManager & evmgr = this->event_manager; - - system.update(); - behaviorscript.active = false; - EXPECT_EQ(1, script.init_count); - EXPECT_EQ(1, script.update_count); - EXPECT_EQ(0, script.event_count); - - evmgr.trigger_event<MyEvent>(); - EXPECT_EQ(1, script.init_count); - EXPECT_EQ(1, script.update_count); - EXPECT_EQ(0, script.event_count); - - behaviorscript.active = true; - evmgr.trigger_event<MyEvent>(); - EXPECT_EQ(1, script.init_count); - EXPECT_EQ(1, script.update_count); - EXPECT_EQ(1, script.event_count); + EXPECT_CALL(script, init()).Times(0); + EXPECT_CALL(script, update()).Times(0); + behaviorscript.active = false; + system.update(); + } + + { + InSequence seq; + + EXPECT_CALL(script, init()).Times(1); + EXPECT_CALL(script, update()).Times(1); + behaviorscript.active = true; + system.update(); + } } diff --git a/src/test/ScriptTest.h b/src/test/ScriptTest.h new file mode 100644 index 0000000..1bbfdd3 --- /dev/null +++ b/src/test/ScriptTest.h @@ -0,0 +1,31 @@ +#pragma once + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/Script.h> +#include <crepe/manager/ComponentManager.h> +#include <crepe/system/ScriptSystem.h> + +class ScriptTest : public testing::Test { +protected: + crepe::Mediator mediator; + +public: + crepe::ComponentManager component_manager{mediator}; + crepe::ScriptSystem system{mediator}; + + class MyScript : public crepe::Script { + // NOTE: explicitly stating `public:` is not required on actual scripts + + public: + MOCK_METHOD(void, init, (), (override)); + MOCK_METHOD(void, update, (), (override)); + }; + + crepe::OptionalRef<crepe::BehaviorScript> behaviorscript; + crepe::OptionalRef<MyScript> script; + + virtual void SetUp(); +}; diff --git a/src/test/loopManagerTest.cpp b/src/test/loopManagerTest.cpp deleted file mode 100644 index 6e66ce7..0000000 --- a/src/test/loopManagerTest.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include <gtest/gtest.h> -#include <chrono> -#include <thread> -#define private public -#define protected public -#include "api/LoopTimer.h" -#include "api/LoopManager.h" - -using namespace std::chrono; -using namespace crepe; - -class LoopTimerTest : public ::testing::Test { -protected: - LoopManager loop_manager; - - void SetUp() override { - // Setting up loop manager and start the loop - loop_manager.setup(); - loop_manager.loop_timer->set_target_fps(60); - } -}; - -// Test to check if exactly 5 fixed updates are done every second (50Hz) -TEST_F(LoopTimerTest, FixedUpdateCalledAt50Hz) { - // Set target fixed delta time to 20ms (50Hz fixed updates) - loop_manager.loop_timer->set_fixed_delta_time(milliseconds(20)); - - int fixed_update_count = 0; - - // We want to simulate the game loop for about 1 second - auto start_time = steady_clock::now(); - - // Simulate the game loop for 1 second - while (duration_cast<seconds>(steady_clock::now() - start_time).count() < 1) { - loop_manager.loop_timer->update(); - - // Simulate processing fixed updates while there's lag to advance - while (loop_manager.loop_timer->get_lag() >= loop_manager.loop_timer->get_fixed_delta_time()) { - loop_manager.fixed_update(); // Process fixed update - fixed_update_count++; // Count the number of fixed updates - loop_manager.loop_timer->advance_fixed_update(); - } - - // We do not need to call render or update for this test - loop_manager.loop_timer->enforce_frame_rate(); // Enforce the frame rate (this would normally go to the display) - } - - // We expect 5 fixed updates to occur in 1 second at 50Hz - ASSERT_EQ(fixed_update_count, 5); -} |