diff options
Diffstat (limited to 'src/crepe/api')
43 files changed, 583 insertions, 439 deletions
diff --git a/src/crepe/api/AI.cpp b/src/crepe/api/AI.cpp index 2195249..2fedaf4 100644 --- a/src/crepe/api/AI.cpp +++ b/src/crepe/api/AI.cpp @@ -8,8 +8,9 @@ namespace crepe { AI::AI(game_object_id_t id, float max_force) : Component(id), max_force(max_force) {} -void AI::make_circle_path(float radius, const vec2 & center, float start_angle, - bool clockwise) { +void AI::make_circle_path( + float radius, const vec2 & center, float start_angle, bool clockwise +) { if (radius <= 0) { throw std::runtime_error("Radius must be greater than 0"); } @@ -25,19 +26,25 @@ void AI::make_circle_path(float radius, const vec2 & center, float start_angle, if (clockwise) { for (float i = start_angle; i < 2 * M_PI + start_angle; i += step) { - path.push_back(vec2{static_cast<float>(center.x + radius * cos(i)), - static_cast<float>(center.y + radius * sin(i))}); + path.push_back(vec2 { + static_cast<float>(center.x + radius * cos(i)), + static_cast<float>(center.y + radius * sin(i)) + }); } } else { for (float i = start_angle; i > start_angle - 2 * M_PI; i -= step) { - path.push_back(vec2{static_cast<float>(center.x + radius * cos(i)), - static_cast<float>(center.y + radius * sin(i))}); + path.push_back(vec2 { + static_cast<float>(center.x + radius * cos(i)), + static_cast<float>(center.y + radius * sin(i)) + }); } } } -void AI::make_oval_path(float radius_x, float radius_y, const vec2 & center, float start_angle, - bool clockwise, float rotation) { +void AI::make_oval_path( + float radius_x, float radius_y, const vec2 & center, float start_angle, bool clockwise, + float rotation +) { if (radius_x <= 0 && radius_y <= 0) { throw std::runtime_error("Radius must be greater than 0"); } @@ -73,14 +80,16 @@ void AI::make_oval_path(float radius_x, float radius_y, const vec2 & center, flo if (clockwise) { for (float i = start_angle; i < 2 * M_PI + start_angle; i += step) { - vec2 point = {static_cast<float>(center.x + radius_x * cos(i)), - static_cast<float>(center.y + radius_y * sin(i))}; + vec2 point + = {static_cast<float>(center.x + radius_x * cos(i)), + static_cast<float>(center.y + radius_y * sin(i))}; path.push_back(rotate_point(point, center)); } } else { for (float i = start_angle; i > start_angle - 2 * M_PI; i -= step) { - vec2 point = {static_cast<float>(center.x + radius_x * cos(i)), - static_cast<float>(center.y + radius_y * sin(i))}; + vec2 point + = {static_cast<float>(center.x + radius_x * cos(i)), + static_cast<float>(center.y + radius_y * sin(i))}; path.push_back(rotate_point(point, center)); } } diff --git a/src/crepe/api/AI.h b/src/crepe/api/AI.h index c780a91..bee11b3 100644 --- a/src/crepe/api/AI.h +++ b/src/crepe/api/AI.h @@ -70,8 +70,10 @@ public: * \param start_angle The start angle of the circle (in radians) * \param clockwise The direction of the circle */ - void make_circle_path(float radius, const vec2 & center = {0, 0}, float start_angle = 0, - bool clockwise = true); + void make_circle_path( + float radius, const vec2 & center = {0, 0}, float start_angle = 0, + bool clockwise = true + ); /** * \brief Make an oval path (for the path following behavior) * @@ -84,8 +86,10 @@ public: * \param clockwise The direction of the oval * \param rotation The rotation of the oval (in radians) */ - void make_oval_path(float radius_x, float radius_y, const vec2 & center = {0, 0}, - float start_angle = 0, bool clockwise = true, float rotation = 0); + void make_oval_path( + float radius_x, float radius_y, const vec2 & center = {0, 0}, float start_angle = 0, + bool clockwise = true, float rotation = 0 + ); public: //! The maximum force that can be applied to the entity (higher values will make the entity adjust faster) diff --git a/src/crepe/api/Animator.cpp b/src/crepe/api/Animator.cpp index 4ce4bf0..c558d86 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" @@ -7,8 +7,10 @@ using namespace crepe; -Animator::Animator(game_object_id_t id, Sprite & spritesheet, const ivec2 & single_frame_size, - const uvec2 & grid_size, const Animator::Data & data) +Animator::Animator( + game_object_id_t id, Sprite & spritesheet, const ivec2 & single_frame_size, + const uvec2 & grid_size, const Animator::Data & data +) : Component(id), spritesheet(spritesheet), grid_size(grid_size), @@ -52,6 +54,6 @@ void Animator::set_anim(int col) { void Animator::next_anim() { Animator::Data & ctx = this->data; - ctx.row = ctx.row++ % this->grid_size.x; + ctx.row = ++ctx.row % this->grid_size.x; this->spritesheet.mask.x = ctx.row * this->spritesheet.mask.w; } diff --git a/src/crepe/api/Animator.h b/src/crepe/api/Animator.h index 5918800..102894d 100644 --- a/src/crepe/api/Animator.h +++ b/src/crepe/api/Animator.h @@ -83,8 +83,10 @@ public: * This constructor sets up the Animator with the given parameters, and initializes the * animation system. */ - Animator(game_object_id_t id, Sprite & spritesheet, const ivec2 & single_frame_size, - const uvec2 & grid_size, const Animator::Data & data); + Animator( + game_object_id_t id, Sprite & spritesheet, const ivec2 & single_frame_size, + const uvec2 & grid_size, const Animator::Data & data + ); ~Animator(); // dbg_trace public: diff --git a/src/crepe/api/Asset.cpp b/src/crepe/api/Asset.cpp index e148367..bab82e7 100644 --- a/src/crepe/api/Asset.cpp +++ b/src/crepe/api/Asset.cpp @@ -50,5 +50,5 @@ string Asset::whereami() const noexcept { bool Asset::operator==(const Asset & other) const noexcept { return this->src == other.src; } size_t std::hash<const Asset>::operator()(const Asset & asset) const noexcept { - return std::hash<string>{}(asset.get_path()); + return std::hash<string> {}(asset.get_path()); }; diff --git a/src/crepe/api/AudioSource.h b/src/crepe/api/AudioSource.h index b20e490..eaa56e8 100644 --- a/src/crepe/api/AudioSource.h +++ b/src/crepe/api/AudioSource.h @@ -68,7 +68,7 @@ private: typeof(loop) last_loop = loop; //! \} //! This source's voice handle - SoundHandle voice{}; + SoundHandle voice {}; }; } // namespace crepe 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/BoxCollider.cpp b/src/crepe/api/BoxCollider.cpp index a893d41..f6b358d 100644 --- a/src/crepe/api/BoxCollider.cpp +++ b/src/crepe/api/BoxCollider.cpp @@ -4,7 +4,8 @@ using namespace crepe; -BoxCollider::BoxCollider(game_object_id_t game_object_id, const vec2 & dimensions, - const vec2 & offset) +BoxCollider::BoxCollider( + game_object_id_t game_object_id, const vec2 & dimensions, const vec2 & offset +) : Collider(game_object_id, offset), dimensions(dimensions) {} diff --git a/src/crepe/api/BoxCollider.h b/src/crepe/api/BoxCollider.h index d643e7f..229b90f 100644 --- a/src/crepe/api/BoxCollider.h +++ b/src/crepe/api/BoxCollider.h @@ -13,8 +13,9 @@ namespace crepe { */ class BoxCollider : public Collider { public: - BoxCollider(game_object_id_t game_object_id, const vec2 & dimensions, - const vec2 & offset = {0, 0}); + BoxCollider( + game_object_id_t game_object_id, const vec2 & dimensions, const vec2 & offset = {0, 0} + ); //! Width and height of the box collider vec2 dimensions; 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..b1466b5 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" @@ -6,8 +6,9 @@ using namespace crepe; -Camera::Camera(game_object_id_t id, const ivec2 & screen, const vec2 & viewport_size, - const Data & data) +Camera::Camera( + game_object_id_t id, const ivec2 & screen, const vec2 & viewport_size, const Data & data +) : Component(id), screen(screen), viewport_size(viewport_size), diff --git a/src/crepe/api/Camera.h b/src/crepe/api/Camera.h index 54d9a73..3191b04 100644 --- a/src/crepe/api/Camera.h +++ b/src/crepe/api/Camera.h @@ -44,8 +44,10 @@ public: * \param viewport_size is the view of the world in game units * \param data the camera component data */ - Camera(game_object_id_t id, const ivec2 & screen, const vec2 & viewport_size, - const Camera::Data & data); + Camera( + game_object_id_t id, const ivec2 & screen, const vec2 & viewport_size, + const Camera::Data & data + ); ~Camera(); // dbg_trace only public: diff --git a/src/crepe/api/CircleCollider.cpp b/src/crepe/api/CircleCollider.cpp index 90ab5e7..e72800c 100644 --- a/src/crepe/api/CircleCollider.cpp +++ b/src/crepe/api/CircleCollider.cpp @@ -2,7 +2,8 @@ using namespace crepe; -CircleCollider::CircleCollider(game_object_id_t game_object_id, float radius, - const vec2 & offset) +CircleCollider::CircleCollider( + game_object_id_t game_object_id, float radius, const vec2 & offset +) : Collider(game_object_id, offset), radius(radius) {} diff --git a/src/crepe/api/CircleCollider.h b/src/crepe/api/CircleCollider.h index 22da836..e6ad4fa 100644 --- a/src/crepe/api/CircleCollider.h +++ b/src/crepe/api/CircleCollider.h @@ -13,8 +13,9 @@ namespace crepe { */ class CircleCollider : public Collider { public: - CircleCollider(game_object_id_t game_object_id, float radius, - const vec2 & offset = {0, 0}); + CircleCollider( + game_object_id_t game_object_id, float radius, const vec2 & offset = {0, 0} + ); //! Radius of the circle collider. float radius; diff --git a/src/crepe/api/Color.cpp b/src/crepe/api/Color.cpp index 29bd77a..6858aa8 100644 --- a/src/crepe/api/Color.cpp +++ b/src/crepe/api/Color.cpp @@ -2,11 +2,11 @@ using namespace crepe; -const Color Color::WHITE{0xff, 0xff, 0xff}; -const Color Color::RED{0xff, 0x00, 0x00}; -const Color Color::GREEN{0x00, 0xff, 0x00}; -const Color Color::BLUE{0x00, 0x00, 0xff}; -const Color Color::BLACK{0x00, 0x00, 0x00}; -const Color Color::CYAN{0x00, 0xff, 0xff}; -const Color Color::YELLOW{0xff, 0xff, 0x00}; -const Color Color::MAGENTA{0xff, 0x00, 0xff}; +const Color Color::WHITE {0xff, 0xff, 0xff}; +const Color Color::RED {0xff, 0x00, 0x00}; +const Color Color::GREEN {0x00, 0xff, 0x00}; +const Color Color::BLUE {0x00, 0x00, 0xff}; +const Color Color::BLACK {0x00, 0x00, 0x00}; +const Color Color::CYAN {0x00, 0xff, 0xff}; +const Color Color::YELLOW {0xff, 0xff, 0x00}; +const Color Color::MAGENTA {0xff, 0x00, 0xff}; diff --git a/src/crepe/api/Engine.cpp b/src/crepe/api/Engine.cpp new file mode 100644 index 0000000..cd9786b --- /dev/null +++ b/src/crepe/api/Engine.cpp @@ -0,0 +1,67 @@ +#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..452a856 --- /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/Event.h b/src/crepe/api/Event.h index 8e38280..7d4df21 100644 --- a/src/crepe/api/Event.h +++ b/src/crepe/api/Event.h @@ -10,15 +10,14 @@ namespace crepe { /** - * \brief Base class for all event types in the system. + * \brief Base struct for all event types in the system. */ -class Event {}; +struct Event {}; /** * \brief Event triggered when a key is pressed. */ -class KeyPressEvent : public Event { -public: +struct KeyPressEvent : public Event { //! false if first time press, true if key is repeated bool repeat = false; @@ -29,8 +28,7 @@ public: /** * \brief Event triggered when a key is released. */ -class KeyReleaseEvent : public Event { -public: +struct KeyReleaseEvent : public Event { //! The key that was released. Keycode key = Keycode::NONE; }; @@ -38,8 +36,7 @@ public: /** * \brief Event triggered when a mouse button is pressed. */ -class MousePressEvent : public Event { -public: +struct MousePressEvent : public Event { //! mouse position in world coordinates (game units). vec2 mouse_pos = {0, 0}; @@ -50,8 +47,7 @@ public: /** * \brief Event triggered when a mouse button is clicked (press and release). */ -class MouseClickEvent : public Event { -public: +struct MouseClickEvent : public Event { //! mouse position in world coordinates (game units). vec2 mouse_pos = {0, 0}; @@ -62,8 +58,7 @@ public: /** * \brief Event triggered when a mouse button is released. */ -class MouseReleaseEvent : public Event { -public: +struct MouseReleaseEvent : public Event { //! mouse position in world coordinates (game units). vec2 mouse_pos = {0, 0}; @@ -74,8 +69,7 @@ public: /** * \brief Event triggered when the mouse is moved. */ -class MouseMoveEvent : public Event { -public: +struct MouseMoveEvent : public Event { //! mouse position in world coordinates (game units). vec2 mouse_pos = {0, 0}; //! The change in mouse position relative to the last position (in pixels). @@ -85,8 +79,7 @@ public: /** * \brief Event triggered when the mouse is moved. */ -class MouseScrollEvent : public Event { -public: +struct MouseScrollEvent : public Event { //! mouse position in world coordinates (game units) when the scroll happened. vec2 mouse_pos = {0, 0}; //! scroll direction (-1 = down, 1 = up) @@ -98,20 +91,19 @@ public: /** * \brief Event triggered to indicate the application is shutting down. */ -class ShutDownEvent : public Event {}; +struct ShutDownEvent : public Event {}; /** * \brief Event triggered to indicate the window is overlapped by another window. * * When two windows overlap the bottom window gets distorted and that window has to be redrawn. */ -class WindowExposeEvent : public Event {}; +struct WindowExposeEvent : public Event {}; /** * \brief Event triggered to indicate the window is resized. */ -class WindowResizeEvent : public Event { -public: +struct WindowResizeEvent : public Event { //! new window dimensions ivec2 dimensions = {0, 0}; }; @@ -119,8 +111,7 @@ public: /** * \brief Event triggered to indicate the window is moved. */ -class WindowMoveEvent : public Event { -public: +struct WindowMoveEvent : public Event { //! The change in position relative to the last position (in pixels). ivec2 delta_move = {0, 0}; }; @@ -128,12 +119,12 @@ public: /** * \brief Event triggered to indicate the window is minimized. */ -class WindowMinimizeEvent : public Event {}; +struct WindowMinimizeEvent : public Event {}; /** * \brief Event triggered to indicate the window is maximized */ -class WindowMaximizeEvent : public Event {}; +struct WindowMaximizeEvent : public Event {}; /** * \brief Event triggered to indicate the window gained focus @@ -141,7 +132,7 @@ class WindowMaximizeEvent : public Event {}; * This event is triggered when the window receives focus, meaning it becomes the active window * for user interaction. */ -class WindowFocusGainEvent : public Event {}; +struct WindowFocusGainEvent : public Event {}; /** * \brief Event triggered to indicate the window lost focus @@ -149,6 +140,6 @@ class WindowFocusGainEvent : public Event {}; * This event is triggered when the window loses focus, meaning it is no longer the active window * for user interaction. */ -class WindowFocusLostEvent : public Event {}; +struct WindowFocusLostEvent : public Event {}; } // namespace crepe diff --git a/src/crepe/api/GameObject.cpp b/src/crepe/api/GameObject.cpp index 9ef4682..100e210 100644 --- a/src/crepe/api/GameObject.cpp +++ b/src/crepe/api/GameObject.cpp @@ -7,20 +7,19 @@ 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 +31,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..043913a 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,22 @@ 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 +79,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..341c1e2 100644 --- a/src/crepe/api/ParticleEmitter.cpp +++ b/src/crepe/api/ParticleEmitter.cpp @@ -2,9 +2,11 @@ #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) +ParticleEmitter::ParticleEmitter( + game_object_id_t game_object_id, const Sprite & sprite, const Data & data +) : Component(game_object_id), sprite(sprite), data(data) { @@ -12,3 +14,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/Scene.cpp b/src/crepe/api/Scene.cpp index ad729d2..84da7e8 100644 --- a/src/crepe/api/Scene.cpp +++ b/src/crepe/api/Scene.cpp @@ -4,8 +4,10 @@ using namespace crepe; SaveManager & Scene::get_save_manager() const { return mediator->save_manager; } -GameObject Scene::new_object(const std::string & name, const std::string & tag, - const vec2 & position, double rotation, double scale) { +GameObject Scene::new_object( + const std::string & name, const std::string & tag, const vec2 & position, double rotation, + double scale +) { // Forward the call to ComponentManager's new_object method return mediator->component_manager->new_object(name, tag, position, rotation, scale); } diff --git a/src/crepe/api/Scene.h b/src/crepe/api/Scene.h index dcca9d4..b50a0fc 100644 --- a/src/crepe/api/Scene.h +++ b/src/crepe/api/Scene.h @@ -60,7 +60,7 @@ private: OptionalRef<Mediator> mediator; //! \} -protected: +public: /** * \brief Retrieve the reference to the SaveManager instance * @@ -69,9 +69,10 @@ protected: SaveManager & get_save_manager() const; //! \copydoc ComponentManager::new_object - GameObject new_object(const std::string & name, const std::string & tag = "", - const vec2 & position = {0, 0}, double rotation = 0, - double scale = 1); + GameObject new_object( + const std::string & name, const std::string & tag = "", const vec2 & position = {0, 0}, + double rotation = 0, double scale = 1 + ); //! \copydoc ResourceManager::set_persistent void set_persistent(const Asset & asset, bool persistent); diff --git a/src/crepe/api/Script.cpp b/src/crepe/api/Script.cpp index 85016f5..06b535f 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; @@ -19,6 +20,21 @@ void Script::subscribe(const EventHandler<CollisionEvent> & callback) { this->subscribe_internal(callback, this->game_object_id); } +template <> +void Script::subscribe(const EventHandler<ButtonExitEvent> & callback) { + this->subscribe_internal(callback, this->game_object_id); +} + +template <> +void Script::subscribe(const EventHandler<ButtonPressEvent> & callback) { + this->subscribe_internal(callback, this->game_object_id); +} + +template <> +void Script::subscribe(const EventHandler<ButtonEnterEvent> & callback) { + this->subscribe_internal(callback, this->game_object_id); +} + void Script::set_next_scene(const string & name) { SceneManager & mgr = this->mediator->scene_manager; mgr.set_next_scene(name); @@ -28,6 +44,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(); @@ -40,4 +76,3 @@ bool Script::get_key_state(Keycode key) const noexcept { return false; } } - diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index a87af4e..b000d9d 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -6,8 +6,11 @@ #include "../manager/EventManager.h" #include "../manager/LoopTimerManager.h" #include "../manager/Mediator.h" +#include "../manager/ReplayManager.h" #include "../system/CollisionSystem.h" +#include "../system/InputSystem.h" #include "../types.h" +#include "../util/Log.h" #include "../util/OptionalRef.h" namespace crepe { @@ -46,14 +49,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 +73,121 @@ 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 +195,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; @@ -234,7 +273,42 @@ void Script::subscribe(const EventHandler<CollisionEvent> & callback); template <> void Script::subscribe(const EventHandler<CollisionEvent> & callback, event_channel_t) = delete; - +/** + * \brief Subscribe to ButtonPressEvent for the current GameObject + * + * This is a template specialization for Script::subscribe which automatically sets the event + * channel so the callback handler is only called for ButtonPressEvent events that apply to the + * current GameObject the parent BehaviorScript is attached to. + */ +template <> +void Script::subscribe(const EventHandler<ButtonPressEvent> & callback); +template <> +void Script::subscribe(const EventHandler<ButtonPressEvent> & callback, event_channel_t) + = delete; +/** + * \brief Subscribe to ButtonExitEvent for the current GameObject + * + * This is a template specialization for Script::subscribe which automatically sets the event + * channel so the callback handler is only called for ButtonExitEvent events that apply to the + * current GameObject the parent BehaviorScript is attached to. + */ +template <> +void Script::subscribe(const EventHandler<ButtonExitEvent> & callback); +template <> +void Script::subscribe(const EventHandler<ButtonExitEvent> & callback, event_channel_t) + = delete; +/** + * \brief Subscribe to ButtonEnterEvent for the current GameObject + * + * This is a template specialization for Script::subscribe which automatically sets the event + * channel so the callback handler is only called for ButtonEnterEvent events that apply to the + * current GameObject the parent BehaviorScript is attached to. + */ +template <> +void Script::subscribe(const EventHandler<ButtonEnterEvent> & callback); +template <> +void Script::subscribe(const EventHandler<ButtonEnterEvent> & callback, event_channel_t) + = delete; } // namespace crepe #include "Script.hpp" diff --git a/src/crepe/api/Script.hpp b/src/crepe/api/Script.hpp index 225a51c..c7fa6ff 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" @@ -13,7 +14,8 @@ T & Script::get_component() const { RefVector<T> all_components = this->get_components<T>(); if (all_components.size() < 1) throw runtime_error( - format("Script: no component found with type = {}", typeid(T).name())); + format("Script: no component found with type = {}", typeid(T).name()) + ); return all_components.back().get(); } @@ -23,22 +25,39 @@ 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> -void Script::subscribe_internal(const EventHandler<EventType> & callback, - event_channel_t channel) { +void Script::subscribe_internal( + const EventHandler<EventType> & callback, event_channel_t channel +) { 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); + channel + ); this->listeners.push_back(listener); } @@ -52,6 +71,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..b24f0ac 100644 --- a/src/crepe/api/Text.cpp +++ b/src/crepe/api/Text.cpp @@ -1,11 +1,11 @@ -#include "../facade/FontFacade.h" - #include "Text.h" using namespace crepe; -Text::Text(game_object_id_t id, const vec2 & dimensions, const vec2 & offset, - const std::string & font_family, const Data & data, const std::string & text) +Text::Text( + game_object_id_t id, const vec2 & dimensions, const vec2 & offset, + const std::string & font_family, const Data & data, const std::string & text +) : UIObject(id, dimensions, offset), text(text), data(data), diff --git a/src/crepe/api/Text.h b/src/crepe/api/Text.h index c30dc80..0289b85 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" @@ -50,8 +48,10 @@ public: * \param data Data struct containing extra text parameters. * \param font Optional font asset that can be passed or left empty. */ - Text(game_object_id_t id, const vec2 & dimensions, const vec2 & offset, - const std::string & font_family, const Data & data, const std::string & text = ""); + Text( + game_object_id_t id, const vec2 & dimensions, const vec2 & offset, + const std::string & font_family, const Data & data, const std::string & text = "" + ); //! Label text. std::string text = ""; diff --git a/src/crepe/api/Transform.cpp b/src/crepe/api/Transform.cpp index a85b792..b70174c 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/UIObject.h b/src/crepe/api/UIObject.h index f7f4fba..f1318ab 100644 --- a/src/crepe/api/UIObject.h +++ b/src/crepe/api/UIObject.h @@ -20,6 +20,8 @@ public: vec2 dimensions; //! Position offset relative to this GameObjects Transform vec2 offset; + //! variable indicating if transform is relative to camera(false) or world(true) + bool world_space = false; }; } // 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 |