diff options
78 files changed, 974 insertions, 560 deletions
diff --git a/asset/texture/test_ap43.png b/asset/texture/test_ap43.png Binary files differnew file mode 100644 index 0000000..e758ed7 --- /dev/null +++ b/asset/texture/test_ap43.png 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 0313dfa..6cbb9fe 100644 --- a/src/crepe/CMakeLists.txt +++ b/src/crepe/CMakeLists.txt @@ -1,25 +1,21 @@ target_sources(crepe PUBLIC Particle.cpp - ComponentManager.cpp Component.cpp Collider.cpp - ResourceManager.cpp Resource.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES - ComponentManager.h - ComponentManager.hpp Component.h Collider.h ValueBroker.h ValueBroker.hpp - ResourceManager.h Resource.h ) add_subdirectory(api) add_subdirectory(facade) +add_subdirectory(manager) add_subdirectory(system) add_subdirectory(util) diff --git a/src/crepe/ComponentManager.cpp b/src/crepe/ComponentManager.cpp deleted file mode 100644 index e4de027..0000000 --- a/src/crepe/ComponentManager.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "api/GameObject.h" -#include "util/Log.h" - -#include "ComponentManager.h" - -using namespace crepe; -using namespace std; - -ComponentManager::ComponentManager() { dbg_trace(); } -ComponentManager::~ComponentManager() { dbg_trace(); } - -void ComponentManager::delete_all_components_of_id(game_object_id_t id) { - // Loop through all the types (in the unordered_map<>) - for (auto & [type, componentArray] : this->components) { - // Make sure that the id (that we are looking for) is within the boundaries of the vector<> - if (id < componentArray.size()) { - // Clear the components at this specific id - componentArray[id].clear(); - } - } -} - -void ComponentManager::delete_all_components() { - this->components.clear(); - this->next_id = 0; -} - -GameObject ComponentManager::new_object(const string & name, const string & tag, - const vec2 & position, double rotation, double scale) { - GameObject object{*this, this->next_id, name, tag, position, rotation, scale}; - this->next_id++; - return object; -} diff --git a/src/crepe/api/Animator.cpp b/src/crepe/api/Animator.cpp index 464b0fd..45f67f6 100644 --- a/src/crepe/api/Animator.cpp +++ b/src/crepe/api/Animator.cpp @@ -14,11 +14,14 @@ Animator::Animator(game_object_id_t id, Sprite & ss, int row, int col, int col_a col(col) { dbg_trace(); - animator_rect = spritesheet.sprite_rect; - animator_rect.h /= col; - animator_rect.w /= row; - animator_rect.x = 0; - animator_rect.y = col_animator * animator_rect.h; + this->spritesheet.mask.h /= col; + this->spritesheet.mask.w /= row; + this->spritesheet.mask.x = 0; + this->spritesheet.mask.y = col_animator * this->spritesheet.mask.h; this->active = false; + + // need to do this for to get the aspect ratio for a single clipping in the spritesheet + this->spritesheet.aspect_ratio + = static_cast<double>(this->spritesheet.mask.w) / this->spritesheet.mask.h; } Animator::~Animator() { dbg_trace(); } diff --git a/src/crepe/api/Animator.h b/src/crepe/api/Animator.h index 53f4b91..6c506aa 100644 --- a/src/crepe/api/Animator.h +++ b/src/crepe/api/Animator.h @@ -40,10 +40,6 @@ public: Animator(uint32_t id, Sprite & spritesheet, int row, int col, int col_animate); ~Animator(); // dbg_trace - Animator(const Animator &) = delete; - Animator(Animator &&) = delete; - Animator & operator=(const Animator &) = delete; - Animator & operator=(Animator &&) = delete; private: //! A reference to the Sprite sheet containing the animation frames. @@ -61,8 +57,6 @@ private: //! The current row being animated. int curr_row = 0; - Rect animator_rect; - //TODO: Is this necessary? //int fps; diff --git a/src/crepe/api/AssetManager.h b/src/crepe/api/AssetManager.h deleted file mode 100644 index fee6780..0000000 --- a/src/crepe/api/AssetManager.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include <any> -#include <memory> -#include <string> -#include <unordered_map> - -namespace crepe { - -/** - * \brief The AssetManager is responsible for storing and managing assets over multiple scenes. - * - * The AssetManager ensures that assets are loaded once and can be accessed across different - * scenes. It caches assets to avoid reloading them every time a scene is loaded. Assets are - * retained in memory until the AssetManager is destroyed, at which point the cached assets are - * cleared. - */ -class AssetManager { - -private: - //! A cache that holds all the assets, accessible by their file path, over multiple scenes. - std::unordered_map<std::string, std::any> asset_cache; - -private: - AssetManager(); - virtual ~AssetManager(); - -public: - AssetManager(const AssetManager &) = delete; - AssetManager(AssetManager &&) = delete; - AssetManager & operator=(const AssetManager &) = delete; - AssetManager & operator=(AssetManager &&) = delete; - - /** - * \brief Retrieves the singleton instance of the AssetManager. - * - * \return A reference to the single instance of the AssetManager. - */ - static AssetManager & get_instance(); - -public: - /** - * \brief Caches an asset by loading it from the given file path. - * - * \param file_path The path to the asset file to load. - * \param reload If true, the asset will be reloaded from the file, even if it is already - * cached. - * \tparam T The type of asset to cache (e.g., texture, sound, etc.). - * - * \return A shared pointer to the cached asset. - * - * This template function caches the asset at the given file path. If the asset is already - * cached and `reload` is false, the existing cached version will be returned. Otherwise, the - * asset will be reloaded and added to the cache. - */ - template <typename T> - std::shared_ptr<T> cache(const std::string & file_path, bool reload = false); -}; - -} // namespace crepe - -#include "AssetManager.hpp" diff --git a/src/crepe/api/AssetManager.hpp b/src/crepe/api/AssetManager.hpp deleted file mode 100644 index 1c0e978..0000000 --- a/src/crepe/api/AssetManager.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "AssetManager.h" - -namespace crepe { - -template <typename asset> -std::shared_ptr<asset> AssetManager::cache(const std::string & file_path, bool reload) { - auto it = asset_cache.find(file_path); - - if (!reload && it != asset_cache.end()) { - return std::any_cast<std::shared_ptr<asset>>(it->second); - } - - std::shared_ptr<asset> new_asset = std::make_shared<asset>(file_path.c_str()); - - asset_cache[file_path] = new_asset; - - return new_asset; -} - -} // namespace crepe 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..6de0157 100644 --- a/src/crepe/api/BehaviorScript.hpp +++ b/src/crepe/api/BehaviorScript.hpp @@ -14,11 +14,11 @@ 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)...); + Mediator & mediator = this->mediator; s->game_object_id = this->game_object_id; s->active = this->active; - s->component_manager = this->component_manager; - s->event_manager = EventManager::get_instance(); + s->mediator = 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 ad82924..0808612 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -8,13 +8,10 @@ target_sources(crepe PUBLIC Color.cpp Texture.cpp Sprite.cpp - SaveManager.cpp Config.cpp Metadata.cpp - SceneManager.cpp Camera.cpp Animator.cpp - EventManager.cpp IKeyListener.cpp IMouseListener.cpp LoopManager.cpp @@ -38,15 +35,10 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES Vector2.hpp Color.h Texture.h - 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/Camera.cpp b/src/crepe/api/Camera.cpp index 5835bdd..39d8ab0 100644 --- a/src/crepe/api/Camera.cpp +++ b/src/crepe/api/Camera.cpp @@ -1,3 +1,4 @@ +#include "types.h" #include "util/Log.h" #include "Camera.h" @@ -6,9 +7,14 @@ using namespace crepe; -Camera::Camera(game_object_id_t id, const Color & bg_color) +Camera::Camera(game_object_id_t id, const Color & bg_color, const ivec2 & screen, + const vec2 & viewport_size, const double & zoom, const vec2 & offset) : Component(id), - bg_color(bg_color) { + bg_color(bg_color), + offset(offset), + screen(screen), + viewport_size(viewport_size), + zoom(zoom) { dbg_trace(); } diff --git a/src/crepe/api/Camera.h b/src/crepe/api/Camera.h index e0cda34..2d8fa48 100644 --- a/src/crepe/api/Camera.h +++ b/src/crepe/api/Camera.h @@ -2,6 +2,7 @@ #include "Color.h" #include "Component.h" +#include "types.h" namespace crepe { @@ -20,33 +21,31 @@ public: * \param id Unique identifier for the camera component. * \param bg_color Background color for the camera view. */ - Camera(game_object_id_t id, const Color & bg_color); + Camera(game_object_id_t id, const Color & bg_color, const ivec2 & screen, + const vec2 & viewport_size, const double & zoom, const vec2 & offset = {0, 0}); ~Camera(); // dbg_trace only public: //! Background color of the camera view. - Color bg_color; + const Color bg_color; - //! Aspect ratio height for the camera. - double aspect_height = 480; + //! offset postion from the game object transform component + vec2 offset; - //! Aspect ratio width for the camera. - double aspect_width = 640; + //! screen the display size in pixels ( output resolution ) + const ivec2 screen; - //! X-coordinate of the camera position. - double x = 0.0; - - //! Y-coordinate of the camera position. - double y = 0.0; + //! viewport is the area of the world visible through the camera (in world units) + const vec2 viewport_size; //! Zoom level of the camera view. - double zoom = 1.0; + const double zoom; public: /** * \brief Gets the maximum number of camera instances allowed. * \return Maximum instance count as an integer. */ - virtual int get_instances_max() const { return 10; } + virtual int get_instances_max() const { return 1; } }; } // namespace crepe diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h index 5bd6913..693400a 100644 --- a/src/crepe/api/Config.h +++ b/src/crepe/api/Config.h @@ -1,6 +1,8 @@ #pragma once #include "../util/Log.h" +#include "types.h" +#include <string> namespace crepe { @@ -39,6 +41,14 @@ struct Config final { double gravity = 1; } physics; + //! default window settings + struct { + //TODO make this constexpr because this will never change + ivec2 default_size = {1080, 720}; + std::string window_title = "Jetpack joyride clone"; + + } window_settings; + //! Asset loading options struct { /** diff --git a/src/crepe/api/GameObject.cpp b/src/crepe/api/GameObject.cpp index 3c36a21..9ef4682 100644 --- a/src/crepe/api/GameObject.cpp +++ b/src/crepe/api/GameObject.cpp @@ -30,3 +30,9 @@ void GameObject::set_parent(const GameObject & parent) { RefVector<Metadata> parent_metadata = mgr.get_components_by_id<Metadata>(parent.id); parent_metadata.at(0).get().children.push_back(this->id); } + +void GameObject::set_persistent(bool persistent) { + ComponentManager & mgr = this->component_manager; + + mgr.set_persistent(this->id, persistent); +} diff --git a/src/crepe/api/GameObject.h b/src/crepe/api/GameObject.h index fcb8d9a..4cd2bc0 100644 --- a/src/crepe/api/GameObject.h +++ b/src/crepe/api/GameObject.h @@ -58,6 +58,15 @@ public: */ template <typename T, typename... Args> T & add_component(Args &&... args); + /** + * \brief Components will not be deleted if this method is called + * + * This method sets the persistent flag of the GameObject to true. If the persistent + * flag is set to true, the GameObject will not be deleted when the scene is changed. + * + * \param persistent The persistent flag + */ + void set_persistent(bool persistent = true); public: //! The id of the GameObject 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 7edf4d1..b277185 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -1,5 +1,3 @@ -#include "../facade/SDLContext.h" - #include "../system/AnimatorSystem.h" #include "../system/CollisionSystem.h" #include "../system/ParticleSystem.h" @@ -8,12 +6,14 @@ #include "../system/ScriptSystem.h" #include "LoopManager.h" -#include "LoopTimer.h" using namespace crepe; using namespace std; LoopManager::LoopManager() { + this->mediator.component_manager = this->component_manager; + this->mediator.scene_manager = this->scene_manager; + this->load_system<AnimatorSystem>(); this->load_system<CollisionSystem>(); this->load_system<ParticleSystem>(); @@ -23,7 +23,7 @@ LoopManager::LoopManager() { } void LoopManager::process_input() { - SDLContext::get_instance().handle_events(this->game_running); + this->sdl_context.handle_events(this->game_running); } void LoopManager::start() { @@ -35,7 +35,7 @@ void LoopManager::set_running(bool running) { this->game_running = running; } void LoopManager::fixed_update() {} void LoopManager::loop() { - LoopTimer & timer = LoopTimer::get_instance(); + LoopTimer & timer = this->loop_timer; timer.start(); while (game_running) { @@ -55,15 +55,18 @@ void LoopManager::loop() { } void LoopManager::setup() { + LoopTimer & timer = this->loop_timer; + this->game_running = true; - LoopTimer::get_instance().start(); - LoopTimer::get_instance().set_fps(200); + timer.start(); + timer.set_fps(200); } void LoopManager::render() { - if (this->game_running) { - this->get_system<RenderSystem>().update(); - } + if (!this->game_running) return; + + this->get_system<RenderSystem>().update(); } -void LoopManager::update() { LoopTimer & timer = LoopTimer::get_instance(); } +void LoopManager::update() {} + diff --git a/src/crepe/api/LoopManager.h b/src/crepe/api/LoopManager.h index 13e6dac..6ea5ccc 100644 --- a/src/crepe/api/LoopManager.h +++ b/src/crepe/api/LoopManager.h @@ -2,9 +2,12 @@ #include <memory> -#include "../ComponentManager.h" +#include "../manager/ComponentManager.h" +#include "../manager/SceneManager.h" #include "../system/System.h" -#include "api/SceneManager.h" +#include "../facade/SDLContext.h" + +#include "LoopTimer.h" namespace crepe { @@ -85,10 +88,18 @@ 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}; + + //! SDL context \todo no more singletons! + SDLContext & sdl_context = SDLContext::get_instance(); + //! Loop timer \todo no more singletons! + LoopTimer & loop_timer = LoopTimer::get_instance(); private: /** diff --git a/src/crepe/api/LoopManager.hpp b/src/crepe/api/LoopManager.hpp index 9cf470b..cd6bd02 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); + System * system = new T(this->mediator); + const type_info & type = typeid(T); + if (this->systems.contains(type)) + throw runtime_error(format("LoopManager: {} is already initialized", type.name())); + this->systems[type] = unique_ptr<System>(system); } } // namespace crepe diff --git a/src/crepe/api/Scene.h b/src/crepe/api/Scene.h index f6fdb2a..66dad17 100644 --- a/src/crepe/api/Scene.h +++ b/src/crepe/api/Scene.h @@ -3,6 +3,7 @@ #include <string> #include "../util/OptionalRef.h" +#include "../manager/Mediator.h" namespace crepe { @@ -34,6 +35,8 @@ 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 +49,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..a27838e 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,10 @@ 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..e1f86b2 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -4,8 +4,8 @@ #include "../types.h" #include "../util/OptionalRef.h" - -#include "EventManager.h" +#include "../manager/Mediator.h" +#include "../manager/EventManager.h" namespace crepe { @@ -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/api/Sprite.cpp b/src/crepe/api/Sprite.cpp index bd2d5cf..8647794 100644 --- a/src/crepe/api/Sprite.cpp +++ b/src/crepe/api/Sprite.cpp @@ -1,7 +1,7 @@ -#include <memory> +#include <cmath> +#include <utility> #include "../util/Log.h" -#include "facade/SDLContext.h" #include "Component.h" #include "Sprite.h" @@ -10,16 +10,21 @@ using namespace std; using namespace crepe; -Sprite::Sprite(game_object_id_t id, const shared_ptr<Texture> image, const Color & color, - const FlipSettings & flip) +Sprite::Sprite(game_object_id_t id, Texture & image, const Color & color, + const FlipSettings & flip, int sort_layer, int order_layer, int height) : Component(id), color(color), flip(flip), - sprite_image(image) { + sprite_image(std::move(image)), + sorting_in_layer(sort_layer), + order_in_layer(order_layer), + height(height) { + dbg_trace(); - this->sprite_rect.w = sprite_image->get_width(); - this->sprite_rect.h = sprite_image->get_height(); + this->mask.w = sprite_image.get_width(); + this->mask.h = sprite_image.get_height(); + this->aspect_ratio = static_cast<double>(this->mask.w) / this->mask.h; } Sprite::~Sprite() { dbg_trace(); } diff --git a/src/crepe/api/Sprite.h b/src/crepe/api/Sprite.h index 74a55d4..a0e90a0 100644 --- a/src/crepe/api/Sprite.h +++ b/src/crepe/api/Sprite.h @@ -1,6 +1,6 @@ #pragma once -#include <memory> +#include <cstdint> #include "../Component.h" @@ -9,18 +9,6 @@ namespace crepe { -struct Rect { - int w = 0; - int h = 0; - int x = 0; - int y = 0; -}; - -struct FlipSettings { - bool flip_x = false; - bool flip_y = false; -}; - class SDLContext; class Animator; class AnimatorSystem; @@ -34,6 +22,12 @@ class AnimatorSystem; class Sprite : public Component { public: + struct FlipSettings { + bool flip_x = false; + bool flip_y = false; + }; + +public: // TODO: Loek comment in github #27 will be looked another time // about shared_ptr Texture /** @@ -42,9 +36,12 @@ public: * \param image Shared pointer to the texture for this sprite. * \param color Color tint applied to the sprite. * \param flip Flip settings for horizontal and vertical orientation. + * \param order_layer decides the sorting in layer of the sprite. + * \param sort_layer decides the order in layer of the sprite. + * \param height the height of the image in game units */ - Sprite(game_object_id_t id, const std::shared_ptr<Texture> image, const Color & color, - const FlipSettings & flip); + Sprite(game_object_id_t id, Texture & image, const Color & color, + const FlipSettings & flip, int sort_layer, int order_layer, int height); /** * \brief Destroys the Sprite instance. @@ -52,38 +49,49 @@ public: ~Sprite(); //! Texture used for the sprite - const std::shared_ptr<Texture> sprite_image; + const Texture sprite_image; + //! Color tint of the sprite Color color; + //! Flip settings for the sprite FlipSettings flip; + //! Layer sorting level of the sprite - uint8_t sorting_in_layer = 0; + const int sorting_in_layer; //! Order within the sorting layer - uint8_t order_in_layer = 0; + const int order_in_layer; + + //! height in world units + const int height; -public: /** - * \brief Gets the maximum number of instances allowed for this sprite. - * \return Maximum instance count as an integer. + * \aspect_ratio ratio of the img so that scaling will not become weird * - * For now is this number randomly picked. I think it will eventually be 1. + * cannot be const because if Animator component is addded then ratio becomes scuffed and + * does it need to be calculated again in the Animator */ - virtual int get_instances_max() const { return 10; } + double aspect_ratio; private: - //! Reads the sprite_rect of sprite + //! Reads the mask of sprite friend class SDLContext; - //! Reads the all the variables plus the sprite_rect + //! Reads the all the variables plus the mask friend class Animator; - //! Reads the all the variables plus the sprite_rect + //! Reads the all the variables plus the mask friend class AnimatorSystem; + struct Rect { + int w = 0; + int h = 0; + int x = 0; + int y = 0; + }; //! Render area of the sprite this will also be adjusted by the AnimatorSystem if an Animator - // object is present in GameObject - Rect sprite_rect; + // object is present in GameObject. this is in sprite pixels + Rect mask; }; } // namespace crepe diff --git a/src/crepe/api/Texture.cpp b/src/crepe/api/Texture.cpp index 264d7b1..e43bdaa 100644 --- a/src/crepe/api/Texture.cpp +++ b/src/crepe/api/Texture.cpp @@ -1,5 +1,3 @@ -#include <SDL2/SDL_render.h> - #include "../facade/SDLContext.h" #include "../util/Log.h" @@ -19,6 +17,15 @@ Texture::~Texture() { this->texture.reset(); } +Texture::Texture(Texture && other) noexcept : texture(std::move(other.texture)) {} + +Texture & Texture::operator=(Texture && other) noexcept { + if (this != &other) { + texture = std::move(other.texture); + } + return *this; +} + void Texture::load(const Asset & res) { SDLContext & ctx = SDLContext::get_instance(); this->texture = ctx.texture_from_path(res.get_path()); diff --git a/src/crepe/api/Texture.h b/src/crepe/api/Texture.h index b4f7d07..7206a66 100644 --- a/src/crepe/api/Texture.h +++ b/src/crepe/api/Texture.h @@ -36,6 +36,11 @@ public: ~Texture(); // FIXME: this constructor shouldn't be necessary because this class doesn't manage memory + Texture(Texture && other) noexcept; + Texture & operator=(Texture && other) noexcept; + Texture(const Texture &) = delete; + Texture & operator=(const Texture &) = delete; + /** * \brief Gets the width of the texture. * \return Width of the texture in pixels. diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index b3298a7..9f60285 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -10,16 +10,15 @@ #include <functional> #include <memory> #include <stdexcept> -#include <string> #include "../api/Camera.h" +#include "../api/Config.h" #include "../api/Sprite.h" #include "../api/Texture.h" -#include "../api/Transform.h" -#include "../api/Vector2.h" #include "../util/Log.h" #include "SDLContext.h" +#include "types.h" using namespace crepe; using namespace std; @@ -31,14 +30,15 @@ SDLContext & SDLContext::get_instance() { SDLContext::SDLContext() { dbg_trace(); - // FIXME: read window defaults from config manager if (SDL_Init(SDL_INIT_VIDEO) != 0) { throw runtime_error(format("SDLContext: SDL_Init error: {}", SDL_GetError())); } + + auto & cfg = Config::get_instance().window_settings; SDL_Window * tmp_window - = SDL_CreateWindow("Crepe Game Engine", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - this->viewport.w, this->viewport.h, 0); + = SDL_CreateWindow(cfg.window_title.c_str(), SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, cfg.default_size.x, cfg.default_size.y, 0); if (!tmp_window) { throw runtime_error(format("SDLContext: SDL_Window error: {}", SDL_GetError())); } @@ -93,68 +93,96 @@ void SDLContext::handle_events(bool & running) { */ } -void SDLContext::clear_screen() { SDL_RenderClear(this->game_renderer.get()); } +void SDLContext::clear_screen() { + SDL_SetRenderDrawColor(this->game_renderer.get(), 0, 0, 0, 255); + SDL_RenderClear(this->game_renderer.get()); +} void SDLContext::present_screen() { SDL_RenderPresent(this->game_renderer.get()); } SDL_Rect SDLContext::get_src_rect(const Sprite & sprite) const { return SDL_Rect{ - .x = sprite.sprite_rect.x, - .y = sprite.sprite_rect.y, - .w = sprite.sprite_rect.w, - .h = sprite.sprite_rect.h, + .x = sprite.mask.x, + .y = sprite.mask.y, + .w = sprite.mask.w, + .h = sprite.mask.h, }; } -SDL_Rect SDLContext::get_dst_rect(const Sprite & sprite, const vec2 & pos, - const double & scale, const Camera & cam) const { +SDL_Rect SDLContext::get_dst_rect(const Sprite & sprite, const vec2 & pos, const Camera & cam, + const vec2 & cam_pos, const double & img_scale) const { + + int width = sprite.height * sprite.aspect_ratio; + int height = sprite.height; - double adjusted_w = sprite.sprite_rect.w * scale * cam.zoom; - double adjusted_h = sprite.sprite_rect.h * scale * cam.zoom; - double adjusted_x = (pos.x - cam.x) * cam.zoom - adjusted_w / 2; - double adjusted_y = (pos.y - cam.y) * cam.zoom - adjusted_h / 2; + width *= img_scale * cam.zoom; + height *= img_scale * cam.zoom; return SDL_Rect{ - .x = static_cast<int>(adjusted_x), - .y = static_cast<int>(adjusted_y), - .w = static_cast<int>(adjusted_w), - .h = static_cast<int>(adjusted_h), + .x = static_cast<int>((pos.x - cam_pos.x + (cam.viewport_size.x / 2) - width / 2)), + .y = static_cast<int>((pos.y - cam_pos.y + (cam.viewport_size.y / 2) - height / 2)), + .w = width, + .h = height, }; } -void SDLContext::draw_particle(const Sprite & sprite, const vec2 & pos, const double & angle, - const double & scale, const Camera & camera) { +void SDLContext::draw(const RenderContext & ctx) { SDL_RendererFlip render_flip - = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * sprite.flip.flip_x) - | (SDL_FLIP_VERTICAL * sprite.flip.flip_y)); + = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * ctx.sprite.flip.flip_x) + | (SDL_FLIP_VERTICAL * ctx.sprite.flip.flip_y)); - SDL_Rect srcrect = this->get_src_rect(sprite); - SDL_Rect dstrect = this->get_dst_rect(sprite, pos, scale, camera); + SDL_Rect srcrect = this->get_src_rect(ctx.sprite); + SDL_Rect dstrect + = this->get_dst_rect(ctx.sprite, ctx.pos, ctx.cam, ctx.cam_pos, ctx.scale); - SDL_RenderCopyEx(this->game_renderer.get(), sprite.sprite_image->texture.get(), &srcrect, - &dstrect, angle, NULL, render_flip); + SDL_RenderCopyEx(this->game_renderer.get(), ctx.sprite.sprite_image.texture.get(), + &srcrect, &dstrect, ctx.angle, NULL, render_flip); } -void SDLContext::draw(const Sprite & sprite, const Transform & transform, const Camera & cam) { - - SDL_RendererFlip render_flip - = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * sprite.flip.flip_x) - | (SDL_FLIP_VERTICAL * sprite.flip.flip_y)); +void SDLContext::set_camera(const Camera & cam) { - SDL_Rect srcrect = this->get_src_rect(sprite); - SDL_Rect dstrect = this->get_dst_rect(sprite, transform.position, transform.scale, cam); + // resize window + int w, h; + SDL_GetWindowSize(this->game_window.get(), &w, &h); + if (w != cam.screen.x || h != cam.screen.y) { + SDL_SetWindowSize(this->game_window.get(), cam.screen.x, cam.screen.y); + } - SDL_RenderCopyEx(this->game_renderer.get(), sprite.sprite_image->texture.get(), &srcrect, - &dstrect, transform.rotation, NULL, render_flip); -} + double screen_aspect = cam.screen.x / cam.screen.y; + double viewport_aspect = cam.viewport_size.x / cam.viewport_size.y; + + SDL_Rect view; + // calculate black bars + if (screen_aspect > viewport_aspect) { + // letterboxing + view.h = cam.screen.y / cam.zoom; + view.w = cam.screen.y * viewport_aspect; + view.x = (cam.screen.x - view.w) / 2; + view.y = 0; + } else { + // pillarboxing + view.h = cam.screen.x / viewport_aspect; + view.w = cam.screen.x / cam.zoom; + view.x = 0; + view.y = (cam.screen.y - view.h) / 2; + } + // set drawing area + SDL_RenderSetViewport(this->game_renderer.get(), &view); -void SDLContext::set_camera(const Camera & cam) { - this->viewport.w = static_cast<int>(cam.aspect_width); - this->viewport.h = static_cast<int>(cam.aspect_height); - this->viewport.x = static_cast<int>(cam.x) - (this->viewport.w / 2); - this->viewport.y = static_cast<int>(cam.y) - (this->viewport.h / 2); + SDL_RenderSetLogicalSize(this->game_renderer.get(), static_cast<int>(cam.viewport_size.x), + static_cast<int>(cam.viewport_size.y)); + // set bg color SDL_SetRenderDrawColor(this->game_renderer.get(), cam.bg_color.r, cam.bg_color.g, cam.bg_color.b, cam.bg_color.a); + + SDL_Rect bg = { + .x = 0, + .y = 0, + .w = static_cast<int>(cam.viewport_size.x), + .h = static_cast<int>(cam.viewport_size.y), + }; + // fill bg color + SDL_RenderFillRect(this->game_renderer.get(), &bg); } uint64_t SDLContext::get_ticks() const { return SDL_GetTicks64(); } diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index 20e30b3..6030a6e 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -9,9 +9,8 @@ #include <memory> #include <string> +#include "../api/Camera.h" #include "../api/Sprite.h" -#include "../api/Transform.h" -#include "api/Camera.h" #include "types.h" @@ -29,6 +28,15 @@ typedef SDL_Keycode CREPE_KEYCODES; * event handling, and rendering to the screen. It is never used directly by the user */ class SDLContext { +public: + struct RenderContext { + const Sprite & sprite; + const Camera & cam; + const vec2 & cam_pos; + const vec2 & pos; + const double & angle; + const double & scale; + }; public: /** @@ -100,14 +108,14 @@ private: * \param texture Reference to the Texture object. * \return Width of the texture as an integer. */ - int get_width(const Texture &) const; + int get_width(const Texture & texture) const; /** * \brief Gets the height of a texture. * \param texture Reference to the Texture object. * \return Height of the texture as an integer. */ - int get_height(const Texture &) const; + int get_height(const Texture & texture) const; private: //! Will use draw,clear_screen, present_screen, camera. @@ -115,14 +123,9 @@ private: /** * \brief Draws a sprite to the screen using the specified transform and camera. - * \param sprite Reference to the Sprite to draw. - * \param transform Reference to the Transform for positioning. - * \param camera Reference to the Camera for view adjustments. + * \param RenderCtx Reference to rendering data to draw */ - void draw(const Sprite & sprite, const Transform & transform, const Camera & camera); - - void draw_particle(const Sprite & sprite, const vec2 & pos, const double & angle, - const double & scale, const Camera & camera); + void draw(const RenderContext & ctx); //! Clears the screen, preparing for a new frame. void clear_screen(); @@ -144,18 +147,19 @@ private: * \return sdl rectangle to draw a src image */ SDL_Rect get_src_rect(const Sprite & sprite) const; + /** - * \brief calculates the sqaure size of the image for an destination + * \brief calculates the sqaure size of the image for destination * - * \param sprite Reference to the sprite to calculate the rectangle - * \param pos the pos in pixel positions - * \param scale the multiplier to increase of decrease for the specified sprite - * \param cam Reference to the current camera in the scene to calculate the position based - * on the camera + * \param sprite Reference to the sprite to calculate rectangle + * \param pos the pos in world units + * \param cam the camera of the current scene + * \param cam_pos the current postion of the camera + * \param img_scale the image multiplier for increasing img size * \return sdl rectangle to draw a dst image to draw on the screen */ - SDL_Rect get_dst_rect(const Sprite & sprite, const vec2 & pos, const double & scale, - const Camera & cam) const; + SDL_Rect get_dst_rect(const Sprite & sprite, const vec2 & pos, const Camera & cam, + const vec2 & cam_pos, const double & img_scale) const; private: //! sdl Window @@ -163,9 +167,6 @@ private: //! renderer for the crepe engine std::unique_ptr<SDL_Renderer, std::function<void(SDL_Renderer *)>> game_renderer; - - //! viewport for the camera window - SDL_Rect viewport = {0, 0, 640, 480}; }; } // namespace crepe diff --git a/src/crepe/manager/CMakeLists.txt b/src/crepe/manager/CMakeLists.txt new file mode 100644 index 0000000..480c8ee --- /dev/null +++ b/src/crepe/manager/CMakeLists.txt @@ -0,0 +1,23 @@ +target_sources(crepe PUBLIC + ComponentManager.cpp + EventManager.cpp + Manager.cpp + SaveManager.cpp + SceneManager.cpp + ResourceManager.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 + ResourceManager.h + ResourceManager.hpp +) + diff --git a/src/crepe/manager/ComponentManager.cpp b/src/crepe/manager/ComponentManager.cpp new file mode 100644 index 0000000..5a96158 --- /dev/null +++ b/src/crepe/manager/ComponentManager.cpp @@ -0,0 +1,63 @@ +#include "../api/GameObject.h" +#include "../util/Log.h" +#include "../types.h" + +#include "ComponentManager.h" + +using namespace crepe; +using namespace std; + +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) { + // Do not delete persistent objects + if (this->persistent[id]) { + return; + } + + // Loop through all the types (in the unordered_map<>) + for (auto & [type, component_array] : this->components) { + // Make sure that the id (that we are looking for) is within the boundaries of the vector<> + if (id < component_array.size()) { + // Clear the components at this specific id + component_array[id].clear(); + } + } +} + +void ComponentManager::delete_all_components() { + // Loop through all the types (in the unordered_map<>) + for (auto & [type, component_array] : this->components) { + // Loop through all the ids (in the vector<>) + for (game_object_id_t id = 0; id < component_array.size(); id++) { + // Do not delete persistent objects + if (!this->persistent[id]) { + // Clear the components at this specific id + component_array[id].clear(); + } + } + } + + this->next_id = 0; +} + +GameObject ComponentManager::new_object(const string & name, const string & tag, + const vec2 & position, double rotation, double scale) { + // Find the first available id (taking persistent objects into account) + while (this->persistent[this->next_id]) { + this->next_id++; + } + + GameObject object{*this, this->next_id, name, tag, position, rotation, scale}; + this->next_id++; + + return object; +} + +void ComponentManager::set_persistent(game_object_id_t id, bool persistent) { + this->persistent[id] = persistent; +} diff --git a/src/crepe/ComponentManager.h b/src/crepe/manager/ComponentManager.h index 1cb0b5f..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 /** @@ -99,6 +101,16 @@ protected: * This method deletes all components. */ void delete_all_components(); + /** + * \brief Set a GameObject as persistent + * + * This method sets a GameObject as persistent. If a GameObject is persistent, its + * components will not be deleted. + * + * \param id The id of the GameObject to set as persistent + * \param persistent The persistent flag + */ + void set_persistent(game_object_id_t id, bool persistent); public: /** @@ -137,6 +149,9 @@ private: std::unordered_map<std::type_index, std::vector<std::vector<std::unique_ptr<Component>>>> components; + //! Persistent flag for each GameObject + std::unordered_map<game_object_id_t, bool> persistent; + //! ID of next GameObject allocated by \c ComponentManager::new_object game_object_id_t next_id = 0; }; diff --git a/src/crepe/ComponentManager.hpp b/src/crepe/manager/ComponentManager.hpp index 4d5eaf4..ffb38ec 100644 --- a/src/crepe/ComponentManager.hpp +++ b/src/crepe/manager/ComponentManager.hpp @@ -54,6 +54,11 @@ template <typename T> void ComponentManager::delete_components_by_id(game_object_id_t id) { using namespace std; + // Do not delete persistent objects + if (this->persistent[id]) { + return; + } + // Determine the type of T (this is used as the key of the unordered_map<>) type_index type = typeid(T); @@ -77,7 +82,13 @@ void ComponentManager::delete_components() { if (this->components.find(type) == this->components.end()) return; - this->components[type].clear(); + // Loop through the whole vector<> of this specific type + for (game_object_id_t i = 0; i < this->components[type].size(); ++i) { + // Do not delete persistent objects + if (!this->persistent[i]) { + this->components[type][i].clear(); + } + } } template <typename T> 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..fe7c936 --- /dev/null +++ b/src/crepe/manager/Manager.cpp @@ -0,0 +1,6 @@ +#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..9adfd0b --- /dev/null +++ b/src/crepe/manager/Manager.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Mediator.h" + +namespace crepe { + +class Manager { +public: + Manager(Mediator & mediator); + virtual ~Manager() = default; + +protected: + Mediator & mediator; +}; + +} + diff --git a/src/crepe/manager/Mediator.h b/src/crepe/manager/Mediator.h new file mode 100644 index 0000000..475aed9 --- /dev/null +++ b/src/crepe/manager/Mediator.h @@ -0,0 +1,35 @@ +#pragma once + +#include "../util/OptionalRef.h" + +// TODO: remove these singletons: +#include "SaveManager.h" +#include "EventManager.h" + +namespace crepe { + +class ComponentManager; +class SceneManager; +class ResourceManager; + +/** + * 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<ResourceManager> resource_manager; +}; + +} diff --git a/src/crepe/ResourceManager.cpp b/src/crepe/manager/ResourceManager.cpp index 8b1fbf5..87585ad 100644 --- a/src/crepe/ResourceManager.cpp +++ b/src/crepe/manager/ResourceManager.cpp @@ -5,8 +5,11 @@ using namespace crepe; using namespace std; +ResourceManager::ResourceManager(Mediator & mediator) : Manager(mediator) { + mediator.resource_manager = *this; + dbg_trace(); +} ResourceManager::~ResourceManager() { dbg_trace(); } -ResourceManager::ResourceManager() { dbg_trace(); } void ResourceManager::clear() { std::erase_if(this->resources, [](const pair<const Asset, CacheEntry> & pair) { diff --git a/src/crepe/ResourceManager.h b/src/crepe/manager/ResourceManager.h index fc50b65..e7e6abc 100644 --- a/src/crepe/ResourceManager.h +++ b/src/crepe/manager/ResourceManager.h @@ -3,9 +3,10 @@ #include <memory> #include <unordered_map> -#include "api/Asset.h" +#include "../Resource.h" +#include "../api/Asset.h" -#include "Resource.h" +#include "Manager.h" namespace crepe { @@ -18,9 +19,9 @@ namespace crepe { * a scene is loaded. Assets are retained in memory until the ResourceManager is * destroyed, at which point the cached assets are cleared. */ -class ResourceManager { +class ResourceManager : public Manager { public: - ResourceManager(); // dbg_trace + ResourceManager(Mediator & mediator); virtual ~ResourceManager(); // dbg_trace private: diff --git a/src/crepe/ResourceManager.hpp b/src/crepe/manager/ResourceManager.hpp index 8270bc5..8270bc5 100644 --- a/src/crepe/ResourceManager.hpp +++ b/src/crepe/manager/ResourceManager.hpp diff --git a/src/crepe/api/SaveManager.cpp b/src/crepe/manager/SaveManager.cpp index c5f43ea..121d017 100644 --- a/src/crepe/api/SaveManager.cpp +++ b/src/crepe/manager/SaveManager.cpp @@ -1,9 +1,9 @@ #include "../facade/DB.h" #include "../util/Log.h" +#include "../api/Config.h" +#include "../ValueBroker.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 676e485..8bb6465 100644 --- a/src/crepe/system/AnimatorSystem.cpp +++ b/src/crepe/system/AnimatorSystem.cpp @@ -1,24 +1,24 @@ #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>(); uint64_t tick = SDLContext::get_instance().get_ticks(); for (Animator & a : animations) { - if (a.active) { - a.curr_row = (tick / 100) % a.row; - a.animator_rect.x = (a.curr_row * a.animator_rect.w) + a.curr_col; - a.spritesheet.sprite_rect = a.animator_rect; - } + if (!a.active) continue; + // (10 frames per second) + a.curr_row = (tick / 100) % a.row; + a.spritesheet.mask.x = (a.curr_row * a.spritesheet.mask.w) + a.curr_col; + a.spritesheet.mask = a.spritesheet.mask; } } diff --git a/src/crepe/system/AnimatorSystem.h b/src/crepe/system/AnimatorSystem.h index 56cc7b3..f8179a9 100644 --- a/src/crepe/system/AnimatorSystem.h +++ b/src/crepe/system/AnimatorSystem.h @@ -21,12 +21,11 @@ public: /** * \brief Updates the Animator components. * - * This method is called periodically (likely every frame) to update the state of all + * This method is called to update the state of all * Animator components, moving the animations forward and managing their behavior (e.g., * looping). */ void update() override; - // FIXME: never say "likely" in the documentation lmao }; } // namespace crepe diff --git a/src/crepe/system/AudioSystem.cpp b/src/crepe/system/AudioSystem.cpp index f90132a..97cf966 100644 --- a/src/crepe/system/AudioSystem.cpp +++ b/src/crepe/system/AudioSystem.cpp @@ -1,20 +1,23 @@ #include "AudioSystem.h" -#include "ComponentManager.h" #include "../api/AudioSource.h" +#include "../manager/ComponentManager.h" +#include "../manager/ResourceManager.h" +#include "../types.h" using namespace crepe; using namespace std; void AudioSystem::update() { - ComponentManager & mgr = this->component_manager; - vector<reference_wrapper<AudioSource>> components = mgr.get_components_by_type<AudioSource>(); + ComponentManager & component_manager = this->mediator.component_manager; + ResourceManager & resource_manager = this->mediator.resource_manager; + RefVector<AudioSource> components = component_manager.get_components_by_type<AudioSource>(); for (auto component_ref : components) { AudioSource & component = component_ref.get(); if (!component.active) continue; - Sound & sound = this->resource_manager.get<Sound>(component.source); + Sound & sound = resource_manager.get<Sound>(component.source); // TODO: lots of state diffing } } diff --git a/src/crepe/system/AudioSystem.h b/src/crepe/system/AudioSystem.h index d3d5aeb..e037f51 100644 --- a/src/crepe/system/AudioSystem.h +++ b/src/crepe/system/AudioSystem.h @@ -1,7 +1,6 @@ #pragma once #include "../facade/SoundContext.h" -#include "../ResourceManager.h" #include "System.h" @@ -14,7 +13,6 @@ public: private: SoundContext context {}; - ResourceManager resource_manager {}; }; } // namespace crepe 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..eba9dfa 100644 --- a/src/crepe/system/PhysicsSystem.cpp +++ b/src/crepe/system/PhysicsSystem.cpp @@ -1,6 +1,6 @@ #include <cmath> -#include "../ComponentManager.h" +#include "../manager/ComponentManager.h" #include "../api/Config.h" #include "../api/Rigidbody.h" #include "../api/Transform.h" @@ -11,7 +11,7 @@ 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 ad510f5..4e97b3e 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -2,15 +2,14 @@ #include <cassert> #include <cmath> #include <functional> -#include <iostream> #include <stdexcept> #include <vector> -#include "../ComponentManager.h" +#include "../manager/ComponentManager.h" +#include "../api/Camera.h" #include "../api/ParticleEmitter.h" #include "../api/Sprite.h" #include "../api/Transform.h" -#include "../api/Vector2.h" #include "../facade/SDLContext.h" #include "RenderSystem.h" @@ -21,8 +20,9 @@ using namespace std; void RenderSystem::clear_screen() { this->context.clear_screen(); } void RenderSystem::present_screen() { this->context.present_screen(); } -void RenderSystem::update_camera() { - ComponentManager & mgr = this->component_manager; + +const Camera & RenderSystem::update_camera() { + ComponentManager & mgr = this->mediator.component_manager; RefVector<Camera> cameras = mgr.get_components_by_type<Camera>(); @@ -30,9 +30,13 @@ void RenderSystem::update_camera() { for (Camera & cam : cameras) { if (!cam.active) continue; + const Transform & transform + = mgr.get_components_by_id<Transform>(cam.game_object_id).front().get(); this->context.set_camera(cam); - this->curr_cam_ref = &cam; + this->cam_pos = transform.position + cam.offset; + return cam; } + throw std::runtime_error("No active cameras in current scene"); } bool sorting_comparison(const Sprite & a, const Sprite & b) { @@ -51,14 +55,14 @@ RefVector<Sprite> RenderSystem::sort(RefVector<Sprite> & objs) const { void RenderSystem::update() { this->clear_screen(); - this->update_camera(); this->render(); this->present_screen(); } -bool RenderSystem::render_particle(const Sprite & sprite, const double & scale) { +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); @@ -72,19 +76,35 @@ bool RenderSystem::render_particle(const Sprite & sprite, const double & scale) for (const Particle & p : em.data.particles) { if (!p.active) continue; - this->context.draw_particle(sprite, p.position, p.angle, scale, - *this->curr_cam_ref); + + this->context.draw(SDLContext::RenderContext{ + .sprite = sprite, + .cam = cam, + .cam_pos = this->cam_pos, + .pos = p.position, + .angle = p.angle, + .scale = scale, + }); } } return rendering_particles; } -void RenderSystem::render_normal(const Sprite & sprite, const Transform & tm) { - this->context.draw(sprite, tm, *this->curr_cam_ref); +void RenderSystem::render_normal(const Sprite & sprite, const Camera & cam, + const Transform & tm) { + this->context.draw(SDLContext::RenderContext{ + .sprite = sprite, + .cam = cam, + .cam_pos = this->cam_pos, + .pos = tm.position, + .angle = tm.rotation, + .scale = tm.scale, + }); } void RenderSystem::render() { + ComponentManager & mgr = this->mediator.component_manager; + const Camera & cam = this->update_camera(); - ComponentManager & mgr = this->component_manager; RefVector<Sprite> sprites = mgr.get_components_by_type<Sprite>(); RefVector<Sprite> sorted_sprites = this->sort(sprites); @@ -93,10 +113,10 @@ void RenderSystem::render() { const Transform & transform = mgr.get_components_by_id<Transform>(sprite.game_object_id).front().get(); - bool rendered_particles = this->render_particle(sprite, transform.scale); + bool rendered_particles = this->render_particle(sprite, cam, transform.scale); if (rendered_particles) continue; - this->render_normal(sprite, transform); + this->render_normal(sprite, cam, transform); } } diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h index 30b41cf..e70831e 100644 --- a/src/crepe/system/RenderSystem.h +++ b/src/crepe/system/RenderSystem.h @@ -1,17 +1,17 @@ #pragma once -#include <functional> -#include <vector> +#include <cmath> #include "facade/SDLContext.h" #include "System.h" -#include <cmath> +#include "types.h" namespace crepe { class Camera; class Sprite; +class Transform; /** * \class RenderSystem @@ -37,7 +37,7 @@ private: void present_screen(); //! Updates the active camera used for rendering. - void update_camera(); + const Camera & update_camera(); //! Renders the whole screen void render(); @@ -49,7 +49,7 @@ private: * \param tm the Transform component for scale * \return true if particles have been rendered */ - bool render_particle(const Sprite & sprite, const double & scale); + bool render_particle(const Sprite & sprite, const Camera & cam, const double & scale); /** * \brief renders a sprite with a Transform component on the screen @@ -57,7 +57,7 @@ private: * \param sprite the sprite component that holds all the data * \param tm the Transform component that holds the position,rotation and scale */ - void render_normal(const Sprite & sprite, const Transform & tm); + void render_normal(const Sprite & sprite, const Camera & cam, const Transform & tm); /** * \brief sort a vector sprite objects with @@ -71,17 +71,14 @@ private: * \todo Include color handling for sprites. * \todo Add text rendering using SDL_ttf for text components. * \todo Implement a text component and a button component. - * \todo Ensure each sprite is checked for active status before rendering. - * \todo Sort all layers by order before rendering. * \todo Consider adding text input functionality. */ private: - //! Pointer to the current active camera for rendering - Camera * curr_cam_ref = nullptr; - // TODO: needs a better solution - SDLContext & context = SDLContext::get_instance(); + + //! camera postion in the current scene + vec2 cam_pos; }; } // namespace crepe diff --git a/src/crepe/system/ScriptSystem.cpp b/src/crepe/system/ScriptSystem.cpp index 20a83f7..2e16eb0 100644 --- a/src/crepe/system/ScriptSystem.cpp +++ b/src/crepe/system/ScriptSystem.cpp @@ -1,4 +1,4 @@ -#include "../ComponentManager.h" +#include "../manager/ComponentManager.h" #include "../api/BehaviorScript.h" #include "../api/Script.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..4e7fc6d 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; @@ -19,11 +21,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/crepe/types.h b/src/crepe/types.h index 17f1619..69cc526 100644 --- a/src/crepe/types.h +++ b/src/crepe/types.h @@ -27,4 +27,4 @@ typedef Vector2<float> vec2; //! Default Vector2<double> type typedef Vector2<double> dvec2; -} // namespace crepe +}; // namespace crepe diff --git a/src/example/rendering_particle.cpp b/src/example/rendering_particle.cpp index b38e860..3a12144 100644 --- a/src/example/rendering_particle.cpp +++ b/src/example/rendering_particle.cpp @@ -1,6 +1,7 @@ +#include "api/Animator.h" #include "api/Camera.h" +#include "system/AnimatorSystem.h" #include "system/ParticleSystem.h" -#include "types.h" #include <SDL2/SDL_timer.h> #include <crepe/ComponentManager.h> @@ -12,28 +13,31 @@ #include <crepe/api/Sprite.h> #include <crepe/api/Texture.h> #include <crepe/api/Transform.h> -#include <crepe/api/Vector2.h> #include <crepe/system/RenderSystem.h> +#include <crepe/types.h> #include <chrono> -#include <iostream> -#include <memory> using namespace crepe; using namespace std; int main(int argc, char * argv[]) { ComponentManager mgr; - GameObject game_object = mgr.new_object("", "", vec2{0, 0}, 0, 0.1); + GameObject game_object = mgr.new_object("", "", vec2{0, 0}, 0, 1); RenderSystem sys{mgr}; ParticleSystem psys{mgr}; + AnimatorSystem asys{mgr}; Color color(255, 255, 255, 255); + auto img = Texture("asset/texture/test_ap43.png"); Sprite & test_sprite = game_object.add_component<Sprite>( - make_shared<Texture>("asset/texture/img.png"), color, FlipSettings{false, false}); - test_sprite.order_in_layer = 5; + img, color, Sprite::FlipSettings{true, true}, 1, 1, 500); + //game_object.add_component<Animator>(test_sprite, 4, 1, 0).active = true; + game_object.add_component<Animator>(test_sprite, 1, 1, 0).active = true; + + /* auto & test = game_object.add_component<ParticleEmitter>(ParticleEmitter::Data{ .position = {0, 0}, .max_particles = 10, @@ -53,17 +57,24 @@ int main(int argc, char * argv[]) { }, .sprite = test_sprite, }); - game_object.add_component<Camera>(Color::WHITE); + */ + + auto & cam = game_object.add_component<Camera>(Color::WHITE, ivec2{1080, 720}, + vec2{2000, 2000}, 1.0f); + /* game_object .add_component<Sprite>(make_shared<Texture>("asset/texture/img.png"), color, + .add_component<Sprite>(make_shared<Texture>("asset/texture/img.png"), color, FlipSettings{false, false}) .order_in_layer = 6; + */ auto start = std::chrono::steady_clock::now(); while (std::chrono::steady_clock::now() - start < std::chrono::seconds(5)) { psys.update(); + asys.update(); sys.update(); SDL_Delay(10); } diff --git a/src/test/AudioTest.cpp b/src/test/AudioTest.cpp index e181de9..afd2672 100644 --- a/src/test/AudioTest.cpp +++ b/src/test/AudioTest.cpp @@ -1,6 +1,6 @@ #include <gtest/gtest.h> -#include <crepe/ComponentManager.h> +#include <crepe/manager/ComponentManager.h> #include <crepe/api/AudioSource.h> #include <crepe/api/GameObject.h> #include <crepe/system/AudioSystem.h> @@ -10,9 +10,10 @@ using namespace crepe; using namespace testing; class AudioTest : public Test { + Mediator mediator; public: - ComponentManager component_manager{}; - AudioSystem system {component_manager}; + ComponentManager component_manager{mediator}; + AudioSystem system {mediator}; void SetUp() override { auto & mgr = this->component_manager; diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index b67baad..4174926 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -14,4 +14,6 @@ target_sources(test_main PUBLIC ValueBrokerTest.cpp DBTest.cpp Vector2Test.cpp + ScriptEventTest.cpp + ScriptSceneTest.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 80b936b..22c4fe7 100644 --- a/src/test/ECSTest.cpp +++ b/src/test/ECSTest.cpp @@ -2,7 +2,7 @@ #define protected public -#include <crepe/ComponentManager.h> +#include <crepe/manager/ComponentManager.h> #include <crepe/api/GameObject.h> #include <crepe/api/Metadata.h> #include <crepe/api/Transform.h> @@ -12,8 +12,9 @@ using namespace std; using namespace crepe; class ECSTest : public ::testing::Test { + Mediator m; public: - ComponentManager mgr{}; + ComponentManager mgr{m}; }; TEST_F(ECSTest, createGameObject) { @@ -136,6 +137,53 @@ TEST_F(ECSTest, manyGameObjects) { EXPECT_EQ(metadata.size(), 10000 - 5000); EXPECT_EQ(transform.size(), 10000); + + for (int i = 0; i < 10000 - 5000; i++) { + EXPECT_EQ(metadata[i].get().game_object_id, i + 5000); + EXPECT_EQ(metadata[i].get().name, "body"); + EXPECT_EQ(metadata[i].get().tag, "person" + to_string(i)); + EXPECT_EQ(metadata[i].get().parent, -1); + EXPECT_EQ(metadata[i].get().children.size(), 0); + + EXPECT_EQ(transform[i].get().game_object_id, i); + EXPECT_EQ(transform[i].get().position.x, 0); + EXPECT_EQ(transform[i].get().position.y, 0); + EXPECT_EQ(transform[i].get().rotation, 0); + EXPECT_EQ(transform[i].get().scale, i); + } + + mgr.delete_all_components(); + + metadata = mgr.get_components_by_type<Metadata>(); + transform = mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 0); + EXPECT_EQ(transform.size(), 0); + + for (int i = 0; i < 10000; i++) { + string name = "body" + to_string(i); + GameObject obj = mgr.new_object(name, "person", vec2{0, 0}, 0, 0); + } + + metadata = mgr.get_components_by_type<Metadata>(); + transform = mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 10000); + EXPECT_EQ(transform.size(), 10000); + + for (int i = 0; i < 10000; i++) { + EXPECT_EQ(metadata[i].get().game_object_id, i); + EXPECT_EQ(metadata[i].get().name, "body" + to_string(i)); + EXPECT_EQ(metadata[i].get().tag, "person"); + EXPECT_EQ(metadata[i].get().parent, -1); + EXPECT_EQ(metadata[i].get().children.size(), 0); + + EXPECT_EQ(transform[i].get().game_object_id, i); + EXPECT_EQ(transform[i].get().position.x, 0); + EXPECT_EQ(transform[i].get().position.y, 0); + EXPECT_EQ(transform[i].get().rotation, 0); + EXPECT_EQ(transform[i].get().scale, 0); + } } TEST_F(ECSTest, getComponentsByID) { @@ -234,3 +282,107 @@ TEST_F(ECSTest, partentChild) { EXPECT_EQ(metadata[1].get().children[0], 3); EXPECT_EQ(metadata[2].get().children[0], 4); } + +TEST_F(ECSTest, persistent) { + GameObject obj0 = mgr.new_object("obj0", "obj0", vec2{0, 0}, 0, 1); + GameObject obj1 = mgr.new_object("obj1", "obj1", vec2{0, 0}, 0, 1); + obj1.set_persistent(); + GameObject obj2 = mgr.new_object("obj2", "obj2", vec2{0, 0}, 0, 1); + + vector<reference_wrapper<Metadata>> metadata = mgr.get_components_by_type<Metadata>(); + vector<reference_wrapper<Transform>> transform = mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 3); + EXPECT_EQ(transform.size(), 3); + + mgr.delete_components_by_id<Metadata>(1); + mgr.delete_components<Metadata>(); + mgr.delete_all_components_of_id(1); + + metadata = mgr.get_components_by_type<Metadata>(); + transform = mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 1); + EXPECT_EQ(transform.size(), 3); + + mgr.delete_all_components(); + + metadata = mgr.get_components_by_type<Metadata>(); + transform = mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 1); + EXPECT_EQ(transform.size(), 1); + + EXPECT_EQ(metadata[0].get().game_object_id, 1); + EXPECT_EQ(metadata[0].get().name, "obj1"); + EXPECT_EQ(metadata[0].get().tag, "obj1"); + EXPECT_EQ(metadata[0].get().parent, -1); + EXPECT_EQ(metadata[0].get().children.size(), 0); + + EXPECT_EQ(transform[0].get().game_object_id, 1); + EXPECT_EQ(transform[0].get().position.x, 0); + EXPECT_EQ(transform[0].get().position.y, 0); + + GameObject obj3 = mgr.new_object("obj3", "obj3", vec2{0, 0}, 0, 5); + GameObject obj4 = mgr.new_object("obj4", "obj4", vec2{0, 0}, 0, 5); + + metadata = mgr.get_components_by_type<Metadata>(); + transform = mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 3); + EXPECT_EQ(transform.size(), 3); + + EXPECT_EQ(metadata[0].get().game_object_id, 0); + EXPECT_EQ(metadata[0].get().name, "obj3"); + + EXPECT_EQ(metadata[1].get().game_object_id, 1); + EXPECT_EQ(metadata[1].get().name, "obj1"); + + EXPECT_EQ(metadata[2].get().game_object_id, 2); + EXPECT_EQ(metadata[2].get().name, "obj4"); + + EXPECT_EQ(transform[0].get().game_object_id, 0); + EXPECT_EQ(transform[0].get().scale, 5); + + EXPECT_EQ(transform[1].get().game_object_id, 1); + EXPECT_EQ(transform[1].get().scale, 1); + + EXPECT_EQ(transform[2].get().game_object_id, 2); + EXPECT_EQ(transform[2].get().scale, 5); +} + +TEST_F(ECSTest, resetPersistent) { + GameObject obj0 = mgr.new_object("obj0", "obj0", vec2{0, 0}, 0, 1); + GameObject obj1 = mgr.new_object("obj1", "obj1", vec2{0, 0}, 0, 1); + obj1.set_persistent(); + GameObject obj2 = mgr.new_object("obj2", "obj2", vec2{0, 0}, 0, 1); + + vector<reference_wrapper<Metadata>> metadata = mgr.get_components_by_type<Metadata>(); + vector<reference_wrapper<Transform>> transform = mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 3); + EXPECT_EQ(transform.size(), 3); + + mgr.delete_all_components(); + + metadata = mgr.get_components_by_type<Metadata>(); + transform = mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 1); + EXPECT_EQ(transform.size(), 1); + + vector<reference_wrapper<Metadata>> metadata_id = mgr.get_components_by_id<Metadata>(1); + + EXPECT_EQ(metadata_id.size(), 1); + EXPECT_EQ(metadata_id[0].get().game_object_id, 1); + EXPECT_EQ(metadata_id[0].get().name, "obj1"); + + mgr.set_persistent(1, false); + mgr.delete_all_components(); + + metadata = mgr.get_components_by_type<Metadata>(); + transform = mgr.get_components_by_type<Transform>(); + + EXPECT_EQ(metadata.size(), 0); + EXPECT_EQ(transform.size(), 0); +} diff --git a/src/test/EventTest.cpp b/src/test/EventTest.cpp index a21a851..350dd07 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/manager/EventManager.h> +#include <crepe/api/IKeyListener.h> +#include <crepe/api/IMouseListener.h> + using namespace std; using namespace std::chrono_literals; using namespace crepe; diff --git a/src/test/ParticleTest.cpp b/src/test/ParticleTest.cpp index 8b81e74..4e9fa4e 100644 --- a/src/test/ParticleTest.cpp +++ b/src/test/ParticleTest.cpp @@ -1,11 +1,11 @@ -#include "api/Vector2.h" -#include <crepe/ComponentManager.h> +#include <crepe/manager/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/system/ParticleSystem.h> #include <gtest/gtest.h> @@ -16,9 +16,10 @@ 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; @@ -28,9 +29,9 @@ public: GameObject game_object = mgr.new_object("", "", vec2{0, 0}, 0, 0); Color color(0, 0, 0, 0); + auto s1 = Texture("asset/texture/img.png"); Sprite & test_sprite = game_object.add_component<Sprite>( - make_shared<Texture>("asset/texture/img.png"), color, - FlipSettings{true, true}); + s1, color, Sprite::FlipSettings{true, true}, 1, 1, 100); game_object.add_component<ParticleEmitter>(ParticleEmitter::Data{ .position = {0, 0}, diff --git a/src/test/PhysicsTest.cpp b/src/test/PhysicsTest.cpp index 33b6020..01b7c51 100644 --- a/src/test/PhysicsTest.cpp +++ b/src/test/PhysicsTest.cpp @@ -1,4 +1,4 @@ -#include <crepe/ComponentManager.h> +#include <crepe/manager/ComponentManager.h> #include <crepe/api/Config.h> #include <crepe/api/GameObject.h> #include <crepe/api/Rigidbody.h> @@ -11,9 +11,10 @@ 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 f37fb56..3528e46 100644 --- a/src/test/RenderSystemTest.cpp +++ b/src/test/RenderSystemTest.cpp @@ -1,4 +1,3 @@ -#include "api/Camera.h" #include <functional> #include <gtest/gtest.h> #include <memory> @@ -7,7 +6,8 @@ #define private public #define protected public -#include <crepe/ComponentManager.h> +#include <crepe/api/Camera.h> +#include <crepe/manager/ComponentManager.h> #include <crepe/api/Color.h> #include <crepe/api/GameObject.h> #include <crepe/api/Sprite.h> @@ -20,49 +20,40 @@ 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"); GameObject entity4 = this->mgr.new_object("name"); void SetUp() override { - auto & sprite1 - = entity1.add_component<Sprite>(make_shared<Texture>("asset/texture/img.png"), - Color(0, 0, 0, 0), FlipSettings{false, false}); - ASSERT_NE(sprite1.sprite_image.get(), nullptr); - sprite1.order_in_layer = 5; - sprite1.sorting_in_layer = 5; + auto s1 = Texture("asset/texture/img.png"); + auto s2 = Texture("asset/texture/img.png"); + auto s3 = Texture("asset/texture/img.png"); + auto s4 = Texture("asset/texture/img.png"); + auto & sprite1 = entity1.add_component<Sprite>( + s1, Color(0, 0, 0, 0), Sprite::FlipSettings{false, false}, 5, 5, 100); + ASSERT_NE(sprite1.sprite_image.texture.get(), nullptr); EXPECT_EQ(sprite1.order_in_layer, 5); EXPECT_EQ(sprite1.sorting_in_layer, 5); - auto & sprite2 - = entity2.add_component<Sprite>(make_shared<Texture>("asset/texture/img.png"), - Color(0, 0, 0, 0), FlipSettings{false, false}); - ASSERT_NE(sprite2.sprite_image.get(), nullptr); - sprite2.sorting_in_layer = 2; - sprite2.order_in_layer = 1; - + auto & sprite2 = entity2.add_component<Sprite>( + s2, Color(0, 0, 0, 0), Sprite::FlipSettings{false, false}, 2, 1, 100); + ASSERT_NE(sprite2.sprite_image.texture.get(), nullptr); EXPECT_EQ(sprite2.sorting_in_layer, 2); EXPECT_EQ(sprite2.order_in_layer, 1); - auto & sprite3 - = entity3.add_component<Sprite>(make_shared<Texture>("asset/texture/img.png"), - Color(0, 0, 0, 0), FlipSettings{false, false}); - ASSERT_NE(sprite3.sprite_image.get(), nullptr); - sprite3.sorting_in_layer = 1; - sprite3.order_in_layer = 2; - + auto & sprite3 = entity3.add_component<Sprite>( + s3, Color(0, 0, 0, 0), Sprite::FlipSettings{false, false}, 1, 2, 100); + ASSERT_NE(sprite3.sprite_image.texture.get(), nullptr); EXPECT_EQ(sprite3.sorting_in_layer, 1); EXPECT_EQ(sprite3.order_in_layer, 2); - auto & sprite4 - = entity4.add_component<Sprite>(make_shared<Texture>("asset/texture/img.png"), - Color(0, 0, 0, 0), FlipSettings{false, false}); - ASSERT_NE(sprite4.sprite_image.get(), nullptr); - sprite4.sorting_in_layer = 1; - sprite4.order_in_layer = 1; + auto & sprite4 = entity4.add_component<Sprite>( + s4, Color(0, 0, 0, 0), Sprite::FlipSettings{false, false}, 1, 1, 100); + ASSERT_NE(sprite4.sprite_image.texture.get(), nullptr); EXPECT_EQ(sprite4.sorting_in_layer, 1); EXPECT_EQ(sprite4.order_in_layer, 1); } @@ -73,8 +64,9 @@ TEST_F(RenderSystemTest, expected_throws) { // no texture img EXPECT_ANY_THROW({ - entity1.add_component<Sprite>(make_shared<Texture>("NO_IMAGE"), Color(0, 0, 0, 0), - FlipSettings{false, false}); + auto test = Texture(""); + entity1.add_component<Sprite>(test, Color(0, 0, 0, 0), + Sprite::FlipSettings{false, false}, 1, 1, 100); }); // No camera @@ -121,7 +113,7 @@ TEST_F(RenderSystemTest, sorting_sprites) { } TEST_F(RenderSystemTest, Update) { - entity1.add_component<Camera>(Color::WHITE); + entity1.add_component<Camera>(Color::WHITE, ivec2{1080, 720}, vec2{2000, 2000}, 1.0f); { vector<reference_wrapper<Sprite>> sprites = this->mgr.get_components_by_type<Sprite>(); ASSERT_EQ(sprites.size(), 4); @@ -149,7 +141,7 @@ TEST_F(RenderSystemTest, Camera) { EXPECT_NE(cameras.size(), 1); } { - entity1.add_component<Camera>(Color::WHITE); + entity1.add_component<Camera>(Color::WHITE, ivec2{1080, 720}, vec2{2000, 2000}, 1.0f); auto cameras = this->mgr.get_components_by_type<Camera>(); EXPECT_EQ(cameras.size(), 1); } @@ -157,9 +149,9 @@ TEST_F(RenderSystemTest, Camera) { //TODO improve with newer version } TEST_F(RenderSystemTest, Color) { - entity1.add_component<Camera>(Color::WHITE); + entity1.add_component<Camera>(Color::WHITE, ivec2{1080, 720}, vec2{2000, 2000}, 1.0f); auto & sprite = this->mgr.get_components_by_id<Sprite>(entity1.id).front().get(); - ASSERT_NE(sprite.sprite_image.get(), nullptr); + ASSERT_NE(sprite.sprite_image.texture.get(), nullptr); sprite.color = Color::GREEN; EXPECT_EQ(sprite.color.r, Color::GREEN.r); diff --git a/src/test/ResourceManagerTest.cpp b/src/test/ResourceManagerTest.cpp index cc3b022..1f56e23 100644 --- a/src/test/ResourceManagerTest.cpp +++ b/src/test/ResourceManagerTest.cpp @@ -4,7 +4,7 @@ #define protected public #include <crepe/util/Log.h> -#include <crepe/ResourceManager.h> +#include <crepe/manager/ResourceManager.h> #include <crepe/api/GameObject.h> using namespace std; @@ -12,8 +12,9 @@ using namespace crepe; using namespace testing; class ResourceManagerTest : public Test { + Mediator mediator; public: - ResourceManager resource_manager{}; + ResourceManager resource_manager{mediator}; Asset asset_a{"asset/texture/img.png"}; Asset asset_b{"asset/texture/ERROR.png"}; diff --git a/src/test/SceneManagerTest.cpp b/src/test/SceneManagerTest.cpp index 62b7d33..d027d89 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/types.h> +#include <crepe/manager/SceneManager.h> +#include <crepe/manager/ComponentManager.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> 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,10 @@ 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..7a9abbb --- /dev/null +++ b/src/test/ScriptEventTest.cpp @@ -0,0 +1,51 @@ +#include <gtest/gtest.h> + +// stupid hack to allow access to private/protected members under test +#define private public +#define protected public + +#include <crepe/manager/ComponentManager.h> +#include <crepe/manager/EventManager.h> +#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/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..f96ae8b --- /dev/null +++ b/src/test/ScriptSceneTest.cpp @@ -0,0 +1,31 @@ +#include <gtest/gtest.h> + +// stupid hack to allow access to private/protected members under test +#define private public +#define protected public + +#include <crepe/manager/SceneManager.h> +#include "ScriptTest.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..6d0d5fb 100644 --- a/src/test/ScriptTest.cpp +++ b/src/test/ScriptTest.cpp @@ -1,129 +1,78 @@ #include <gtest/gtest.h> +#include <gmock/gmock.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..9a71ba7 --- /dev/null +++ b/src/test/ScriptTest.h @@ -0,0 +1,29 @@ +#pragma once + +#include <gtest/gtest.h> +#include <gmock/gmock.h> + +#include <crepe/manager/ComponentManager.h> +#include <crepe/system/ScriptSystem.h> +#include <crepe/api/BehaviorScript.h> +#include <crepe/api/Script.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(); +}; |