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(); +};  |