diff options
Diffstat (limited to 'src/crepe/api')
28 files changed, 408 insertions, 352 deletions
| diff --git a/src/crepe/api/Animator.cpp b/src/crepe/api/Animator.cpp index 4ce4bf0..203cef3 100644 --- a/src/crepe/api/Animator.cpp +++ b/src/crepe/api/Animator.cpp @@ -1,5 +1,5 @@ -#include "util/Log.h" +#include "util/dbg.h"  #include "Animator.h"  #include "Component.h" diff --git a/src/crepe/api/BehaviorScript.cpp b/src/crepe/api/BehaviorScript.cpp index d22afdf..af7572c 100644 --- a/src/crepe/api/BehaviorScript.cpp +++ b/src/crepe/api/BehaviorScript.cpp @@ -10,6 +10,6 @@ BehaviorScript::BehaviorScript(game_object_id_t id, Mediator & mediator)  template <>  BehaviorScript & GameObject::add_component<BehaviorScript>() { -	ComponentManager & mgr = this->component_manager; -	return mgr.add_component<BehaviorScript>(this->id, mgr.mediator); +	ComponentManager & mgr = this->mediator.component_manager; +	return mgr.add_component<BehaviorScript>(this->id, this->mediator);  } diff --git a/src/crepe/api/BehaviorScript.hpp b/src/crepe/api/BehaviorScript.hpp index b9bb1e2..353d5e2 100644 --- a/src/crepe/api/BehaviorScript.hpp +++ b/src/crepe/api/BehaviorScript.hpp @@ -2,8 +2,6 @@  #include <type_traits> -#include "../util/Log.h" -  #include "BehaviorScript.h"  #include "Script.h" @@ -11,7 +9,6 @@ namespace crepe {  template <class T, typename... Args>  BehaviorScript & BehaviorScript::set_script(Args &&... args) { -	dbg_trace();  	static_assert(std::is_base_of<Script, T>::value);  	this->script = std::unique_ptr<Script>(new T(std::forward<Args>(args)...)); diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index e8d6f92..2bee3fb 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -13,7 +13,7 @@ target_sources(crepe PUBLIC  	Animator.cpp  	BoxCollider.cpp  	CircleCollider.cpp -	LoopManager.cpp +	Engine.cpp  	Asset.cpp  	EventHandler.cpp  	Script.cpp @@ -47,7 +47,8 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES  	EventHandler.h  	EventHandler.hpp  	Event.h -	LoopManager.h +	Engine.h +	Engine.hpp  	Asset.h  	Button.h  	UIObject.h diff --git a/src/crepe/api/Camera.cpp b/src/crepe/api/Camera.cpp index 179dc18..19a3296 100644 --- a/src/crepe/api/Camera.cpp +++ b/src/crepe/api/Camera.cpp @@ -1,4 +1,4 @@ -#include "util/Log.h" +#include "util/dbg.h"  #include "Camera.h"  #include "Component.h" diff --git a/src/crepe/api/Engine.cpp b/src/crepe/api/Engine.cpp new file mode 100644 index 0000000..2e9d35a --- /dev/null +++ b/src/crepe/api/Engine.cpp @@ -0,0 +1,63 @@ +#include "../util/Log.h" + +#include "Engine.h" + +using namespace crepe; +using namespace std; + +int Engine::main() noexcept { +	try { +		this->setup(); +	} catch (const exception & e) { +		Log::logf(Log::Level::ERROR, "Uncaught exception in setup: {}\n", e.what()); +		return EXIT_FAILURE; +	} + +	try { +		this->loop(); +	} catch (const exception & e) { +		Log::logf(Log::Level::ERROR, "Uncaught exception in main loop: {}\n", e.what()); +		this->event_manager.trigger_event<ShutDownEvent>(); +	} + +	return EXIT_SUCCESS; +} + +void Engine::setup() { +	this->loop_timer.start(); +	this->scene_manager.load_next_scene(); + +	this->event_manager.subscribe<ShutDownEvent>([this](const ShutDownEvent & event) { +		this->game_running = false; + +		// propagate to possible user ShutDownEvent listeners +		return false; +	}); +} + +void Engine::loop() { +	LoopTimerManager & timer = this->loop_timer; +	SystemManager & systems = this->system_manager; + +	while (this->game_running) { +		timer.update(); + +		while (timer.get_lag() >= timer.get_fixed_delta_time()) { +			try { +				systems.fixed_update(); +			} catch (const exception & e) { +				Log::logf(Log::Level::WARNING, +						  "Uncaught exception in fixed update function: {}\n", e.what()); +			} +			timer.advance_fixed_elapsed_time(); +		} + +		try { +			systems.frame_update(); +		} catch (const exception & e) { +			Log::logf(Log::Level::WARNING, "Uncaught exception in frame update function: {}\n", +					  e.what()); +		} +		timer.enforce_frame_rate(); +	} +} diff --git a/src/crepe/api/Engine.h b/src/crepe/api/Engine.h new file mode 100644 index 0000000..700a0cd --- /dev/null +++ b/src/crepe/api/Engine.h @@ -0,0 +1,81 @@ +#pragma once + +#include "../facade/SDLContext.h" +#include "../manager/ComponentManager.h" +#include "../manager/EventManager.h" +#include "../manager/LoopTimerManager.h" +#include "../manager/ReplayManager.h" +#include "../manager/ResourceManager.h" +#include "../manager/SaveManager.h" +#include "../manager/SceneManager.h" +#include "../manager/SystemManager.h" + +namespace crepe { + +/** + * \brief Main game entrypoint + * + * This class is responsible for managing the game loop, including initialization and updating. + */ +class Engine { +public: +	/** +	 * \brief Engine entrypoint +	 * +	 * This function is called by the game programmer after registering all scenes +	 * +	 * \returns process exit code +	 */ +	int main() noexcept; + +	//! \copydoc SceneManager::add_scene +	template <typename T> +	void add_scene(); + +private: +	/** +	 * \brief Setup function for one-time initialization. +	 * +	 * This function initializes necessary components for the game. +	 */ +	void setup(); +	/** +	 * \brief Main game loop function. +	 * +	 * This function runs the main loop, handling game updates and rendering. +	 */ +	void loop(); + +	//! Game loop condition +	bool game_running = true; + +private: +	//! Global context +	Mediator mediator; + +	//! SystemManager +	SystemManager system_manager{mediator}; + +	//! SDLContext instance +	SDLContext sdl_context{mediator}; + +	//! Resource manager instance +	ResourceManager resource_manager{mediator}; + +	//! Component manager instance +	ComponentManager component_manager{mediator}; +	//! Scene manager instance +	SceneManager scene_manager{mediator}; +	//! LoopTimerManager instance +	LoopTimerManager loop_timer{mediator}; +	//! EventManager instance +	EventManager event_manager{mediator}; +	//! Save manager instance +	SaveManager save_manager{mediator}; +	//! ReplayManager instance +	ReplayManager replay_manager{mediator}; +}; + +} // namespace crepe + +#include "Engine.hpp" diff --git a/src/crepe/api/Engine.hpp b/src/crepe/api/Engine.hpp new file mode 100644 index 0000000..f2fdc0a --- /dev/null +++ b/src/crepe/api/Engine.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "Engine.h" + +namespace crepe { + +template <class T> +void Engine::add_scene() { +	this->scene_manager.add_scene<T>(); +} + +} // namespace crepe diff --git a/src/crepe/api/GameObject.cpp b/src/crepe/api/GameObject.cpp index 9ef4682..9b94cad 100644 --- a/src/crepe/api/GameObject.cpp +++ b/src/crepe/api/GameObject.cpp @@ -7,20 +7,17 @@  using namespace crepe;  using namespace std; -GameObject::GameObject(ComponentManager & component_manager, game_object_id_t id, -					   const std::string & name, const std::string & tag, -					   const vec2 & position, double rotation, double scale) +GameObject::GameObject(Mediator & mediator, game_object_id_t id, const std::string & name, +					   const std::string & tag, const vec2 & position, double rotation, +					   double scale)  	: id(id), -	  component_manager(component_manager) { - -	// Add Transform and Metadata components -	ComponentManager & mgr = this->component_manager; -	mgr.add_component<Transform>(this->id, position, rotation, scale); -	mgr.add_component<Metadata>(this->id, name, tag); -} +	  mediator(mediator), +	  transform(mediator.component_manager->add_component<Transform>(this->id, position, +																	 rotation, scale)), +	  metadata(mediator.component_manager->add_component<Metadata>(this->id, name, tag)) {}  void GameObject::set_parent(const GameObject & parent) { -	ComponentManager & mgr = this->component_manager; +	ComponentManager & mgr = this->mediator.component_manager;  	// Set parent on own Metadata component  	RefVector<Metadata> this_metadata = mgr.get_components_by_id<Metadata>(this->id); @@ -32,7 +29,7 @@ void GameObject::set_parent(const GameObject & parent) {  }  void GameObject::set_persistent(bool persistent) { -	ComponentManager & mgr = this->component_manager; +	ComponentManager & mgr = this->mediator.component_manager;  	mgr.set_persistent(this->id, persistent);  } diff --git a/src/crepe/api/GameObject.h b/src/crepe/api/GameObject.h index ff80f49..572ce3a 100644 --- a/src/crepe/api/GameObject.h +++ b/src/crepe/api/GameObject.h @@ -6,7 +6,9 @@  namespace crepe { -class ComponentManager; +class Mediator; +class Transform; +class Metadata;  /**   * \brief Represents a GameObject @@ -20,7 +22,7 @@ private:  	 * This constructor creates a new GameObject. It creates a new Transform and Metadata  	 * component and adds them to the ComponentManager.  	 * -	 * \param component_manager Reference to component_manager +	 * \param mediator Reference to mediator  	 * \param id The id of the GameObject  	 * \param name The name of the GameObject  	 * \param tag The tag of the GameObject @@ -28,13 +30,20 @@ private:  	 * \param rotation The rotation of the GameObject  	 * \param scale The scale of the GameObject  	 */ -	GameObject(ComponentManager & component_manager, game_object_id_t id, -			   const std::string & name, const std::string & tag, const vec2 & position, -			   double rotation, double scale); +	GameObject(Mediator & mediator, game_object_id_t id, const std::string & name, +			   const std::string & tag, const vec2 & position, double rotation, double scale);  	//! ComponentManager instances GameObject  	friend class ComponentManager;  public: +	//! The id of the GameObject +	const game_object_id_t id; +	//! This entity's transform +	Transform & transform; +	//! This entity's metadata +	Metadata & metadata; + +public:  	/**  	 * \brief Set the parent of this GameObject  	 * @@ -68,12 +77,8 @@ public:  	 */  	void set_persistent(bool persistent = true); -public: -	//! The id of the GameObject -	const game_object_id_t id; -  protected: -	ComponentManager & component_manager; +	Mediator & mediator;  };  } // namespace crepe diff --git a/src/crepe/api/GameObject.hpp b/src/crepe/api/GameObject.hpp index a6b45b0..69f7d73 100644 --- a/src/crepe/api/GameObject.hpp +++ b/src/crepe/api/GameObject.hpp @@ -8,7 +8,7 @@ namespace crepe {  template <typename T, typename... Args>  T & GameObject::add_component(Args &&... args) { -	ComponentManager & mgr = this->component_manager; +	ComponentManager & mgr = this->mediator.component_manager;  	return mgr.add_component<T>(this->id, std::forward<Args>(args)...);  } diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp deleted file mode 100644 index 7a78019..0000000 --- a/src/crepe/api/LoopManager.cpp +++ /dev/null @@ -1,87 +0,0 @@ -#include "../facade/SDLContext.h" -#include "../manager/EventManager.h" -#include "../manager/LoopTimerManager.h" -#include "../system/AISystem.h" -#include "../system/AnimatorSystem.h" -#include "../system/AudioSystem.h" -#include "../system/CollisionSystem.h" -#include "../system/InputSystem.h" -#include "../system/ParticleSystem.h" -#include "../system/PhysicsSystem.h" -#include "../system/RenderSystem.h" -#include "../system/ScriptSystem.h" -#include "../util/Log.h" - -#include "LoopManager.h" - -using namespace crepe; -using namespace std; - -LoopManager::LoopManager() { -	this->load_system<AnimatorSystem>(); -	this->load_system<CollisionSystem>(); -	this->load_system<ParticleSystem>(); -	this->load_system<PhysicsSystem>(); -	this->load_system<RenderSystem>(); -	this->load_system<ScriptSystem>(); -	this->load_system<InputSystem>(); -	this->event_manager.subscribe<ShutDownEvent>( -		[this](const ShutDownEvent & event) { return this->on_shutdown(event); }); -	this->load_system<AudioSystem>(); -	this->load_system<AISystem>(); -} -void LoopManager::start() { -	this->setup(); -	this->loop(); -} - -void LoopManager::setup() { -	this->game_running = true; -	this->loop_timer.start(); -	this->scene_manager.load_next_scene(); -} - -void LoopManager::loop() { -	try { -		while (game_running) { -			this->loop_timer.update(); - -			while (this->loop_timer.get_lag() >= this->loop_timer.get_fixed_delta_time()) { -				this->fixed_update(); -				this->loop_timer.advance_fixed_elapsed_time(); -			} - -			this->frame_update(); -			this->loop_timer.enforce_frame_rate(); -		} -	} catch (const exception & e) { -		Log::logf(Log::Level::ERROR, "Exception caught in main loop: {}", e.what()); -		this->event_manager.trigger_event<ShutDownEvent>(ShutDownEvent{}); -	} -} - -// will be called at a fixed interval -void LoopManager::fixed_update() { -	this->get_system<InputSystem>().update(); -	this->event_manager.dispatch_events(); -	this->get_system<ScriptSystem>().update(); -	this->get_system<ParticleSystem>().update(); -	this->get_system<AISystem>().update(); -	this->get_system<PhysicsSystem>().update(); -	this->get_system<CollisionSystem>().update(); -	this->get_system<AudioSystem>().update(); -} - -// will be called every frame -void LoopManager::frame_update() { -	this->scene_manager.load_next_scene(); -	this->get_system<AnimatorSystem>().update(); -	//render -	this->get_system<RenderSystem>().update(); -} - -bool LoopManager::on_shutdown(const ShutDownEvent & e) { -	this->game_running = false; -	// propagate to possible user ShutDownEvent listeners -	return false; -} diff --git a/src/crepe/api/LoopManager.h b/src/crepe/api/LoopManager.h deleted file mode 100644 index 124cd3a..0000000 --- a/src/crepe/api/LoopManager.h +++ /dev/null @@ -1,123 +0,0 @@ -#pragma once - -#include <memory> - -#include "../facade/SDLContext.h" -#include "../manager/ComponentManager.h" -#include "../manager/EventManager.h" -#include "../manager/LoopTimerManager.h" -#include "../manager/Mediator.h" -#include "../manager/ResourceManager.h" -#include "../manager/SaveManager.h" -#include "../manager/SceneManager.h" -#include "../system/System.h" - -namespace crepe { -/** - * \brief Main game loop manager - * - * This class is responsible for managing the game loop, including initialization and updating. - */ -class LoopManager { -public: -	LoopManager(); -	/** -	 * \brief Start the gameloop -	 * -	 * This is the start of the engine where the setup is called and then the loop keeps running until the game stops running. -	 * The Game programmer needs to call this function to run the game. This should be done after creating and adding all scenes. -	 */ -	void start(); - -	/** -	 * \brief Add a new concrete scene to the scene manager -	 * -	 * \tparam T  Type of concrete scene -	 */ -	template <typename T> -	void add_scene(); - -private: -	/** -	 * \brief Setup function for one-time initialization. -	 * -	 * This function initializes necessary components for the game. -	 */ -	void setup(); -	/** -	 * \brief Main game loop function. -	 * -	 * This function runs the main loop, handling game updates and rendering. -	 */ -	void loop(); - -	/** -	 * \brief Per-frame update. -	 * -	 * Updates the game state based on the elapsed time since the last frame. -	 */ -	virtual void frame_update(); - -	/** -	 * \brief Fixed update executed at a fixed rate. -	 * -	 * This function updates physics and game logic based on LoopTimer's fixed_delta_time. -	 */ -	virtual void fixed_update(); - -	//! Indicates whether the game is running. -	bool game_running = false; - -private: -	//! Global context -	Mediator mediator; -	/** -	 * \brief Collection of System instances -	 * -	 * This map holds System instances indexed by the system's class typeid. It is filled in the -	 * constructor of LoopManager using LoopManager::load_system. -	 */ -	std::unordered_map<std::type_index, std::unique_ptr<System>> systems; - -	//! SDLContext instance -	SDLContext sdl_context{mediator}; -	//! Resource manager instance -	ResourceManager resource_manager{mediator}; - -	//! Component manager instance -	ComponentManager component_manager{mediator}; -	//! Scene manager instance -	SceneManager scene_manager{mediator}; -	//! LoopTimerManager instance -	LoopTimerManager loop_timer{mediator}; -	//! EventManager instance -	EventManager event_manager{mediator}; -	//! Save manager instance -	SaveManager save_manager{mediator}; - -private: -	/** -	 * \brief Callback function for ShutDownEvent -	 * -	 * This function sets the game_running variable to false, stopping the gameloop and therefor quitting the game. -	 */ -	bool on_shutdown(const ShutDownEvent & e); -	/** -	 * \brief Initialize a system -	 * \tparam T System type (must be derivative of \c System) -	 */ -	template <class T> -	void load_system(); -	/** -	 * \brief Retrieve a reference to ECS system -	 * \tparam T System type -	 * \returns Reference to system instance -	 * \throws std::runtime_error if the System is not initialized -	 */ -	template <class T> -	T & get_system(); -}; - -} // namespace crepe - -#include "LoopManager.hpp" diff --git a/src/crepe/api/LoopManager.hpp b/src/crepe/api/LoopManager.hpp deleted file mode 100644 index 266758a..0000000 --- a/src/crepe/api/LoopManager.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -#include <cassert> -#include <format> -#include <memory> - -#include "../system/System.h" - -#include "LoopManager.h" - -namespace crepe { - -template <class T> -void LoopManager::add_scene() { -	this->scene_manager.add_scene<T>(); -} - -template <class T> -T & LoopManager::get_system() { -	using namespace std; -	static_assert(is_base_of<System, T>::value, -				  "get_system must recieve a derivative class of System"); - -	const type_info & type = typeid(T); -	if (!this->systems.contains(type)) -		throw runtime_error(format("LoopManager: {} is not initialized", type.name())); - -	System * system = this->systems.at(type).get(); -	T * concrete_system = dynamic_cast<T *>(system); -	assert(concrete_system != nullptr); - -	return *concrete_system; -} - -template <class T> -void LoopManager::load_system() { -	using namespace std; -	static_assert(is_base_of<System, T>::value, -				  "load_system must recieve a derivative class of System"); - -	const type_info & type = typeid(T); -	if (this->systems.contains(type)) -		throw runtime_error(format("LoopManager: {} is already initialized", type.name())); -	System * system = new T(this->mediator); -	this->systems[type] = unique_ptr<System>(system); -} - -} // namespace crepe diff --git a/src/crepe/api/ParticleEmitter.cpp b/src/crepe/api/ParticleEmitter.cpp index 4f54bbd..9a70334 100644 --- a/src/crepe/api/ParticleEmitter.cpp +++ b/src/crepe/api/ParticleEmitter.cpp @@ -2,6 +2,7 @@  #include "api/Sprite.h"  using namespace crepe; +using namespace std;  ParticleEmitter::ParticleEmitter(game_object_id_t game_object_id, const Sprite & sprite,  								 const Data & data) @@ -12,3 +13,16 @@ ParticleEmitter::ParticleEmitter(game_object_id_t game_object_id, const Sprite &  		this->particles.emplace_back();  	}  } + +unique_ptr<Component> ParticleEmitter::save() const { +	return unique_ptr<Component>{new ParticleEmitter(*this)}; +} + +void ParticleEmitter::restore(const Component & snapshot) { +	*this = static_cast<const ParticleEmitter &>(snapshot); +} + +ParticleEmitter & ParticleEmitter::operator=(const ParticleEmitter & other) { +	this->particles = other.particles; +	return *this; +} diff --git a/src/crepe/api/ParticleEmitter.h b/src/crepe/api/ParticleEmitter.h index 8ac2e72..1edd2b5 100644 --- a/src/crepe/api/ParticleEmitter.h +++ b/src/crepe/api/ParticleEmitter.h @@ -84,6 +84,12 @@ public:  	//! Configuration data for particle emission settings.  	Data data; +protected: +	virtual std::unique_ptr<Component> save() const; +	ParticleEmitter(const ParticleEmitter &) = default; +	virtual void restore(const Component & snapshot); +	virtual ParticleEmitter & operator=(const ParticleEmitter &); +  private:  	//! Only ParticleSystem can move and read particles  	friend ParticleSystem; diff --git a/src/crepe/api/Rigidbody.h b/src/crepe/api/Rigidbody.h index 6900295..b63d941 100644 --- a/src/crepe/api/Rigidbody.h +++ b/src/crepe/api/Rigidbody.h @@ -2,6 +2,7 @@  #include <cmath>  #include <set> +#include <string>  #include "../Component.h" @@ -120,26 +121,49 @@ public:  		* above 0.0.  		*  		*/ -		float elastisity_coefficient = 0.0; +		float elasticity_coefficient = 0.0;  		/** -		* \brief Offset of all colliders relative to the object's transform position. +		 * \brief  Enables collision handling for objects colliding with kinematic objects. +		 * +		 * Enables collision handling for objects colliding with kinematic objects in the collision system. +     * If `kinematic_collision` is true, dynamic objects cannot pass through this kinematic object. +     * This ensures that kinematic objects delegate collision handling to the collision system. +		 */ +		bool kinematic_collision = true; + +		/** +		* \brief Defines the collision layers a GameObject interacts with.  		* -		* The `offset` defines a positional shift applied to all colliders associated with the object, relative to the object's -		* transform position. This allows for the colliders to be placed at a different position than the object's actual -		* position, without modifying the object's transform itself. +		* The `collision_layers` represent the set of layers the GameObject can detect collisions with. +		* Each element in this set corresponds to a layer ID. The GameObject will only collide with other +		* GameObjects that belong to one these layers. +		*/ +		std::set<int> collision_layers = {0}; + +		/** +		* \brief Specifies the collision layer of the GameObject.  		* +		* The `collision_layer` indicates the single layer that this GameObject belongs to.  +		* This determines which layers other objects must match to detect collisions with this object.  		*/ -		vec2 offset; +		int collision_layer = 0;  		/**  		 * \brief Defines the collision layers of a GameObject.  		 * -		 * The `collision_layers` specifies the layers that the GameObject will collide with. -		 * Each element represents a layer ID, and the GameObject will only detect -		 * collisions with other GameObjects that belong to these layers. +		 * The `collision_names` specifies where the GameObject will collide with. +		 * Each element represents a name from the Metadata of the gameobject.  		 */ -		std::set<int> collision_layers = {0}; +		std::set<std::string> collision_names; + +		/** +		 * \brief Defines the collision layers of a GameObject. +		 * +		 * The `collision_tags` specifies where the GameObject will collide with. +		 * Each element represents a tag from the Metadata of the gameobject. +		 */ +		std::set<std::string> collision_tags;  	};  public: diff --git a/src/crepe/api/Script.cpp b/src/crepe/api/Script.cpp index 7531388..b147252 100644 --- a/src/crepe/api/Script.cpp +++ b/src/crepe/api/Script.cpp @@ -2,6 +2,7 @@  #include "../facade/SDLContext.h"  #include "../manager/SceneManager.h" +  #include "Script.h"  using namespace crepe; @@ -28,6 +29,26 @@ SaveManager & Script::get_save_manager() const { return this->mediator->save_man  LoopTimerManager & Script::get_loop_timer() const { return this->mediator->loop_timer; } +void Script::replay::record_start() { +	ReplayManager & mgr = this->mediator->replay_manager; +	return mgr.record_start(); +} + +recording_t Script::replay::record_end() { +	ReplayManager & mgr = this->mediator->replay_manager; +	return mgr.record_end(); +} + +void Script::replay::play(recording_t recording) { +	ReplayManager & mgr = this->mediator->replay_manager; +	return mgr.play(recording); +} + +void Script::replay::release(recording_t recording) { +	ReplayManager & mgr = this->mediator->replay_manager; +	return mgr.release(recording); +} +  const keyboard_state_t & Script::get_keyboard_state() const {  	SDLContext & sdl_context = this->mediator->sdl_context;  	return sdl_context.get_keyboard_state(); diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index a87af4e..5f68928 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -6,8 +6,10 @@  #include "../manager/EventManager.h"  #include "../manager/LoopTimerManager.h"  #include "../manager/Mediator.h" +#include "../manager/ReplayManager.h"  #include "../system/CollisionSystem.h"  #include "../types.h" +#include "../util/Log.h"  #include "../util/OptionalRef.h"  namespace crepe { @@ -46,14 +48,23 @@ protected:  	 */  	virtual void init() {}  	/** -	 * \brief Script update function (empty by default) +	 * \brief Script fixed update function (empty by default)  	 *  	 * \param delta_time Time since last fixed update  	 * -	 * This function is called during the ScriptSystem::update() routine if the \c BehaviorScript -	 * component holding this script instance is active. +	 * \note This function is called during the ScriptSystem::update() routine if the \c +	 * BehaviorScript component holding this script instance is active.  	 */ -	virtual void update(duration_t delta_time) {} +	virtual void fixed_update(duration_t delta_time) {} +	/** +	 * \brief Script frame update function (empty by default) +	 * +	 * \param delta_time Time since last frame update +	 * +	 * \note This function is called during the ScriptSystem::update() routine if the \c +	 * BehaviorScript component holding this script instance is active. +	 */ +	virtual void frame_update(duration_t delta_time) {}  	//! \}  	//! ScriptSystem calls \c init() and \c update() @@ -61,93 +72,119 @@ protected:  protected:  	/** -	 * \name Utility functions +	 * \name Component query functions +	 * \see ComponentManager  	 * \{  	 */ -  	/**  	 * \brief Get single component of type \c T on this game object -	 *  	 * \tparam T Type of component -	 *  	 * \returns Reference to component -	 *  	 * \throws std::runtime_error if this game object does not have a component with type \c T  	 */  	template <typename T>  	T & get_component() const; -	// TODO: make get_component calls for component types that can have more than 1 instance -	// cause compile-time errors -  	/**  	 * \brief Get all components of type \c T on this game object -	 *  	 * \tparam T Type of component -	 *  	 * \returns List of component references  	 */  	template <typename T>  	RefVector<T> get_components() const; - -	/** -	 * \copydoc ComponentManager::get_components_by_id -	 * \see ComponentManager::get_components_by_id -	 */ +	//! \copydoc ComponentManager::get_components_by_id  	template <typename T>  	RefVector<T> get_components_by_id(game_object_id_t id) const; -	/** -	 * \copydoc ComponentManager::get_components_by_name -	 * \see ComponentManager::get_components_by_name -	 */ +	//! \copydoc ComponentManager::get_components_by_name  	template <typename T>  	RefVector<T> get_components_by_name(const std::string & name) const; -	/** -	 * \copydoc ComponentManager::get_components_by_tag -	 * \see ComponentManager::get_components_by_tag -	 */ +	//! \copydoc ComponentManager::get_components_by_tag  	template <typename T>  	RefVector<T> get_components_by_tag(const std::string & tag) const; +	//! \}  	/** -	 * \brief Log a message using Log::logf -	 * -	 * \tparam Args Log::logf parameters -	 * \param args  Log::logf parameters +	 * \name Logging functions +	 * \see Log +	 * \{  	 */ -	template <typename... Args> -	void logf(Args &&... args); +	//! \copydoc Log::logf +	template <class... Args> +	void logf(const Log::Level & level, std::format_string<Args...> fmt, Args &&... args); +	//! \copydoc Log::logf +	template <class... Args> +	void logf(std::format_string<Args...> fmt, Args &&... args); +	// \}  	/** -	 * \brief Subscribe to an event with an explicit channel -	 * \see EventManager::subscribe +	 * \name Event manager functions +	 * \see EventManager +	 * \{  	 */ +	//! \copydoc EventManager::subscribe  	template <typename EventType>  	void subscribe(const EventHandler<EventType> & callback, event_channel_t channel); -	/** -	 * \brief Subscribe to an event on EventManager::CHANNEL_ALL -	 * \see EventManager::subscribe -	 */ +	//! \copydoc EventManager::subscribe  	template <typename EventType>  	void subscribe(const EventHandler<EventType> & callback); +	//! \copydoc EventManager::trigger_event +	template <typename EventType> +	void trigger_event(const EventType & event = {}, +					   event_channel_t channel = EventManager::CHANNEL_ALL); +	//! \copydoc EventManager::queue_event +	template <typename EventType> +	void queue_event(const EventType & event = {}, +					 event_channel_t channel = EventManager::CHANNEL_ALL); +	//! \}  	/** -	 * \brief Set the next scene using SceneManager -	 * \see SceneManager::set_next_scene +	 * \name Scene-related functions +	 * \see SceneManager +	 * \{  	 */ +	//! \copydoc SceneManager::set_next_scene  	void set_next_scene(const std::string & name); +	//! \} +	/** +	 * \name Save data management functions +	 * \see SaveManager +	 * \{ +	 */  	//! Retrieve SaveManager reference  	SaveManager & get_save_manager() const; +	//! \} +	/** +	 * \name Timing functions +	 * \see LoopTimerManager +	 * \{ +	 */  	//! Retrieve LoopTimerManager reference  	LoopTimerManager & get_loop_timer() const; +	//! \} + +	//! Replay management functions +	struct replay { // NOLINT +		//! \copydoc ReplayManager::record_start +		void record_start(); +		//! \copydoc ReplayManager::record_end +		recording_t record_end(); +		//! \copydoc ReplayManager::play +		void play(recording_t); +		//! \copydoc ReplayManager::release +		void release(recording_t); + +	private: +		OptionalRef<Mediator> & mediator; +		replay(OptionalRef<Mediator> & mediator) : mediator(mediator) {} +		friend class Script; +	} replay{mediator};  	/**  	 * \brief Utility function to retrieve the keyboard state  	 * \see SDLContext::get_keyboard_state  	 *   	 * \return current keyboard state map with Keycode as key and bool as value(true = pressed, false = not pressed) -	 *   	 */  	const keyboard_state_t & get_keyboard_state() const;  	/** @@ -155,7 +192,6 @@ protected:  	 * \see SDLContext::get_keyboard_state  	 *   	 * \return Keycode state (true if pressed, false if not pressed). -	 *   	 */  	bool get_key_state(Keycode key) const noexcept; diff --git a/src/crepe/api/Script.hpp b/src/crepe/api/Script.hpp index 225a51c..4462a41 100644 --- a/src/crepe/api/Script.hpp +++ b/src/crepe/api/Script.hpp @@ -1,6 +1,7 @@  #pragma once  #include "../manager/ComponentManager.h" +#include "../manager/ReplayManager.h"  #include "BehaviorScript.h"  #include "Script.h" @@ -23,9 +24,14 @@ RefVector<T> Script::get_components() const {  	return this->get_components_by_id<T>(this->game_object_id);  } -template <typename... Args> -void Script::logf(Args &&... args) { -	Log::logf(std::forward<Args>(args)...); +template <class... Args> +void Script::logf(const Log::Level & level, std::format_string<Args...> fmt, Args &&... args) { +	Log::logf(level, fmt, std::forward<Args>(args)...); +} + +template <class... Args> +void Script::logf(std::format_string<Args...> fmt, Args &&... args) { +	Log::logf(fmt, std::forward<Args>(args)...);  }  template <typename EventType> @@ -34,8 +40,18 @@ void Script::subscribe_internal(const EventHandler<EventType> & callback,  	EventManager & mgr = this->mediator->event_manager;  	subscription_t listener = mgr.subscribe<EventType>(  		[this, callback](const EventType & data) -> bool { +			// check if (parent) BehaviorScript component is active  			bool & active = this->active;  			if (!active) return false; + +			// check if replay manager is playing (if initialized) +			try { +				ReplayManager & replay = this->mediator->replay_manager; +				if (replay.get_state() == ReplayManager::PLAYING) return false; +			} catch (const std::runtime_error &) { +			} + +			// call user-provided callback  			return callback(data);  		},  		channel); @@ -52,6 +68,18 @@ void Script::subscribe(const EventHandler<EventType> & callback) {  	this->subscribe_internal(callback, EventManager::CHANNEL_ALL);  } +template <typename EventType> +void Script::trigger_event(const EventType & event, event_channel_t channel) { +	EventManager & mgr = this->mediator->event_manager; +	mgr.trigger_event(event, channel); +} + +template <typename EventType> +void Script::queue_event(const EventType & event, event_channel_t channel) { +	EventManager & mgr = this->mediator->event_manager; +	mgr.queue_event(event, channel); +} +  template <typename T>  RefVector<T> Script::get_components_by_id(game_object_id_t id) const {  	Mediator & mediator = this->mediator; diff --git a/src/crepe/api/Sprite.cpp b/src/crepe/api/Sprite.cpp index ba684ba..0107c7b 100644 --- a/src/crepe/api/Sprite.cpp +++ b/src/crepe/api/Sprite.cpp @@ -1,6 +1,6 @@  #include <cmath> -#include "../util/Log.h" +#include "../util/dbg.h"  #include "api/Asset.h"  #include "Component.h" diff --git a/src/crepe/api/Sprite.h b/src/crepe/api/Sprite.h index a2409c2..a3fc319 100644 --- a/src/crepe/api/Sprite.h +++ b/src/crepe/api/Sprite.h @@ -66,6 +66,16 @@ public:  		//! independent sprite offset position  		vec2 position_offset; + +		/** +		 * \brief gives the user the option to render this in world space or in camera space +		 * +		 * - if true will this be rendered in world space this means that the sprite can be +		 *   rendered off the screen  +		 * - if false --> will the sprite be rendered in camera space. this means that the +		 *   coordinates given on the \c Sprite and \c Transform will be inside the camera  +		 */ +		bool world_space = true;  	};  public: diff --git a/src/crepe/api/Text.cpp b/src/crepe/api/Text.cpp index 54a4370..4a94180 100644 --- a/src/crepe/api/Text.cpp +++ b/src/crepe/api/Text.cpp @@ -1,5 +1,3 @@ -#include "../facade/FontFacade.h" -  #include "Text.h"  using namespace crepe; diff --git a/src/crepe/api/Text.h b/src/crepe/api/Text.h index c30dc80..da40141 100644 --- a/src/crepe/api/Text.h +++ b/src/crepe/api/Text.h @@ -3,8 +3,6 @@  #include <optional>  #include <string> -#include "../Component.h" -  #include "Asset.h"  #include "Color.h"  #include "UIObject.h" diff --git a/src/crepe/api/Transform.cpp b/src/crepe/api/Transform.cpp index a85b792..fcfce14 100644 --- a/src/crepe/api/Transform.cpp +++ b/src/crepe/api/Transform.cpp @@ -1,8 +1,9 @@ -#include "../util/Log.h" +#include "../util/dbg.h"  #include "Transform.h"  using namespace crepe; +using namespace std;  Transform::Transform(game_object_id_t id, const vec2 & point, double rotation, double scale)  	: Component(id), @@ -11,3 +12,11 @@ Transform::Transform(game_object_id_t id, const vec2 & point, double rotation, d  	  scale(scale) {  	dbg_trace();  } + +unique_ptr<Component> Transform::save() const { +	return unique_ptr<Component>{new Transform(*this)}; +} + +void Transform::restore(const Component & snapshot) { +	*this = static_cast<const Transform &>(snapshot); +} diff --git a/src/crepe/api/Transform.h b/src/crepe/api/Transform.h index 7ee6d65..a6f3486 100644 --- a/src/crepe/api/Transform.h +++ b/src/crepe/api/Transform.h @@ -35,6 +35,12 @@ protected:  	virtual int get_instances_max() const { return 1; }  	//! ComponentManager instantiates all components  	friend class ComponentManager; + +protected: +	virtual std::unique_ptr<Component> save() const; +	Transform(const Transform &) = default; +	virtual void restore(const Component & snapshot); +	virtual Transform & operator=(const Transform &) = default;  };  } // namespace crepe diff --git a/src/crepe/api/Vector2.h b/src/crepe/api/Vector2.h index bf9d124..52e1bb6 100644 --- a/src/crepe/api/Vector2.h +++ b/src/crepe/api/Vector2.h @@ -90,6 +90,9 @@ struct Vector2 {  	//! Returns the perpendicular vector to this vector.  	Vector2 perpendicular() const; + +	//! Checks if both components of the vector are NaN. +	bool is_nan() const;  };  } // namespace crepe diff --git a/src/crepe/api/Vector2.hpp b/src/crepe/api/Vector2.hpp index ff53cb0..e195760 100644 --- a/src/crepe/api/Vector2.hpp +++ b/src/crepe/api/Vector2.hpp @@ -163,4 +163,9 @@ Vector2<T> Vector2<T>::perpendicular() const {  	return {-y, x};  } +template <class T> +bool Vector2<T>::is_nan() const { +	return std::isnan(x) && std::isnan(y); +} +  } // namespace crepe |