aboutsummaryrefslogtreecommitdiff
path: root/src/crepe
diff options
context:
space:
mode:
authorLoek Le Blansch <loek@pipeframe.xyz>2024-12-07 14:21:31 +0100
committerLoek Le Blansch <loek@pipeframe.xyz>2024-12-07 14:21:31 +0100
commite7423549a26c0df6db930329e2c4067b1c6777b7 (patch)
tree0de96a7b935fead6cc9b5d04d09d713047372b1f /src/crepe
parentf3009ab8f0785a54d3fd83c0d758c8ebd901adda (diff)
parentfdb4c99e139a264d4e15e6913a3756fc6cccb2f2 (diff)
merge with master
Diffstat (limited to 'src/crepe')
-rw-r--r--src/crepe/Collider.cpp2
-rw-r--r--src/crepe/Collider.h13
-rw-r--r--src/crepe/Component.h2
-rw-r--r--src/crepe/api/Animator.cpp50
-rw-r--r--src/crepe/api/Animator.h94
-rw-r--r--src/crepe/api/AssetManager.h6
-rw-r--r--src/crepe/api/BoxCollider.cpp10
-rw-r--r--src/crepe/api/BoxCollider.h22
-rw-r--r--src/crepe/api/Button.h6
-rw-r--r--src/crepe/api/CMakeLists.txt8
-rw-r--r--src/crepe/api/Camera.cpp11
-rw-r--r--src/crepe/api/Camera.h38
-rw-r--r--src/crepe/api/CircleCollider.cpp8
-rw-r--r--src/crepe/api/CircleCollider.h16
-rw-r--r--src/crepe/api/Config.h9
-rw-r--r--src/crepe/api/Event.h4
-rw-r--r--src/crepe/api/EventHandler.h34
-rw-r--r--src/crepe/api/GameObject.h12
-rw-r--r--src/crepe/api/LoopManager.cpp14
-rw-r--r--src/crepe/api/Metadata.h2
-rw-r--r--src/crepe/api/Rigidbody.cpp4
-rw-r--r--src/crepe/api/Rigidbody.h144
-rw-r--r--src/crepe/api/Scene.h4
-rw-r--r--src/crepe/api/Script.h3
-rw-r--r--src/crepe/api/Sprite.cpp16
-rw-r--r--src/crepe/api/Sprite.h92
-rw-r--r--src/crepe/api/Transform.h8
-rw-r--r--src/crepe/facade/SDLContext.cpp130
-rw-r--r--src/crepe/facade/SDLContext.h73
-rw-r--r--src/crepe/facade/Sound.h2
-rw-r--r--src/crepe/manager/ComponentManager.h30
-rw-r--r--src/crepe/manager/EventManager.h28
-rw-r--r--src/crepe/manager/Mediator.h4
-rw-r--r--src/crepe/system/AnimatorSystem.cpp31
-rw-r--r--src/crepe/system/AnimatorSystem.h3
-rw-r--r--src/crepe/system/CollisionSystem.cpp548
-rw-r--r--src/crepe/system/CollisionSystem.h298
-rw-r--r--src/crepe/system/InputSystem.cpp8
-rw-r--r--src/crepe/system/ParticleSystem.h10
-rw-r--r--src/crepe/system/PhysicsSystem.cpp13
-rw-r--r--src/crepe/system/PhysicsSystem.h4
-rw-r--r--src/crepe/system/RenderSystem.cpp40
-rw-r--r--src/crepe/system/RenderSystem.h23
-rw-r--r--src/crepe/system/ScriptSystem.h2
44 files changed, 1522 insertions, 357 deletions
diff --git a/src/crepe/Collider.cpp b/src/crepe/Collider.cpp
index bbec488..77e11c8 100644
--- a/src/crepe/Collider.cpp
+++ b/src/crepe/Collider.cpp
@@ -2,4 +2,4 @@
using namespace crepe;
-Collider::Collider(game_object_id_t id) : Component(id) {}
+Collider::Collider(game_object_id_t id, const vec2 & offset) : Component(id), offset(offset) {}
diff --git a/src/crepe/Collider.h b/src/crepe/Collider.h
index 827f83d..42ccfd4 100644
--- a/src/crepe/Collider.h
+++ b/src/crepe/Collider.h
@@ -1,14 +1,23 @@
#pragma once
#include "Component.h"
+#include "types.h"
namespace crepe {
class Collider : public Component {
public:
- Collider(game_object_id_t id);
+ Collider(game_object_id_t id, const vec2 & offset);
- int size;
+public:
+ /**
+ * \brief Offset of the collider relative to the rigidbody position.
+ *
+ * The `offset` defines the positional shift applied to the collider relative to the position of the rigidbody it is attached to.
+ * This allows the collider to be placed at a different position than the rigidbody.
+ *
+ */
+ vec2 offset;
};
} // namespace crepe
diff --git a/src/crepe/Component.h b/src/crepe/Component.h
index dc17721..c30419d 100644
--- a/src/crepe/Component.h
+++ b/src/crepe/Component.h
@@ -8,7 +8,7 @@ class ComponentManager;
/**
* \brief Base class for all components
- *
+ *
* This class is the base class for all components. It provides a common interface for all
* components.
*/
diff --git a/src/crepe/api/Animator.cpp b/src/crepe/api/Animator.cpp
index 45f67f6..b8a91dc 100644
--- a/src/crepe/api/Animator.cpp
+++ b/src/crepe/api/Animator.cpp
@@ -7,21 +7,53 @@
using namespace crepe;
-Animator::Animator(game_object_id_t id, Sprite & ss, int row, int col, int col_animator)
+Animator::Animator(game_object_id_t id, Sprite & spritesheet, unsigned int max_row,
+ unsigned int max_col, const Animator::Data & data)
: Component(id),
- spritesheet(ss),
- row(row),
- col(col) {
+ spritesheet(spritesheet),
+ max_rows(max_row),
+ max_columns(max_col),
+ data(data) {
dbg_trace();
- 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;
+ this->spritesheet.mask.h /= this->max_columns;
+ this->spritesheet.mask.w /= this->max_rows;
+ this->spritesheet.mask.x = this->data.row * this->spritesheet.mask.w;
+ this->spritesheet.mask.y = this->data.col * this->spritesheet.mask.h;
// 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(); }
+
+void Animator::loop() { this->data.looping = true; }
+
+void Animator::play() { this->active = true; }
+
+void Animator::pause() { this->active = false; }
+
+void Animator::stop() {
+ this->active = false;
+ this->data.col = 0;
+ this->data.row = 0;
+}
+void Animator::set_fps(int fps) { this->data.fps = fps; }
+
+void Animator::set_cycle_range(int start, int end) {
+ this->data.cycle_start = start, this->data.cycle_end = end;
+}
+
+void Animator::set_anim(int col) {
+ Animator::Data & ctx = this->data;
+ this->spritesheet.mask.x = ctx.row = 0;
+ ctx.col = col;
+ this->spritesheet.mask.y = ctx.col * this->spritesheet.mask.h;
+}
+
+void Animator::next_anim() {
+ Animator::Data & ctx = this->data;
+ ctx.row = ctx.row++ % this->max_rows;
+ 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 6c506aa..7c850b8 100644
--- a/src/crepe/api/Animator.h
+++ b/src/crepe/api/Animator.h
@@ -1,5 +1,7 @@
#pragma once
+#include "../types.h"
+
#include "Component.h"
#include "Sprite.h"
@@ -16,56 +18,86 @@ class SDLContext;
* sheet. It can be used to play animations, loop them, or stop them.
*/
class Animator : public Component {
+public:
+ struct Data {
+ //! frames per second for animation
+ unsigned int fps = 1;
+ //! The current col being animated.
+ unsigned int col = 0;
+ //! The current row being animated.
+ unsigned int row = 0;
+ //! should the animation loop
+ bool looping = false;
+ //! starting frame for cycling
+ unsigned int cycle_start = 0;
+ //! end frame for cycling (-1 = use last frame)
+ int cycle_end = -1;
+ };
public:
- //TODO: need to implement this
+ //! Animator will repeat the animation
void loop();
+ //! starts the animation
+ void play();
+ //! pauses the animation
+ void pause();
+ /**
+ * \brief stops the animation
+ *
+ * sets the active on false and resets all the current rows and columns
+ */
void stop();
+ /**
+ * \brief set frames per second
+ *
+ * \param fps frames per second
+ */
+ void set_fps(int fps);
+ /**
+ * \brief set the range in the row
+ *
+ * \param start of row animation
+ * \param end of row animation
+ */
+ void set_cycle_range(int start, int end);
+ /**
+ * \brief select which column to animate from
+ *
+ * \param col animation column
+ */
+ void set_anim(int col);
+ //! will go to the next animaiton of current row
+ void next_anim();
public:
/**
* \brief Constructs an Animator object that will control animations for a sprite sheet.
*
* \param id The unique identifier for the component, typically assigned automatically.
- * \param spritesheet A reference to the Sprite object which holds the sprite sheet for
- * animation.
- * \param row The maximum number of rows in the sprite sheet.
- * \param col The maximum number of columns in the sprite sheet.
- * \param col_animate The specific col index of the sprite sheet to animate. This allows
- * selecting which col to animate from multiple col in the sheet.
+ * \param spritesheet the reference to the spritesheet
+ * \param max_row maximum of rows inside the given spritesheet
+ * \param max_col maximum of columns inside the given spritesheet
+ * \param data extra animation data for more control
*
* This constructor sets up the Animator with the given parameters, and initializes the
* animation system.
*/
- Animator(uint32_t id, Sprite & spritesheet, int row, int col, int col_animate);
-
+ Animator(game_object_id_t id, Sprite & spritesheet, unsigned int max_row,
+ unsigned int max_col, const Animator::Data & data);
~Animator(); // dbg_trace
-private:
- //! A reference to the Sprite sheet containing the animation frames.
- Sprite & spritesheet;
-
+public:
//! The maximum number of columns in the sprite sheet.
- const int col;
-
+ const unsigned int max_columns;
//! The maximum number of rows in the sprite sheet.
- const int row;
-
- //! The current col being animated.
- int curr_col = 0;
-
- //! The current row being animated.
- int curr_row = 0;
-
- //TODO: Is this necessary?
- //int fps;
+ const unsigned int max_rows;
+ Animator::Data data;
private:
- //! AnimatorSystem adjust the private member parameters of Animator;
- friend class AnimatorSystem;
-
- //! SDLContext reads the Animator member var's
- friend class SDLContext;
+ //! A reference to the Sprite sheet containing.
+ Sprite & spritesheet;
+ //! Uses the spritesheet
+ friend AnimatorSystem;
};
+
} // namespace crepe
-//
diff --git a/src/crepe/api/AssetManager.h b/src/crepe/api/AssetManager.h
index fee6780..3b1cc4b 100644
--- a/src/crepe/api/AssetManager.h
+++ b/src/crepe/api/AssetManager.h
@@ -9,7 +9,7 @@ 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
@@ -46,9 +46,9 @@ public:
* \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.
diff --git a/src/crepe/api/BoxCollider.cpp b/src/crepe/api/BoxCollider.cpp
new file mode 100644
index 0000000..c097a24
--- /dev/null
+++ b/src/crepe/api/BoxCollider.cpp
@@ -0,0 +1,10 @@
+#include "BoxCollider.h"
+
+#include "../Collider.h"
+
+using namespace crepe;
+
+BoxCollider::BoxCollider(game_object_id_t game_object_id, const vec2 & offset,
+ const vec2 & dimensions)
+ : Collider(game_object_id, offset),
+ dimensions(dimensions) {}
diff --git a/src/crepe/api/BoxCollider.h b/src/crepe/api/BoxCollider.h
new file mode 100644
index 0000000..1ac4d46
--- /dev/null
+++ b/src/crepe/api/BoxCollider.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "../Collider.h"
+#include "Vector2.h"
+#include "types.h"
+
+namespace crepe {
+
+/**
+ * \brief A class representing a box-shaped collider.
+ *
+ * This class is used for collision detection with other colliders (e.g., CircleCollider).
+ */
+class BoxCollider : public Collider {
+public:
+ BoxCollider(game_object_id_t game_object_id, const vec2 & offset, const vec2 & dimensions);
+
+ //! Width and height of the box collider
+ vec2 dimensions;
+};
+
+} // namespace crepe
diff --git a/src/crepe/api/Button.h b/src/crepe/api/Button.h
index 26e7526..61b18d7 100644
--- a/src/crepe/api/Button.h
+++ b/src/crepe/api/Button.h
@@ -11,7 +11,7 @@ class Button : public UIObject {
public:
/**
* \brief Constructs a Button with the specified game object ID and dimensions.
- *
+ *
* \param id The unique ID of the game object associated with this button.
* \param dimensions The width and height of the UIObject
* \param offset The offset relative this GameObjects Transform
@@ -23,7 +23,7 @@ public:
/**
* \brief Indicates if the button is a toggle button (can be pressed and released).
- *
+ *
* A toggle button allows for a pressed/released state, whereas a regular button
* typically only has an on-click state.
*/
@@ -31,7 +31,7 @@ public:
// TODO: create separate toggle button class
/**
* \brief The callback function to be executed when the button is clicked.
- *
+ *
* This function is invoked whenever the button is clicked. It can be set to any
* function that matches the signature `void()`.
*/
diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt
index ac8f301..593c4e6 100644
--- a/src/crepe/api/CMakeLists.txt
+++ b/src/crepe/api/CMakeLists.txt
@@ -13,6 +13,8 @@ target_sources(crepe PUBLIC
Metadata.cpp
Camera.cpp
Animator.cpp
+ BoxCollider.cpp
+ CircleCollider.cpp
IKeyListener.cpp
IMouseListener.cpp
LoopManager.cpp
@@ -37,13 +39,15 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
Vector2.h
Vector2.hpp
Color.h
- Texture.h
- AssetManager.h
+ Texture.h
+ AssetManager.h
AssetManager.hpp
Scene.h
Metadata.h
Camera.h
Animator.h
+ BoxCollider.h
+ CircleCollider.h
EventHandler.h
EventHandler.hpp
Event.h
diff --git a/src/crepe/api/Camera.cpp b/src/crepe/api/Camera.cpp
index 39d8ab0..179dc18 100644
--- a/src/crepe/api/Camera.cpp
+++ b/src/crepe/api/Camera.cpp
@@ -1,20 +1,17 @@
-#include "types.h"
#include "util/Log.h"
#include "Camera.h"
-#include "Color.h"
#include "Component.h"
+#include "types.h"
using namespace crepe;
-Camera::Camera(game_object_id_t id, const Color & bg_color, const ivec2 & screen,
- const vec2 & viewport_size, const double & zoom, const vec2 & offset)
+Camera::Camera(game_object_id_t id, const ivec2 & screen, const vec2 & viewport_size,
+ const Data & data)
: Component(id),
- bg_color(bg_color),
- offset(offset),
screen(screen),
viewport_size(viewport_size),
- zoom(zoom) {
+ data(data) {
dbg_trace();
}
diff --git a/src/crepe/api/Camera.h b/src/crepe/api/Camera.h
index 2d8fa48..54d9a73 100644
--- a/src/crepe/api/Camera.h
+++ b/src/crepe/api/Camera.h
@@ -14,23 +14,42 @@ namespace crepe {
* position, and zoom level. It controls what part of the game world is visible on the screen.
*/
class Camera : public Component {
+public:
+ struct Data {
+ /**
+ * \bg_color background color of the game
+ *
+ * This will make the background the same color as the given value.
+ */
+ const Color bg_color = Color::BLACK;
+
+ /**
+ * \zoom Zooming level of the game
+ *
+ * zoom = 1 --> no zoom.
+ * zoom < 1 --> zoom out
+ * zoom > 1 --> zoom in
+ */
+ double zoom = 1;
+
+ //! offset postion from the game object transform component
+ vec2 postion_offset;
+ };
public:
/**
* \brief Constructs a Camera with the specified ID and background color.
* \param id Unique identifier for the camera component.
- * \param bg_color Background color for the camera view.
+ * \param screen is the actual screen size in pixels
+ * \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 Color & bg_color, const ivec2 & screen,
- const vec2 & viewport_size, const double & zoom, const vec2 & offset = {0, 0});
+ Camera(game_object_id_t id, const ivec2 & screen, const vec2 & viewport_size,
+ const Camera::Data & data);
~Camera(); // dbg_trace only
public:
- //! Background color of the camera view.
- const Color bg_color;
-
- //! offset postion from the game object transform component
- vec2 offset;
+ Camera::Data data;
//! screen the display size in pixels ( output resolution )
const ivec2 screen;
@@ -38,9 +57,6 @@ public:
//! viewport is the area of the world visible through the camera (in world units)
const vec2 viewport_size;
- //! Zoom level of the camera view.
- const double zoom;
-
public:
/**
* \brief Gets the maximum number of camera instances allowed.
diff --git a/src/crepe/api/CircleCollider.cpp b/src/crepe/api/CircleCollider.cpp
new file mode 100644
index 0000000..a4271e9
--- /dev/null
+++ b/src/crepe/api/CircleCollider.cpp
@@ -0,0 +1,8 @@
+#include "CircleCollider.h"
+
+using namespace crepe;
+
+CircleCollider::CircleCollider(game_object_id_t game_object_id, const vec2 & offset,
+ float radius)
+ : Collider(game_object_id, offset),
+ radius(radius) {}
diff --git a/src/crepe/api/CircleCollider.h b/src/crepe/api/CircleCollider.h
index e77a592..c7bf66e 100644
--- a/src/crepe/api/CircleCollider.h
+++ b/src/crepe/api/CircleCollider.h
@@ -1,14 +1,22 @@
#pragma once
+
+#include "Vector2.h"
+
#include "../Collider.h"
namespace crepe {
+/**
+ * \brief A class representing a circle-shaped collider.
+ *
+ * This class is used for collision detection with other colliders (e.g., BoxCollider).
+ */
class CircleCollider : public Collider {
public:
- CircleCollider(game_object_id_t game_object_id, int radius)
- : Collider(game_object_id),
- radius(radius) {}
- int radius;
+ CircleCollider(game_object_id_t game_object_id, const vec2 & offset, float radius);
+
+ //! Radius of the circle collider.
+ float radius;
};
} // namespace crepe
diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h
index 225e9b9..a9745c3 100644
--- a/src/crepe/api/Config.h
+++ b/src/crepe/api/Config.h
@@ -1,8 +1,10 @@
#pragma once
+#include <string>
+
#include "../util/Log.h"
+
#include "types.h"
-#include <string>
namespace crepe {
@@ -66,10 +68,9 @@ public:
//! default window settings
struct {
- //TODO make this constexpr because this will never change
- ivec2 default_size = {1080, 720};
+ //! default screen size in pixels
+ ivec2 default_size = {1280, 720};
std::string window_title = "Jetpack joyride clone";
-
} window_settings;
//! Asset loading options
diff --git a/src/crepe/api/Event.h b/src/crepe/api/Event.h
index 6298118..f2f3daf 100644
--- a/src/crepe/api/Event.h
+++ b/src/crepe/api/Event.h
@@ -112,10 +112,6 @@ public:
//! scroll amount in y axis (from and away from the person).
float scroll_delta = 0;
};
-/**
- * \brief Event triggered during a collision between objects.
- */
-class CollisionEvent : public Event {};
/**
* \brief Event triggered when text is submitted, e.g., from a text input.
diff --git a/src/crepe/api/EventHandler.h b/src/crepe/api/EventHandler.h
index 7bdd9a3..7bb501b 100644
--- a/src/crepe/api/EventHandler.h
+++ b/src/crepe/api/EventHandler.h
@@ -8,12 +8,12 @@
namespace crepe {
/**
* \brief A type alias for an event handler function.
- *
- * The EventHandler is a std::function that takes an EventType reference and returns a boolean value
+ *
+ * The EventHandler is a std::function that takes an EventType reference and returns a boolean value
* indicating whether the event is handled.
- *
+ *
* \tparam EventType The type of event this handler will handle.
- *
+ *
* Returning \c false from an event handler results in the event being propogated to other listeners for the same event type, while returning \c true stops propogation altogether.
*/
template <typename EventType>
@@ -22,7 +22,7 @@ using EventHandler = std::function<bool(const EventType & e)>;
/**
* \class IEventHandlerWrapper
* \brief An abstract base class for event handler wrappers.
- *
+ *
* This class provides the interface for handling events. Derived classes must implement the
* `call()` method to process events
*/
@@ -35,9 +35,9 @@ public:
/**
* \brief Executes the handler with the given event.
- *
+ *
* This method calls the `call()` method of the derived class, passing the event to the handler.
- *
+ *
* \param e The event to be processed.
* \return A boolean value indicating whether the event is handled.
*/
@@ -46,9 +46,9 @@ public:
private:
/**
* \brief The method responsible for handling the event.
- *
+ *
* This method is implemented by derived classes to process the event.
- *
+ *
* \param e The event to be processed.
* \return A boolean value indicating whether the event is handled.
*/
@@ -58,11 +58,11 @@ private:
/**
* \class EventHandlerWrapper
* \brief A wrapper for event handler functions.
- *
- * This class wraps an event handler function of a specific event type. It implements the
- * `call()` and `get_type()` methods to allow the handler to be executed and its type to be
+ *
+ * This class wraps an event handler function of a specific event type. It implements the
+ * `call()` and `get_type()` methods to allow the handler to be executed and its type to be
* queried.
- *
+ *
* \tparam EventType The type of event this handler will handle.
*/
template <typename EventType>
@@ -70,9 +70,9 @@ class EventHandlerWrapper : public IEventHandlerWrapper {
public:
/**
* \brief Constructs an EventHandlerWrapper with a given handler.
- *
+ *
* The constructor takes an event handler function and stores it in the wrapper.
- *
+ *
* \param handler The event handler function.
*/
explicit EventHandlerWrapper(const EventHandler<EventType> & handler);
@@ -80,9 +80,9 @@ public:
private:
/**
* \brief Calls the stored event handler with the event.
- *
+ *
* This method casts the event to the appropriate type and calls the handler.
- *
+ *
* \param e The event to be handled.
* \return A boolean value indicating whether the event is handled.
*/
diff --git a/src/crepe/api/GameObject.h b/src/crepe/api/GameObject.h
index 4cd2bc0..ff80f49 100644
--- a/src/crepe/api/GameObject.h
+++ b/src/crepe/api/GameObject.h
@@ -10,7 +10,7 @@ class ComponentManager;
/**
* \brief Represents a GameObject
- *
+ *
* This class represents a GameObject. The GameObject class is only used as an interface for
* the game programmer. The actual implementation is done in the ComponentManager.
*/
@@ -19,7 +19,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 id The id of the GameObject
* \param name The name of the GameObject
@@ -37,20 +37,20 @@ private:
public:
/**
* \brief Set the parent of this GameObject
- *
+ *
* This method sets the parent of this GameObject. It sets the parent in the Metadata
* component of this GameObject and adds this GameObject to the children list of the parent
* GameObject.
- *
+ *
* \param parent The parent GameObject
*/
void set_parent(const GameObject & parent);
/**
* \brief Add a component to the GameObject
- *
+ *
* This method adds a component to the GameObject. It forwards the arguments to the
* ComponentManager.
- *
+ *
* \tparam T The type of the component
* \tparam Args The types of the arguments
* \param args The arguments to create the component
diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp
index 8fef0c4..044f096 100644
--- a/src/crepe/api/LoopManager.cpp
+++ b/src/crepe/api/LoopManager.cpp
@@ -5,6 +5,7 @@
#include "../system/PhysicsSystem.h"
#include "../system/RenderSystem.h"
#include "../system/ScriptSystem.h"
+#include "manager/EventManager.h"
#include "LoopManager.h"
@@ -29,7 +30,14 @@ void LoopManager::start() {
}
void LoopManager::set_running(bool running) { this->game_running = running; }
-void LoopManager::fixed_update() {}
+void LoopManager::fixed_update() {
+ // TODO: retrieve EventManager from direct member after singleton refactor
+ EventManager & ev = this->mediator.event_manager;
+ ev.dispatch_events();
+ this->get_system<ScriptSystem>().update();
+ this->get_system<PhysicsSystem>().update();
+ this->get_system<CollisionSystem>().update();
+}
void LoopManager::loop() {
LoopTimer & timer = this->loop_timer;
@@ -53,15 +61,17 @@ void LoopManager::loop() {
void LoopManager::setup() {
LoopTimer & timer = this->loop_timer;
-
this->game_running = true;
+ this->scene_manager.load_next_scene();
timer.start();
timer.set_fps(200);
+ this->scene_manager.load_next_scene();
}
void LoopManager::render() {
if (!this->game_running) return;
+ this->get_system<AnimatorSystem>().update();
this->get_system<RenderSystem>().update();
}
diff --git a/src/crepe/api/Metadata.h b/src/crepe/api/Metadata.h
index 235d42f..f404703 100644
--- a/src/crepe/api/Metadata.h
+++ b/src/crepe/api/Metadata.h
@@ -9,7 +9,7 @@ namespace crepe {
/**
* \brief Metadata component
- *
+ *
* This class represents the Metadata component. It stores the name, tag, parent and children
* of a GameObject.
*/
diff --git a/src/crepe/api/Rigidbody.cpp b/src/crepe/api/Rigidbody.cpp
index 576ca45..8213afb 100644
--- a/src/crepe/api/Rigidbody.cpp
+++ b/src/crepe/api/Rigidbody.cpp
@@ -10,6 +10,4 @@ void crepe::Rigidbody::add_force_linear(const vec2 & force) {
this->data.linear_velocity += force;
}
-void crepe::Rigidbody::add_force_angular(double force) {
- this->data.angular_velocity += force;
-}
+void crepe::Rigidbody::add_force_angular(float force) { this->data.angular_velocity += force; }
diff --git a/src/crepe/api/Rigidbody.h b/src/crepe/api/Rigidbody.h
index 3b0588f..40c6bf1 100644
--- a/src/crepe/api/Rigidbody.h
+++ b/src/crepe/api/Rigidbody.h
@@ -1,5 +1,8 @@
#pragma once
+#include <cmath>
+#include <set>
+
#include "../Component.h"
#include "types.h"
@@ -8,7 +11,7 @@ namespace crepe {
/**
* \brief Rigidbody class
- *
+ *
* This class is used by the physics sytem and collision system. It configures how to system
* interact with the gameobject for movement and collisions.
*/
@@ -16,7 +19,7 @@ class Rigidbody : public Component {
public:
/**
* \brief BodyType enum
- *
+ *
* This enum provides three bodytypes the physics sytem and collision system use.
*/
enum class BodyType {
@@ -29,54 +32,118 @@ public:
};
/**
* \brief PhysicsConstraints to constrain movement
- *
+ *
* This struct configures the movement constraint for this object. If a constraint is enabled
* the systems will not move the object.
*/
struct PhysicsConstraints {
- //! X constraint
+ //! Prevent movement along X axis
bool x = false;
- //! Y constraint
+ //! Prevent movement along Y axis
bool y = false;
- //! rotation constraint
+ //! Prevent rotation
bool rotation = false;
};
public:
- /**
+ /**
* \brief struct for Rigidbody data
- *
+ *
* This struct holds the data for the Rigidbody.
*/
struct Data {
//! objects mass
- double mass = 0.0;
- //! gravtiy scale
- double gravity_scale = 0.0;
- //! Changes if physics apply
+ float mass = 0.0;
+ /**
+ * \brief Gravity scale factor.
+ *
+ * The `gravity_scale` controls how much gravity affects the object. It is a multiplier applied to the default
+ * gravity force, allowing for fine-grained control over how the object responds to gravity.
+ *
+ */
+ float gravity_scale = 0;
+
+ //! Defines the type of the physics body, which determines how the physics system interacts with the object.
BodyType body_type = BodyType::DYNAMIC;
- //! linear velocity of object
+
+ /**
+ * \name Linear (positional) motion
+ *
+ * These variables define the linear motion (movement along the position) of an object.
+ * The linear velocity is applied to the object's position in each update of the PhysicsSystem.
+ * The motion is affected by the object's linear velocity, its maximum velocity, and a coefficient
+ * that can scale the velocity over time.
+ *
+ * \{
+ */
+ //! Linear velocity of the object (speed and direction).
vec2 linear_velocity;
- //! maximum linear velocity of object
- vec2 max_linear_velocity;
- //! linear damping of object
- vec2 linear_damping;
- //! angular velocity of object
- double angular_velocity = 0.0;
- //! max angular velocity of object
- double max_angular_velocity = 0.0;
- //! angular damping of object
- double angular_damping = 0.0;
- //! movements constraints of object
+ //! Maximum linear velocity of the object. This limits the object's speed.
+ vec2 max_linear_velocity = {INFINITY, INFINITY};
+ //! Linear velocity coefficient. This scales the object's velocity for adjustment or damping.
+ vec2 linear_velocity_coefficient = {1, 1};
+ //! \}
+
+ /**
+ * \name Angular (rotational) motion
+ *
+ * These variables define the angular motion (rotation) of an object.
+ * The angular velocity determines how quickly the object rotates, while the maximum angular velocity
+ * sets a limit on the rotation speed. The angular velocity coefficient applies damping or scaling
+ * to the angular velocity, which can be used to simulate friction or other effects that slow down rotation.
+ *
+ * \{
+ */
+ //! Angular velocity of the object, representing the rate of rotation (in degrees).
+ float angular_velocity = 0;
+ //! Maximum angular velocity of the object. This limits the maximum rate of rotation.
+ float max_angular_velocity = INFINITY;
+ //! Angular velocity coefficient. This scales the object's angular velocity, typically used for damping.
+ float angular_velocity_coefficient = 1;
+ //! \}
+
+ /**
+ * \brief Movement constraints for an object.
+ *
+ * The `PhysicsConstraints` struct defines the constraints that restrict an object's movement
+ * in certain directions or prevent rotation. These constraints effect only the physics system
+ * to prevent the object from moving or rotating in specified ways.
+ *
+ */
PhysicsConstraints constraints;
- //! if gravity applies
- bool use_gravity = true;
- //! if object bounces
- bool bounce = false;
+
+ /**
+ * \brief Elasticity factor of the material (bounce factor).
+ *
+ * The `elasticity_coefficient` controls how much of the object's velocity is retained after a collision.
+ * It represents the material's ability to bounce or recover velocity upon impact. The coefficient is a value
+ * above 0.0.
+ *
+ */
+ float elastisity_coefficient = 0.0;
+
+ /**
+ * \brief Offset of all colliders relative to the object's transform position.
+ *
+ * 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.
+ *
+ */
+ vec2 offset;
+
+ /**
+ * \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.
+ */
+ std::set<int> collision_layers;
};
public:
- /**
+ /**
* \param game_object_id id of the gameobject the rigibody is added to.
* \param data struct to configure the rigidbody.
*/
@@ -85,18 +152,27 @@ public:
Data data;
public:
- /**
+ /**
* \brief add a linear force to the Rigidbody.
- *
+ *
* \param force Vector2 that is added to the linear force.
*/
void add_force_linear(const vec2 & force);
- /**
+ /**
* \brief add a angular force to the Rigidbody.
- *
+ *
* \param force Vector2 that is added to the angular force.
*/
- void add_force_angular(double force);
+ void add_force_angular(float force);
+
+protected:
+ /**
+ * Ensures there is at most one Rigidbody component per entity.
+ * \return Always returns 1, indicating this constraint.
+ */
+ virtual int get_instances_max() const { return 1; }
+ //! ComponentManager instantiates all components
+ friend class ComponentManager;
};
} // namespace crepe
diff --git a/src/crepe/api/Scene.h b/src/crepe/api/Scene.h
index 9f1e8ce..ba9bb76 100644
--- a/src/crepe/api/Scene.h
+++ b/src/crepe/api/Scene.h
@@ -12,7 +12,7 @@ class ComponentManager;
/**
* \brief Represents a Scene
- *
+ *
* This class represents a Scene. The Scene class is only used as an interface for the game
* programmer.
*/
@@ -41,7 +41,7 @@ public:
protected:
/**
* \name Late references
- *
+ *
* These references are set by SceneManager immediately after calling the constructor of Scene.
*
* \note Scene must have a constructor without arguments so the game programmer doesn't need to
diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h
index a040608..49bdcf5 100644
--- a/src/crepe/api/Script.h
+++ b/src/crepe/api/Script.h
@@ -4,6 +4,7 @@
#include "../manager/EventManager.h"
#include "../manager/Mediator.h"
+#include "../system/CollisionSystem.h"
#include "../types.h"
#include "../util/OptionalRef.h"
@@ -19,7 +20,7 @@ class ComponentManager;
* This class is used as a base class for user-defined scripts that can be added to game
* objects using the \c BehaviorScript component.
*
- * \info Additional *events* (like Unity's OnDisable and OnEnable) should be implemented as
+ * \note Additional *events* (like Unity's OnDisable and OnEnable) should be implemented as
* member or lambda methods in derivative user script classes and registered in \c init().
*
* \warning Concrete scripts are allowed do create a custom constructor, but the utility
diff --git a/src/crepe/api/Sprite.cpp b/src/crepe/api/Sprite.cpp
index 0a2ad4c..cc0e20a 100644
--- a/src/crepe/api/Sprite.cpp
+++ b/src/crepe/api/Sprite.cpp
@@ -6,24 +6,20 @@
#include "Component.h"
#include "Sprite.h"
#include "Texture.h"
+#include "types.h"
using namespace std;
using namespace crepe;
-Sprite::Sprite(game_object_id_t id, Texture & image, const Color & color,
- const FlipSettings & flip, int sort_layer, int order_layer, int height)
+Sprite::Sprite(game_object_id_t id, Texture & texture, const Sprite::Data & data)
: Component(id),
- color(color),
- flip(flip),
- sprite_image(std::move(image)),
- sorting_in_layer(sort_layer),
- order_in_layer(order_layer),
- height(height) {
+ texture(std::move(texture)),
+ data(data) {
dbg_trace();
- this->mask.w = sprite_image.get_size().x;
- this->mask.h = sprite_image.get_size().y;
+ this->mask.w = this->texture.get_size().x;
+ this->mask.h = this->texture.get_size().y;
this->aspect_ratio = static_cast<double>(this->mask.w) / this->mask.h;
}
diff --git a/src/crepe/api/Sprite.h b/src/crepe/api/Sprite.h
index a0e90a0..dbf41e4 100644
--- a/src/crepe/api/Sprite.h
+++ b/src/crepe/api/Sprite.h
@@ -1,11 +1,10 @@
#pragma once
-#include <cstdint>
-
#include "../Component.h"
#include "Color.h"
#include "Texture.h"
+#include "types.h"
namespace crepe {
@@ -20,60 +19,79 @@ class AnimatorSystem;
* flip settings, and is managed in layers with defined sorting orders.
*/
class Sprite : public Component {
-
public:
+ //! settings to flip the image
struct FlipSettings {
+ //! horizantal flip
bool flip_x = false;
+ //! vertical flip
bool flip_y = false;
};
+ //! Sprite data that does not have to be set in the constructor
+ struct Data {
+ /**
+ * \brief Sprite tint (multiplied)
+ *
+ * The sprite texture's pixels are multiplied by this color before being displayed
+ * (including alpha channel for transparency).
+ */
+ Color color = Color::WHITE;
+
+ //! Flip settings for the sprite
+ FlipSettings flip;
+
+ //! Layer sorting level of the sprite
+ const int sorting_in_layer = 0;
+
+ //! Order within the sorting layer
+ const int order_in_layer = 0;
+
+ /**
+ * \brief width and height of the sprite in game units
+ *
+ * - if exclusively width is specified, the height is calculated using the texture's aspect
+ * ratio
+ * - if exclusively height is specified, the width is calculated using the texture's aspect
+ * ratio
+ * - if both are specified the texture is streched to fit the specified size
+ */
+ vec2 size = {0, 0};
+
+ //! independent sprite angle. rotating clockwise direction in degrees
+ float angle_offset = 0;
+
+ //! independent sprite scale multiplier
+ float scale_offset = 1;
+
+ //! independent sprite offset position
+ vec2 position_offset;
+ };
+
public:
- // TODO: Loek comment in github #27 will be looked another time
- // about shared_ptr Texture
/**
- * \brief Constructs a Sprite with specified parameters.
* \param game_id Unique identifier for the game object this sprite belongs to.
- * \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, Texture & image, const Color & color,
- const FlipSettings & flip, int sort_layer, int order_layer, int height);
-
- /**
- * \brief Destroys the Sprite instance.
+ * \param texture asset of the image
+ * \param ctx all the sprite data
*/
+ Sprite(game_object_id_t id, Texture & texture, const Data & data);
~Sprite();
//! Texture used for the sprite
- const Texture sprite_image;
-
- //! Color tint of the sprite
- Color color;
-
- //! Flip settings for the sprite
- FlipSettings flip;
+ const Texture texture;
- //! Layer sorting level of the sprite
- const int sorting_in_layer;
- //! Order within the sorting layer
- const int order_in_layer;
-
- //! height in world units
- const int height;
+ Data data;
+private:
/**
- * \aspect_ratio ratio of the img so that scaling will not become weird
+ * \brief ratio of the img
*
- * cannot be const because if Animator component is addded then ratio becomes scuffed and
- * does it need to be calculated again in the Animator
+ * - This will multiply one of \c size variable if it is 0.
+ * - Will be adjusted if \c Animator component is added to an GameObject that is why this
+ * value cannot be const.
*/
- double aspect_ratio;
+ float aspect_ratio;
-private:
//! Reads the mask of sprite
friend class SDLContext;
diff --git a/src/crepe/api/Transform.h b/src/crepe/api/Transform.h
index 6243a93..7ee6d65 100644
--- a/src/crepe/api/Transform.h
+++ b/src/crepe/api/Transform.h
@@ -7,7 +7,7 @@ namespace crepe {
/**
* \brief Transform component
- *
+ *
* This class represents the Transform component. It stores the position, rotation and scale of
* a GameObject.
*/
@@ -15,10 +15,10 @@ class Transform : public Component {
public:
//! Translation (shift)
vec2 position = {0, 0};
- //! Rotation, in degrees
- double rotation = 0;
+ //! Rotation, in degrees clockwise
+ float rotation = 0;
//! Multiplication factor
- double scale = 0;
+ float scale = 0;
protected:
/**
diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp
index ad9f1f0..4cc2206 100644
--- a/src/crepe/facade/SDLContext.cpp
+++ b/src/crepe/facade/SDLContext.cpp
@@ -11,19 +11,17 @@
#include <cstddef>
#include <cstdint>
#include <functional>
-#include <iostream>
#include <memory>
#include <stdexcept>
#include "../api/Camera.h"
+#include "../api/Color.h"
#include "../api/Config.h"
#include "../api/Sprite.h"
#include "../api/Texture.h"
-#include "../manager/EventManager.h"
#include "../util/Log.h"
#include "SDLContext.h"
-#include "api/Color.h"
#include "types.h"
using namespace crepe;
@@ -215,11 +213,13 @@ MouseButton SDLContext::sdl_to_mousebutton(Uint8 sdl_button) {
return MOUSE_BUTTON_LOOKUP_TABLE[sdl_button];
}
-void SDLContext::clear_screen() {
+void SDLContext::clear_screen() { SDL_RenderClear(this->game_renderer.get()); }
+void SDLContext::present_screen() {
SDL_SetRenderDrawColor(this->game_renderer.get(), 0, 0, 0, 255);
- SDL_RenderClear(this->game_renderer.get());
+ SDL_RenderFillRectF(this->game_renderer.get(), &black_bars[0]);
+ SDL_RenderFillRectF(this->game_renderer.get(), &black_bars[1]);
+ SDL_RenderPresent(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{
@@ -229,40 +229,62 @@ SDL_Rect SDLContext::get_src_rect(const Sprite & sprite) const {
.h = sprite.mask.h,
};
}
-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;
+SDL_FRect SDLContext::get_dst_rect(const DestinationRectangleData & ctx) const {
- width *= img_scale * cam.zoom;
- height *= img_scale * cam.zoom;
+ const Sprite::Data & data = ctx.sprite.data;
- return SDL_Rect{
- .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,
+ vec2 size;
+ if (data.size.x == 0 && data.size.y != 0) {
+ size.x = data.size.y * ctx.sprite.aspect_ratio;
+ }
+ if (data.size.y == 0 && data.size.x != 0) {
+ size.y = data.size.x / ctx.sprite.aspect_ratio;
+ }
+
+ const CameraValues & cam = ctx.cam;
+
+ size *= cam.render_scale * ctx.img_scale * data.scale_offset;
+
+ vec2 screen_pos
+ = (ctx.pos + data.position_offset - cam.cam_pos + (cam.zoomed_viewport) / 2)
+ * cam.render_scale
+ - size / 2 + cam.bar_size;
+
+ return SDL_FRect{
+ .x = screen_pos.x,
+ .y = screen_pos.y,
+ .w = size.x,
+ .h = size.y,
};
}
void SDLContext::draw(const RenderContext & ctx) {
+ const Sprite::Data & data = ctx.sprite.data;
SDL_RendererFlip render_flip
- = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * ctx.sprite.flip.flip_x)
- | (SDL_FLIP_VERTICAL * ctx.sprite.flip.flip_y));
+ = (SDL_RendererFlip) ((SDL_FLIP_HORIZONTAL * data.flip.flip_x)
+ | (SDL_FLIP_VERTICAL * data.flip.flip_y));
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);
-
- this->set_color_texture(ctx.sprite.sprite_image, ctx.sprite.color);
- SDL_RenderCopyEx(this->game_renderer.get(), ctx.sprite.sprite_image.texture.get(),
- &srcrect, &dstrect, ctx.angle, NULL, render_flip);
+ SDL_FRect dstrect = this->get_dst_rect(SDLContext::DestinationRectangleData{
+ .sprite = ctx.sprite,
+ .cam = ctx.cam,
+ .pos = ctx.pos,
+ .img_scale = ctx.scale,
+ });
+
+ double angle = ctx.angle + data.angle_offset;
+
+ this->set_color_texture(ctx.sprite.texture, ctx.sprite.data.color);
+ SDL_RenderCopyExF(this->game_renderer.get(), ctx.sprite.texture.texture.get(), &srcrect,
+ &dstrect, angle, NULL, render_flip);
}
-void SDLContext::set_camera(const Camera & cam) {
+SDLContext::CameraValues SDLContext::set_camera(const Camera & cam) {
+ const Camera::Data & cam_data = cam.data;
+ CameraValues ret_cam;
// resize window
int w, h;
SDL_GetWindowSize(this->game_window.get(), &w, &h);
@@ -270,42 +292,52 @@ void SDLContext::set_camera(const Camera & cam) {
SDL_SetWindowSize(this->game_window.get(), cam.screen.x, cam.screen.y);
}
- double screen_aspect = cam.screen.x / cam.screen.y;
- double viewport_aspect = cam.viewport_size.x / cam.viewport_size.y;
+ vec2 & zoomed_viewport = ret_cam.zoomed_viewport;
+ vec2 & bar_size = ret_cam.bar_size;
+ vec2 & render_scale = ret_cam.render_scale;
+
+ zoomed_viewport = cam.viewport_size * cam_data.zoom;
+ float screen_aspect = static_cast<float>(cam.screen.x) / cam.screen.y;
+ float viewport_aspect = zoomed_viewport.x / zoomed_viewport.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;
+ float scale = cam.screen.y / zoomed_viewport.y;
+ float adj_width = zoomed_viewport.x * scale;
+ float bar_width = (cam.screen.x - adj_width) / 2;
+ this->black_bars[0] = {0, 0, bar_width, (float) cam.screen.y};
+ this->black_bars[1] = {(cam.screen.x - bar_width), 0, bar_width, (float) cam.screen.y};
+
+ bar_size = {bar_width, 0};
+ render_scale.x = render_scale.y = scale;
+ } else {
+ // letterboxing
+ float scale = cam.screen.x / (cam.viewport_size.x * cam_data.zoom);
+ float adj_height = cam.viewport_size.y * scale;
+ float bar_height = (cam.screen.y - adj_height) / 2;
+ this->black_bars[0] = {0, 0, (float) cam.screen.x, bar_height};
+ this->black_bars[1]
+ = {0, (cam.screen.y - bar_height), (float) cam.screen.x, bar_height};
+
+ bar_size = {0, bar_height};
+ render_scale.x = render_scale.y = scale;
}
- // set drawing area
- SDL_RenderSetViewport(this->game_renderer.get(), &view);
-
- 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_SetRenderDrawColor(this->game_renderer.get(), cam_data.bg_color.r, cam_data.bg_color.g,
+ cam_data.bg_color.b, cam_data.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),
+ .w = cam.screen.x,
+ .h = cam.screen.y,
};
+
// fill bg color
SDL_RenderFillRect(this->game_renderer.get(), &bg);
+
+ return ret_cam;
}
uint64_t SDLContext::get_ticks() const { return SDL_GetTicks64(); }
diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h
index a2b34c1..e232511 100644
--- a/src/crepe/facade/SDLContext.h
+++ b/src/crepe/facade/SDLContext.h
@@ -9,11 +9,9 @@
#include <functional>
#include <memory>
#include <string>
-#include <utility>
#include "api/Camera.h"
#include "api/Color.h"
-#include "api/Event.h"
#include "api/KeyCodes.h"
#include "api/Sprite.h"
#include "api/Texture.h"
@@ -27,16 +25,44 @@ class InputSystem;
/**
* \class SDLContext
* \brief Facade for the SDL library
- *
+ *
* SDLContext is a singleton that handles the SDL window and renderer, provides methods for
* event handling, and rendering to the screen. It is never used directly by the user
*/
class SDLContext {
public:
+ //! data that the camera component cannot hold
+ struct CameraValues {
+
+ //! zoomed in viewport in game_units
+ vec2 zoomed_viewport;
+
+ /**
+ * \brief scaling factor
+ *
+ * depending on the black bars type will the scaling be different.
+ * - letterboxing --> scaling on the y-as
+ * - pillarboxing --> scaling on the x-as
+ */
+ vec2 render_scale;
+
+ /**
+ * \brief size of calculated black bars
+ *
+ * depending on the black bars type will the size be different
+ * - lettorboxing --> {0, bar_height}
+ * - pillarboxing --> {bar_width , 0}
+ */
+ vec2 bar_size;
+
+ //! Calculated camera position
+ vec2 cam_pos;
+ };
+
+ //! rendering data needed to render on screen
struct RenderContext {
const Sprite & sprite;
- const Camera & cam;
- const vec2 & cam_pos;
+ const CameraValues & cam;
const vec2 & pos;
const double & angle;
const double & scale;
@@ -82,21 +108,21 @@ private:
friend class InputSystem;
/**
* \brief Retrieves a list of all events from the SDL context.
- *
+ *
* This method retrieves all the events from the SDL context that are currently
* available. It is primarily used by the InputSystem to process various
* input events such as mouse clicks, mouse movements, and keyboard presses.
- *
+ *
* \return Events that occurred since last call to `get_events()`
*/
std::vector<SDLContext::EventData> get_events();
/**
* \brief Converts an SDL key code to the custom Keycode type.
- *
+ *
* This method maps an SDL key code to the corresponding `Keycode` enum value,
* which is used internally by the system to identify the keys.
- *
+ *
* \param sdl_key The SDL key code to convert.
* \return The corresponding `Keycode` value or `Keycode::NONE` if the key is unrecognized.
*/
@@ -104,18 +130,16 @@ private:
/**
* \brief Converts an SDL mouse button code to the custom MouseButton type.
- *
- * This method maps an SDL mouse button code to the corresponding `MouseButton`
+ *
+ * This method maps an SDL mouse button code to the corresponding `MouseButton`
* enum value, which is used internally by the system to identify mouse buttons.
- *
+ *
* \param sdl_button The SDL mouse button code to convert.
* \return The corresponding `MouseButton` value or `MouseButton::NONE` if the key is unrecognized
*/
MouseButton sdl_to_mousebutton(Uint8 sdl_button);
private:
- //! Will only use get_ticks
- friend class AnimatorSystem;
//! Will only use delay
friend class LoopTimer;
/**
@@ -170,7 +194,7 @@ private:
/**
* \brief Draws a sprite to the screen using the specified transform and camera.
- * \param RenderCtx Reference to rendering data to draw
+ * \param RenderContext Reference to rendering data to draw
*/
void draw(const RenderContext & ctx);
@@ -184,9 +208,16 @@ private:
* \brief sets the background of the camera (will be adjusted in future PR)
* \param camera Reference to the Camera object.
*/
- void set_camera(const Camera & camera);
+ CameraValues set_camera(const Camera & camera);
private:
+ //! the data needed to construct a sdl dst rectangle
+ struct DestinationRectangleData {
+ const Sprite & sprite;
+ const CameraValues & cam;
+ const vec2 & pos;
+ const double & img_scale;
+ };
/**
* \brief calculates the sqaure size of the image
*
@@ -202,15 +233,14 @@ private:
* \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
+ * \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 Camera & cam,
- const vec2 & cam_pos, const double & img_scale) const;
+ SDL_FRect get_dst_rect(const DestinationRectangleData & data) const;
/**
* \brief Set an additional color value multiplied into render copy operations.
*
- * \param texture the given texture to adjust
+ * \param texture the given texture to adjust
* \param color the color data for the texture
*/
void set_color_texture(const Texture & texture, const Color & color);
@@ -221,6 +251,9 @@ private:
//! renderer for the crepe engine
std::unique_ptr<SDL_Renderer, std::function<void(SDL_Renderer *)>> game_renderer;
+
+ //! black bars rectangle to draw
+ SDL_FRect black_bars[2] = {};
};
} // namespace crepe
diff --git a/src/crepe/facade/Sound.h b/src/crepe/facade/Sound.h
index 4c68f32..ee43d94 100644
--- a/src/crepe/facade/Sound.h
+++ b/src/crepe/facade/Sound.h
@@ -35,7 +35,7 @@ public:
void play();
/**
* \brief Reset playhead position
- *
+ *
* Resets the playhead position so that calling \c play() after this function makes it play
* from the start of the sample. If the sound is not paused before calling this function,
* this function will stop playback.
diff --git a/src/crepe/manager/ComponentManager.h b/src/crepe/manager/ComponentManager.h
index 685cae5..e7eeaa2 100644
--- a/src/crepe/manager/ComponentManager.h
+++ b/src/crepe/manager/ComponentManager.h
@@ -17,7 +17,7 @@ class GameObject;
/**
* \brief Manages all components
- *
+ *
* This class manages all components. It provides methods to add, delete and get components.
*/
class ComponentManager : public Manager {
@@ -57,10 +57,10 @@ protected:
friend class GameObject;
/**
* \brief Add a component to the ComponentManager
- *
+ *
* This method adds a component to the ComponentManager. The component is created with the
* given arguments and added to the ComponentManager.
- *
+ *
* \tparam T The type of the component
* \tparam Args The types of the arguments
* \param id The id of the GameObject this component belongs to
@@ -71,9 +71,9 @@ protected:
T & add_component(game_object_id_t id, Args &&... args);
/**
* \brief Delete all components of a specific type and id
- *
+ *
* This method deletes all components of a specific type and id.
- *
+ *
* \tparam T The type of the component
* \param id The id of the GameObject this component belongs to
*/
@@ -81,24 +81,24 @@ protected:
void delete_components_by_id(game_object_id_t id);
/**
* \brief Delete all components of a specific type
- *
+ *
* This method deletes all components of a specific type.
- *
+ *
* \tparam T The type of the component
*/
template <typename T>
void delete_components();
/**
* \brief Delete all components of a specific id
- *
+ *
* This method deletes all components of a specific id.
- *
+ *
* \param id The id of the GameObject this component belongs to
*/
void delete_all_components_of_id(game_object_id_t id);
/**
* \brief Delete all components
- *
+ *
* This method deletes all components.
*/
void delete_all_components();
@@ -116,9 +116,9 @@ protected:
public:
/**
* \brief Get all components of a specific type and id
- *
+ *
* This method gets all components of a specific type and id.
- *
+ *
* \tparam T The type of the component
* \param id The id of the GameObject this component belongs to
* \return A vector of all components of the specific type and id
@@ -127,9 +127,9 @@ public:
RefVector<T> get_components_by_id(game_object_id_t id) const;
/**
* \brief Get all components of a specific type
- *
+ *
* This method gets all components of a specific type.
- *
+ *
* \tparam T The type of the component
* \return A vector of all components of the specific type
*/
@@ -171,7 +171,7 @@ private:
using by_id_index = std::vector<T>;
/**
* \brief The components
- *
+ *
* This unordered_map stores all components. The key is the type of the component and the
* value is a vector of vectors of unique pointers to the components.
*
diff --git a/src/crepe/manager/EventManager.h b/src/crepe/manager/EventManager.h
index d634f54..ba5e98b 100644
--- a/src/crepe/manager/EventManager.h
+++ b/src/crepe/manager/EventManager.h
@@ -24,7 +24,7 @@ typedef size_t event_channel_t;
/**
* \class EventManager
* \brief Manages event subscriptions, triggers, and queues, enabling decoupled event handling.
- *
+ *
* The `EventManager` acts as a centralized event system. It allows for registering callbacks
* for specific event types, triggering events synchronously, queueing events for later
* processing, and managing subscriptions via unique identifiers.
@@ -35,20 +35,20 @@ public:
/**
* \brief Get the singleton instance of the EventManager.
- *
+ *
* This method returns the unique instance of the EventManager, creating it if it
* doesn't already exist. Ensures only one instance is active in the program.
- *
+ *
* \return Reference to the singleton instance of the EventManager.
*/
static EventManager & get_instance();
/**
* \brief Subscribe to a specific event type.
- *
+ *
* Registers a callback for a given event type and optional channel. Each callback
* is assigned a unique subscription ID that can be used for later unsubscription.
- *
+ *
* \tparam EventType The type of the event to subscribe to.
* \param callback The callback function to be invoked when the event is triggered.
* \param channel The channel number to subscribe to (default is CHANNEL_ALL, which listens to all channels).
@@ -60,18 +60,18 @@ public:
/**
* \brief Unsubscribe a previously registered callback.
- *
+ *
* Removes a callback from the subscription list based on its unique subscription ID.
- *
+ *
* \param event_id The unique subscription ID of the callback to remove.
*/
void unsubscribe(subscription_t event_id);
/**
* \brief Trigger an event immediately.
- *
+ *
* Synchronously invokes all registered callbacks for the given event type on the specified channel.
- *
+ *
* \tparam EventType The type of the event to trigger.
* \param event The event instance to pass to the callbacks.
* \param channel The channel to trigger the event on (default is CHANNEL_ALL, which triggers on all channels).
@@ -81,9 +81,9 @@ public:
/**
* \brief Queue an event for later processing.
- *
+ *
* Adds an event to the event queue to be processed during the next call to `dispatch_events`.
- *
+ *
* \tparam EventType The type of the event to queue.
* \param event The event instance to queue.
* \param channel The channel to associate with the event (default is CHANNEL_ALL).
@@ -93,7 +93,7 @@ public:
/**
* \brief Process all queued events.
- *
+ *
* Iterates through the event queue and triggers callbacks for each queued event.
* Events are removed from the queue once processed.
*/
@@ -101,7 +101,7 @@ public:
/**
* \brief Clear all subscriptions.
- *
+ *
* Removes all registered event handlers and clears the subscription list.
*/
void clear();
@@ -109,7 +109,7 @@ public:
private:
/**
* \brief Default constructor for the EventManager.
- *
+ *
* Constructor is private to enforce the singleton pattern.
*/
EventManager() = default;
diff --git a/src/crepe/manager/Mediator.h b/src/crepe/manager/Mediator.h
index 71bd1c9..8094d80 100644
--- a/src/crepe/manager/Mediator.h
+++ b/src/crepe/manager/Mediator.h
@@ -3,8 +3,10 @@
#include "../util/OptionalRef.h"
// TODO: remove these singletons:
+#include "../facade/SDLContext.h"
#include "EventManager.h"
#include "SaveManager.h"
+#include "api/LoopTimer.h"
namespace crepe {
@@ -28,6 +30,8 @@ struct Mediator {
OptionalRef<SceneManager> scene_manager;
OptionalRef<SaveManager> save_manager = SaveManager::get_instance();
OptionalRef<EventManager> event_manager = EventManager::get_instance();
+ OptionalRef<SDLContext> sdl_context = SDLContext::get_instance();
+ OptionalRef<LoopTimer> timer = LoopTimer::get_instance();
};
} // namespace crepe
diff --git a/src/crepe/system/AnimatorSystem.cpp b/src/crepe/system/AnimatorSystem.cpp
index 8bb6465..549c35d 100644
--- a/src/crepe/system/AnimatorSystem.cpp
+++ b/src/crepe/system/AnimatorSystem.cpp
@@ -1,8 +1,8 @@
-#include <cstdint>
+
#include "../api/Animator.h"
-#include "../facade/SDLContext.h"
#include "../manager/ComponentManager.h"
+#include "api/LoopTimer.h"
#include "AnimatorSystem.h"
@@ -10,15 +10,30 @@ using namespace crepe;
void AnimatorSystem::update() {
ComponentManager & mgr = this->mediator.component_manager;
-
+ LoopTimer & timer = this->mediator.timer;
RefVector<Animator> animations = mgr.get_components_by_type<Animator>();
- uint64_t tick = SDLContext::get_instance().get_ticks();
+ double elapsed_time = timer.get_current_time();
+
for (Animator & a : animations) {
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;
+
+ Animator::Data & ctx = a.data;
+ float frame_duration = 1.0f / ctx.fps;
+
+ int last_frame = ctx.row;
+
+ int cycle_end = (ctx.cycle_end == -1) ? a.max_rows : ctx.cycle_end;
+ int total_frames = cycle_end - ctx.cycle_start;
+
+ int curr_frame = static_cast<int>(elapsed_time / frame_duration) % total_frames;
+
+ ctx.row = ctx.cycle_start + curr_frame;
+ a.spritesheet.mask.x = ctx.row * a.spritesheet.mask.w;
+ a.spritesheet.mask.y = (ctx.col * a.spritesheet.mask.h);
+
+ if (!ctx.looping && curr_frame == ctx.cycle_start && last_frame == total_frames - 1) {
+ a.active = false;
+ }
}
}
diff --git a/src/crepe/system/AnimatorSystem.h b/src/crepe/system/AnimatorSystem.h
index f8179a9..7d3f565 100644
--- a/src/crepe/system/AnimatorSystem.h
+++ b/src/crepe/system/AnimatorSystem.h
@@ -2,9 +2,6 @@
#include "System.h"
-//TODO:
-// control if flip works with animation system
-
namespace crepe {
/**
diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp
index c74ca1d..44a0431 100644
--- a/src/crepe/system/CollisionSystem.cpp
+++ b/src/crepe/system/CollisionSystem.cpp
@@ -1,5 +1,551 @@
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <functional>
+#include <optional>
+#include <utility>
+#include <variant>
+
+#include "../manager/ComponentManager.h"
+#include "../manager/EventManager.h"
+#include "api/BoxCollider.h"
+#include "api/CircleCollider.h"
+#include "api/Event.h"
+#include "api/Metadata.h"
+#include "api/Rigidbody.h"
+#include "api/Transform.h"
+#include "api/Vector2.h"
+
+#include "Collider.h"
#include "CollisionSystem.h"
+#include "types.h"
+#include "util/OptionalRef.h"
using namespace crepe;
-void CollisionSystem::update() {}
+void CollisionSystem::update() {
+ std::vector<CollisionInternal> all_colliders;
+ game_object_id_t id = 0;
+ ComponentManager & mgr = this->mediator.component_manager;
+ RefVector<Rigidbody> rigidbodies = mgr.get_components_by_type<Rigidbody>();
+ // Collisions can only happen on object with a rigidbody
+ for (Rigidbody & rigidbody : rigidbodies) {
+ if (!rigidbody.active) continue;
+ id = rigidbody.game_object_id;
+ Transform & transform = mgr.get_components_by_id<Transform>(id).front().get();
+ // Check if the boxcollider is active and has the same id as the rigidbody.
+ RefVector<BoxCollider> boxcolliders = mgr.get_components_by_type<BoxCollider>();
+ for (BoxCollider & boxcollider : boxcolliders) {
+ if (boxcollider.game_object_id != id) continue;
+ if (!boxcollider.active) continue;
+ all_colliders.push_back({.id = id,
+ .collider = collider_variant{boxcollider},
+ .transform = transform,
+ .rigidbody = rigidbody});
+ }
+ // Check if the circlecollider is active and has the same id as the rigidbody.
+ RefVector<CircleCollider> circlecolliders
+ = mgr.get_components_by_type<CircleCollider>();
+ for (CircleCollider & circlecollider : circlecolliders) {
+ if (circlecollider.game_object_id != id) continue;
+ if (!circlecollider.active) continue;
+ all_colliders.push_back({.id = id,
+ .collider = collider_variant{circlecollider},
+ .transform = transform,
+ .rigidbody = rigidbody});
+ }
+ }
+
+ // Check between all colliders if there is a collision
+ std::vector<std::pair<CollisionInternal, CollisionInternal>> collided
+ = this->gather_collisions(all_colliders);
+
+ // For both objects call the collision handler
+ for (auto & collision_pair : collided) {
+ this->collision_handler_request(collision_pair.first, collision_pair.second);
+ this->collision_handler_request(collision_pair.second, collision_pair.first);
+ }
+}
+
+void CollisionSystem::collision_handler_request(CollisionInternal & this_data,
+ CollisionInternal & other_data) {
+
+ CollisionInternalType type
+ = this->get_collider_type(this_data.collider, other_data.collider);
+ std::pair<vec2, CollisionSystem::Direction> resolution_data
+ = this->collision_handler(this_data, other_data, type);
+ ComponentManager & mgr = this->mediator.component_manager;
+ OptionalRef<Metadata> this_metadata
+ = mgr.get_components_by_id<Metadata>(this_data.id).front().get();
+ OptionalRef<Metadata> other_metadata
+ = mgr.get_components_by_id<Metadata>(other_data.id).front().get();
+ OptionalRef<Collider> this_collider;
+ OptionalRef<Collider> other_collider;
+ switch (type) {
+ case CollisionInternalType::BOX_BOX: {
+ this_collider = std::get<std::reference_wrapper<BoxCollider>>(this_data.collider);
+ other_collider
+ = std::get<std::reference_wrapper<BoxCollider>>(other_data.collider);
+ break;
+ }
+ case CollisionInternalType::BOX_CIRCLE: {
+ this_collider = std::get<std::reference_wrapper<BoxCollider>>(this_data.collider);
+ other_collider
+ = std::get<std::reference_wrapper<CircleCollider>>(other_data.collider);
+ break;
+ }
+ case CollisionInternalType::CIRCLE_BOX: {
+ this_collider
+ = std::get<std::reference_wrapper<CircleCollider>>(this_data.collider);
+ other_collider
+ = std::get<std::reference_wrapper<BoxCollider>>(other_data.collider);
+ break;
+ }
+ case CollisionInternalType::CIRCLE_CIRCLE: {
+ this_collider
+ = std::get<std::reference_wrapper<CircleCollider>>(this_data.collider);
+ other_collider
+ = std::get<std::reference_wrapper<CircleCollider>>(other_data.collider);
+ break;
+ }
+ }
+
+ // collision info
+ crepe::CollisionSystem::CollisionInfo collision_info{
+ .this_collider = this_collider,
+ .this_transform = this_data.transform,
+ .this_rigidbody = this_data.rigidbody,
+ .this_metadata = this_metadata,
+ .other_collider = other_collider,
+ .other_transform = other_data.transform,
+ .other_rigidbody = other_data.rigidbody,
+ .other_metadata = other_metadata,
+ .resolution = resolution_data.first,
+ .resolution_direction = resolution_data.second,
+ };
+
+ // Determine if static needs to be called
+ this->determine_collision_handler(collision_info);
+}
+
+std::pair<vec2, CollisionSystem::Direction>
+CollisionSystem::collision_handler(CollisionInternal & data1, CollisionInternal & data2,
+ CollisionInternalType type) {
+ vec2 resolution;
+ switch (type) {
+ case CollisionInternalType::BOX_BOX: {
+ const BoxCollider & collider1
+ = std::get<std::reference_wrapper<BoxCollider>>(data1.collider);
+ const BoxCollider & collider2
+ = std::get<std::reference_wrapper<BoxCollider>>(data2.collider);
+ vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform,
+ data1.rigidbody);
+ vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform,
+ data2.rigidbody);
+ resolution = this->get_box_box_resolution(collider1, collider2, collider_pos1,
+ collider_pos2);
+ break;
+ }
+ case CollisionInternalType::BOX_CIRCLE: {
+ const BoxCollider & collider1
+ = std::get<std::reference_wrapper<BoxCollider>>(data1.collider);
+ const CircleCollider & collider2
+ = std::get<std::reference_wrapper<CircleCollider>>(data2.collider);
+ vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform,
+ data1.rigidbody);
+ vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform,
+ data2.rigidbody);
+ resolution = -this->get_circle_box_resolution(collider2, collider1, collider_pos2,
+ collider_pos1);
+ break;
+ }
+ case CollisionInternalType::CIRCLE_CIRCLE: {
+ const CircleCollider & collider1
+ = std::get<std::reference_wrapper<CircleCollider>>(data1.collider);
+ const CircleCollider & collider2
+ = std::get<std::reference_wrapper<CircleCollider>>(data2.collider);
+ vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform,
+ data1.rigidbody);
+ vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform,
+ data2.rigidbody);
+ resolution = this->get_circle_circle_resolution(collider1, collider2,
+ collider_pos1, collider_pos2);
+ break;
+ }
+ case CollisionInternalType::CIRCLE_BOX: {
+ const CircleCollider & collider1
+ = std::get<std::reference_wrapper<CircleCollider>>(data1.collider);
+ const BoxCollider & collider2
+ = std::get<std::reference_wrapper<BoxCollider>>(data2.collider);
+ vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform,
+ data1.rigidbody);
+ vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform,
+ data2.rigidbody);
+ resolution = this->get_circle_box_resolution(collider1, collider2, collider_pos1,
+ collider_pos2);
+ break;
+ }
+ }
+
+ Direction resolution_direction = Direction::NONE;
+ if (resolution.x != 0 && resolution.y != 0) {
+ resolution_direction = Direction::BOTH;
+ } else if (resolution.x != 0) {
+ resolution_direction = Direction::X_DIRECTION;
+ if (data1.rigidbody.data.linear_velocity.y != 0)
+ resolution.y = data1.rigidbody.data.linear_velocity.y
+ * (resolution.x / data1.rigidbody.data.linear_velocity.x);
+ } else if (resolution.y != 0) {
+ resolution_direction = Direction::Y_DIRECTION;
+ if (data1.rigidbody.data.linear_velocity.x != 0)
+ resolution.x = data1.rigidbody.data.linear_velocity.x
+ * (resolution.y / data1.rigidbody.data.linear_velocity.y);
+ }
+
+ return std::make_pair(resolution, resolution_direction);
+}
+
+vec2 CollisionSystem::get_box_box_resolution(const BoxCollider & box_collider1,
+ const BoxCollider & box_collider2,
+ const vec2 & final_position1,
+ const vec2 & final_position2) const {
+ vec2 resolution; // Default resolution vector
+ vec2 delta = final_position2 - final_position1;
+
+ // Compute half-dimensions of the boxes
+ float half_width1 = box_collider1.dimensions.x / 2.0;
+ float half_height1 = box_collider1.dimensions.y / 2.0;
+ float half_width2 = box_collider2.dimensions.x / 2.0;
+ float half_height2 = box_collider2.dimensions.y / 2.0;
+
+ // Calculate overlaps along X and Y axes
+ float overlap_x = (half_width1 + half_width2) - std::abs(delta.x);
+ float overlap_y = (half_height1 + half_height2) - std::abs(delta.y);
+
+ // Check if there is a collision should always be true
+ if (overlap_x > 0 && overlap_y > 0) {
+ // Determine the direction of resolution
+ if (overlap_x < overlap_y) {
+ // Resolve along the X-axis (smallest overlap)
+ resolution.x = (delta.x > 0) ? -overlap_x : overlap_x;
+ } else if (overlap_y < overlap_x) {
+ // Resolve along the Y-axis (smallest overlap)
+ resolution.y = (delta.y > 0) ? -overlap_y : overlap_y;
+ } else {
+ // Equal overlap, resolve both directions with preference
+ resolution.x = (delta.x > 0) ? -overlap_x : overlap_x;
+ resolution.y = (delta.y > 0) ? -overlap_y : overlap_y;
+ }
+ }
+
+ return resolution;
+}
+
+vec2 CollisionSystem::get_circle_circle_resolution(const CircleCollider & circle_collider1,
+ const CircleCollider & circle_collider2,
+ const vec2 & final_position1,
+ const vec2 & final_position2) const {
+ vec2 delta = final_position2 - final_position1;
+
+ // Compute the distance between the two circle centers
+ float distance = std::sqrt(delta.x * delta.x + delta.y * delta.y);
+
+ // Compute the combined radii of the two circles
+ float combined_radius = circle_collider1.radius + circle_collider2.radius;
+
+ // Compute the penetration depth
+ float penetration_depth = combined_radius - distance;
+
+ // Normalize the delta vector to get the collision direction
+ vec2 collision_normal = delta / distance;
+
+ // Compute the resolution vector
+ vec2 resolution = -collision_normal * penetration_depth;
+
+ return resolution;
+}
+
+vec2 CollisionSystem::get_circle_box_resolution(const CircleCollider & circle_collider,
+ const BoxCollider & box_collider,
+ const vec2 & circle_position,
+ const vec2 & box_position) const {
+ vec2 delta = circle_position - box_position;
+
+ // Compute half-dimensions of the box
+ float half_width = box_collider.dimensions.x / 2.0f;
+ float half_height = box_collider.dimensions.y / 2.0f;
+
+ // Clamp circle center to the nearest point on the box
+ vec2 closest_point;
+ closest_point.x = std::clamp(delta.x, -half_width, half_width);
+ closest_point.y = std::clamp(delta.y, -half_height, half_height);
+
+ // Find the vector from the circle center to the closest point
+ vec2 closest_delta = delta - closest_point;
+
+ // Normalize the delta to get the collision direction
+ float distance
+ = std::sqrt(closest_delta.x * closest_delta.x + closest_delta.y * closest_delta.y);
+ vec2 collision_normal = closest_delta / distance;
+
+ // Compute penetration depth
+ float penetration_depth = circle_collider.radius - distance;
+
+ // Compute the resolution vector
+ vec2 resolution = collision_normal * penetration_depth;
+
+ return resolution;
+}
+
+void CollisionSystem::determine_collision_handler(CollisionInfo & info) {
+ // Check rigidbody type for static
+ if (info.this_rigidbody.data.body_type == Rigidbody::BodyType::STATIC) return;
+ // If second body is static perform the static collision handler in this system
+ if (info.other_rigidbody.data.body_type == Rigidbody::BodyType::STATIC) {
+ this->static_collision_handler(info);
+ };
+ // Call collision event for user
+ CollisionEvent data(info);
+ EventManager & emgr = this->mediator.event_manager;
+ emgr.trigger_event<CollisionEvent>(data, info.this_collider.game_object_id);
+}
+
+void CollisionSystem::static_collision_handler(CollisionInfo & info) {
+ // Move object back using calculate move back value
+ info.this_transform.position += info.resolution;
+
+ // If bounce is enabled mirror velocity
+ if (info.this_rigidbody.data.elastisity_coefficient > 0) {
+ if (info.resolution_direction == Direction::BOTH) {
+ info.this_rigidbody.data.linear_velocity.y
+ = -info.this_rigidbody.data.linear_velocity.y
+ * info.this_rigidbody.data.elastisity_coefficient;
+ info.this_rigidbody.data.linear_velocity.x
+ = -info.this_rigidbody.data.linear_velocity.x
+ * info.this_rigidbody.data.elastisity_coefficient;
+ } else if (info.resolution_direction == Direction::Y_DIRECTION) {
+ info.this_rigidbody.data.linear_velocity.y
+ = -info.this_rigidbody.data.linear_velocity.y
+ * info.this_rigidbody.data.elastisity_coefficient;
+ } else if (info.resolution_direction == Direction::X_DIRECTION) {
+ info.this_rigidbody.data.linear_velocity.x
+ = -info.this_rigidbody.data.linear_velocity.x
+ * info.this_rigidbody.data.elastisity_coefficient;
+ }
+ }
+ // Stop movement if bounce is disabled
+ else {
+ info.this_rigidbody.data.linear_velocity = {0, 0};
+ }
+}
+
+std::vector<std::pair<CollisionSystem::CollisionInternal, CollisionSystem::CollisionInternal>>
+CollisionSystem::gather_collisions(std::vector<CollisionInternal> & colliders) {
+
+ // TODO:
+ // If no colliders skip
+ // Check if colliders has rigidbody if not skip
+
+ // TODO:
+ // If amount is higer than lets say 16 for now use quadtree otwerwise skip
+ // Quadtree code
+ // Quadtree is placed over the input vector
+
+ // Return data of collided colliders which are variants
+ std::vector<std::pair<CollisionInternal, CollisionInternal>> collisions_ret;
+ //using visit to visit the variant to access the active and id.
+ for (size_t i = 0; i < colliders.size(); ++i) {
+ for (size_t j = i + 1; j < colliders.size(); ++j) {
+ if (colliders[i].id == colliders[j].id) continue;
+ if (!have_common_layer(colliders[i].rigidbody.data.collision_layers,
+ colliders[j].rigidbody.data.collision_layers))
+ continue;
+ CollisionInternalType type
+ = get_collider_type(colliders[i].collider, colliders[j].collider);
+ if (!get_collision(
+ {
+ .collider = colliders[i].collider,
+ .transform = colliders[i].transform,
+ .rigidbody = colliders[i].rigidbody,
+ },
+ {
+ .collider = colliders[j].collider,
+ .transform = colliders[j].transform,
+ .rigidbody = colliders[j].rigidbody,
+ },
+ type))
+ continue;
+ collisions_ret.emplace_back(colliders[i], colliders[j]);
+ }
+ }
+
+ return collisions_ret;
+}
+
+bool CollisionSystem::have_common_layer(const std::set<int> & layers1,
+ const std::set<int> & layers2) {
+
+ // Check if any number is equal in the layers
+ for (int num : layers1) {
+ if (layers2.contains(num)) {
+ // Common layer found
+ return true;
+ break;
+ }
+ }
+ // No common layer found
+ return false;
+}
+
+CollisionSystem::CollisionInternalType
+CollisionSystem::get_collider_type(const collider_variant & collider1,
+ const collider_variant & collider2) const {
+ if (std::holds_alternative<std::reference_wrapper<CircleCollider>>(collider1)) {
+ if (std::holds_alternative<std::reference_wrapper<CircleCollider>>(collider2)) {
+ return CollisionInternalType::CIRCLE_CIRCLE;
+ } else {
+ return CollisionInternalType::CIRCLE_BOX;
+ }
+ } else {
+ if (std::holds_alternative<std::reference_wrapper<CircleCollider>>(collider2)) {
+ return CollisionInternalType::BOX_CIRCLE;
+ } else {
+ return CollisionInternalType::BOX_BOX;
+ }
+ }
+}
+
+bool CollisionSystem::get_collision(const CollisionInternal & first_info,
+ const CollisionInternal & second_info,
+ CollisionInternalType type) const {
+ switch (type) {
+ case CollisionInternalType::BOX_BOX: {
+ const BoxCollider & box_collider1
+ = std::get<std::reference_wrapper<BoxCollider>>(first_info.collider);
+ const BoxCollider & box_collider2
+ = std::get<std::reference_wrapper<BoxCollider>>(second_info.collider);
+ return this->get_box_box_collision(box_collider1, box_collider2,
+ first_info.transform, second_info.transform,
+ second_info.rigidbody, second_info.rigidbody);
+ }
+ case CollisionInternalType::BOX_CIRCLE: {
+ const BoxCollider & box_collider
+ = std::get<std::reference_wrapper<BoxCollider>>(first_info.collider);
+ const CircleCollider & circle_collider
+ = std::get<std::reference_wrapper<CircleCollider>>(second_info.collider);
+ return this->get_box_circle_collision(
+ box_collider, circle_collider, first_info.transform, second_info.transform,
+ second_info.rigidbody, second_info.rigidbody);
+ }
+ case CollisionInternalType::CIRCLE_CIRCLE: {
+ const CircleCollider & circle_collider1
+ = std::get<std::reference_wrapper<CircleCollider>>(first_info.collider);
+ const CircleCollider & circle_collider2
+ = std::get<std::reference_wrapper<CircleCollider>>(second_info.collider);
+ return this->get_circle_circle_collision(
+ circle_collider1, circle_collider2, first_info.transform,
+ second_info.transform, second_info.rigidbody, second_info.rigidbody);
+ }
+ case CollisionInternalType::CIRCLE_BOX: {
+ const CircleCollider & circle_collider
+ = std::get<std::reference_wrapper<CircleCollider>>(first_info.collider);
+ const BoxCollider & box_collider
+ = std::get<std::reference_wrapper<BoxCollider>>(second_info.collider);
+ return this->get_box_circle_collision(
+ box_collider, circle_collider, first_info.transform, second_info.transform,
+ second_info.rigidbody, second_info.rigidbody);
+ }
+ }
+ return false;
+}
+
+bool CollisionSystem::get_box_box_collision(const BoxCollider & box1, const BoxCollider & box2,
+ const Transform & transform1,
+ const Transform & transform2,
+ const Rigidbody & rigidbody1,
+ const Rigidbody & rigidbody2) const {
+ // Get current positions of colliders
+ vec2 final_position1 = this->get_current_position(box1.offset, transform1, rigidbody1);
+ vec2 final_position2 = this->get_current_position(box2.offset, transform2, rigidbody2);
+
+ // Calculate half-extents (half width and half height)
+ float half_width1 = box1.dimensions.x / 2.0;
+ float half_height1 = box1.dimensions.y / 2.0;
+ float half_width2 = box2.dimensions.x / 2.0;
+ float half_height2 = box2.dimensions.y / 2.0;
+
+ // Check if the boxes overlap along the X and Y axes
+ return (final_position1.x + half_width1 > final_position2.x - half_width2
+ && final_position1.x - half_width1 < final_position2.x + half_width2
+ && final_position1.y + half_height1 > final_position2.y - half_height2
+ && final_position1.y - half_height1 < final_position2.y + half_height2);
+}
+
+bool CollisionSystem::get_box_circle_collision(const BoxCollider & box1,
+ const CircleCollider & circle2,
+ const Transform & transform1,
+ const Transform & transform2,
+ const Rigidbody & rigidbody1,
+ const Rigidbody & rigidbody2) const {
+ // Get current positions of colliders
+ vec2 final_position1 = this->get_current_position(box1.offset, transform1, rigidbody1);
+ vec2 final_position2 = this->get_current_position(circle2.offset, transform2, rigidbody2);
+
+ // Calculate box half-extents
+ float half_width = box1.dimensions.x / 2.0;
+ float half_height = box1.dimensions.y / 2.0;
+
+ // Find the closest point on the box to the circle's center
+ float closest_x = std::max(final_position1.x - half_width,
+ std::min(final_position2.x, final_position1.x + half_width));
+ float closest_y = std::max(final_position1.y - half_height,
+ std::min(final_position2.y, final_position1.y + half_height));
+
+ // Calculate the distance squared between the circle's center and the closest point on the box
+ float distance_x = final_position2.x - closest_x;
+ float distance_y = final_position2.y - closest_y;
+ float distance_squared = distance_x * distance_x + distance_y * distance_y;
+
+ // Compare distance squared with the square of the circle's radius
+ return distance_squared < circle2.radius * circle2.radius;
+}
+
+bool CollisionSystem::get_circle_circle_collision(const CircleCollider & circle1,
+ const CircleCollider & circle2,
+ const Transform & transform1,
+ const Transform & transform2,
+ const Rigidbody & rigidbody1,
+ const Rigidbody & rigidbody2) const {
+ // Get current positions of colliders
+ vec2 final_position1 = this->get_current_position(circle1.offset, transform1, rigidbody1);
+ vec2 final_position2 = this->get_current_position(circle2.offset, transform2, rigidbody2);
+
+ float distance_x = final_position1.x - final_position2.x;
+ float distance_y = final_position1.y - final_position2.y;
+ float distance_squared = distance_x * distance_x + distance_y * distance_y;
+
+ // Calculate the sum of the radii
+ float radius_sum = circle1.radius + circle2.radius;
+
+ // Check if the distance between the centers is less than or equal to the sum of the radii
+ return distance_squared < radius_sum * radius_sum;
+}
+
+vec2 CollisionSystem::get_current_position(const vec2 & collider_offset,
+ const Transform & transform,
+ const Rigidbody & rigidbody) const {
+ // Get the rotation in radians
+ float radians1 = transform.rotation * (M_PI / 180.0);
+
+ // Calculate total offset with scale
+ vec2 total_offset = (rigidbody.data.offset + collider_offset) * transform.scale;
+
+ // Rotate
+ float rotated_total_offset_x1
+ = total_offset.x * cos(radians1) - total_offset.y * sin(radians1);
+ float rotated_total_offset_y1
+ = total_offset.x * sin(radians1) + total_offset.y * cos(radians1);
+
+ // Final positions considering scaling and rotation
+ return (transform.position + vec2(rotated_total_offset_x1, rotated_total_offset_y1));
+}
diff --git a/src/crepe/system/CollisionSystem.h b/src/crepe/system/CollisionSystem.h
index c1a70d8..5b136c6 100644
--- a/src/crepe/system/CollisionSystem.h
+++ b/src/crepe/system/CollisionSystem.h
@@ -1,13 +1,311 @@
#pragma once
+#include <optional>
+#include <variant>
+#include <vector>
+
+#include "api/BoxCollider.h"
+#include "api/CircleCollider.h"
+#include "api/Event.h"
+#include "api/Metadata.h"
+#include "api/Rigidbody.h"
+#include "api/Transform.h"
+#include "api/Vector2.h"
+
+#include "Collider.h"
#include "System.h"
namespace crepe {
+//! A system responsible for detecting and handling collisions between colliders.
class CollisionSystem : public System {
public:
using System::System;
+
+private:
+ //! A variant type that can hold either a BoxCollider or a CircleCollider.
+ using collider_variant = std::variant<std::reference_wrapper<BoxCollider>,
+ std::reference_wrapper<CircleCollider>>;
+
+ //! Enum representing the types of collider pairs for collision detection.
+ enum class CollisionInternalType {
+ BOX_BOX,
+ CIRCLE_CIRCLE,
+ BOX_CIRCLE,
+ CIRCLE_BOX,
+ };
+
+ /**
+ * \brief A structure to store the collision data of a single collider.
+ *
+ * This structure all components and id that are for needed within this system when calculating or handeling collisions.
+ * The transform and rigidbody are mostly needed for location and rotation.
+ * In rigidbody additional info is written about what the body of the object is,
+ * and how it should respond on a collision.
+ */
+ struct CollisionInternal {
+ game_object_id_t id = 0;
+ collider_variant collider;
+ Transform & transform;
+ Rigidbody & rigidbody;
+ };
+
+ //! Enum representing movement directions during collision resolution.
+ enum class Direction {
+ //! No movement required.
+ NONE,
+ //! Movement in the X direction.
+ X_DIRECTION,
+ //! Movement in the Y direction.
+ Y_DIRECTION,
+ //! Movement in both X and Y directions.
+ BOTH
+ };
+
+public:
+ /**
+ * \brief Structure representing detailed collision information between two colliders.
+ *
+ * Includes information about the colliding objects and the resolution data for handling the collision.
+ */
+ struct CollisionInfo {
+ Collider & this_collider;
+ Transform & this_transform;
+ Rigidbody & this_rigidbody;
+ Metadata & this_metadata;
+ Collider & other_collider;
+ Transform & other_transform;
+ Rigidbody & other_rigidbody;
+ Metadata & other_metadata;
+ //! The resolution vector for the collision.
+ vec2 resolution;
+ //! The direction of movement for resolving the collision.
+ Direction resolution_direction = Direction::NONE;
+ };
+
+public:
+ //! Updates the collision system by checking for collisions between colliders and handling them.
void update() override;
+
+private:
+ /**
+ * \brief Determines the type of collider pair from two colliders.
+ *
+ * Uses std::holds_alternative to identify the types of the provided colliders.
+ *
+ * \param collider1 First collider variant (BoxCollider or CircleCollider).
+ * \param collider2 Second collider variant (BoxCollider or CircleCollider).
+ * \return The combined type of the two colliders.
+ */
+ CollisionInternalType get_collider_type(const collider_variant & collider1,
+ const collider_variant & collider2) const;
+
+ /**
+ * \brief Calculates the current position of a collider.
+ *
+ * Combines the Collider offset, Transform position, and Rigidbody offset to compute the position of the collider.
+ *
+ * \param collider_offset The offset of the collider.
+ * \param transform The Transform of the associated game object.
+ * \param rigidbody The Rigidbody of the associated game object.
+ * \return The calculated position of the collider.
+ */
+ vec2 get_current_position(const vec2 & collider_offset, const Transform & transform,
+ const Rigidbody & rigidbody) const;
+
+private:
+ /**
+ * \brief Handles collision resolution between two colliders.
+ *
+ * Processes collision data and adjusts objects to resolve collisions and/or calls the user oncollision script function.
+ *
+ * \param data1 Collision data for the first collider.
+ * \param data2 Collision data for the second collider.
+ */
+ void collision_handler_request(CollisionInternal & data1, CollisionInternal & data2);
+
+ /**
+ * \brief Resolves collision between two colliders and calculates the movement required.
+ *
+ * Determines the displacement and direction needed to separate colliders based on their types.
+ *
+ * \param data1 Collision data for the first collider.
+ * \param data2 Collision data for the second collider.
+ * \param type The type of collider pair.
+ * \return A pair containing the resolution vector and direction for the first collider.
+ */
+ std::pair<vec2, Direction> collision_handler(CollisionInternal & data1,
+ CollisionInternal & data2,
+ CollisionInternalType type);
+
+ /**
+ * \brief Calculates the resolution vector for two BoxColliders.
+ *
+ * Computes the displacement required to separate two overlapping BoxColliders.
+ *
+ * \param box_collider1 The first BoxCollider.
+ * \param box_collider2 The second BoxCollider.
+ * \param position1 The position of the first BoxCollider.
+ * \param position2 The position of the second BoxCollider.
+ * \return The resolution vector for the collision.
+ */
+ vec2 get_box_box_resolution(const BoxCollider & box_collider1,
+ const BoxCollider & box_collider2, const vec2 & position1,
+ const vec2 & position2) const;
+
+ /**
+ * \brief Calculates the resolution vector for two CircleCollider.
+ *
+ * Computes the displacement required to separate two overlapping CircleCollider.
+ *
+ * \param circle_collider1 The first CircleCollider.
+ * \param circle_collider2 The second CircleCollider.
+ * \param final_position1 The position of the first CircleCollider.
+ * \param final_position2 The position of the second CircleCollider.
+ * \return The resolution vector for the collision.
+ */
+ vec2 get_circle_circle_resolution(const CircleCollider & circle_collider1,
+ const CircleCollider & circle_collider2,
+ const vec2 & final_position1,
+ const vec2 & final_position2) const;
+
+ /**
+ * \brief Calculates the resolution vector for two CircleCollider.
+ *
+ * Computes the displacement required to separate two overlapping CircleCollider.
+ *
+ * \param circle_collider The first CircleCollider.
+ * \param box_collider The second CircleCollider.
+ * \param circle_position The position of the CircleCollider.
+ * \param box_position The position of the BoxCollider.
+ * \return The resolution vector for the collision.
+ */
+ vec2 get_circle_box_resolution(const CircleCollider & circle_collider,
+ const BoxCollider & box_collider,
+ const vec2 & circle_position,
+ const vec2 & box_position) const;
+
+ /**
+ * \brief Determines the appropriate collision handler for a collision.
+ *
+ * Decides the correct resolution process based on the dynamic or static nature of the colliders involved.
+ *
+ * \param info Collision information containing data about both colliders.
+ */
+ void determine_collision_handler(CollisionInfo & info);
+
+ /**
+ * \brief Handles collisions involving static objects.
+ *
+ * Resolves collisions by adjusting positions and modifying velocities if bounce is enabled.
+ *
+ * \param info Collision information containing data about both colliders.
+ */
+ void static_collision_handler(CollisionInfo & info);
+
+private:
+ /**
+ * \brief Checks for collisions between colliders.
+ *
+ * Identifies collisions and generates pairs of colliding objects for further processing.
+ *
+ * \param colliders A collection of all active colliders.
+ * \return A list of collision pairs with their associated data.
+ */
+ std::vector<std::pair<CollisionInternal, CollisionInternal>>
+ gather_collisions(std::vector<CollisionInternal> & colliders);
+
+ /**
+ * \brief Checks if two collision layers have at least one common layer.
+ *
+ * This function checks if there is any overlapping layer between the two inputs.
+ * It compares each layer from the first input to see
+ * if it exists in the second input. If at least one common layer is found,
+ * the function returns true, indicating that the two colliders share a common
+ * collision layer.
+ *
+ * \param layers1 all collision layers for the first collider.
+ * \param layers2 all collision layers for the second collider.
+ * \return Returns true if there is at least one common layer, false otherwise.
+ */
+
+ bool have_common_layer(const std::set<int> & layers1, const std::set<int> & layers2);
+
+ /**
+ * \brief Checks for collision between two colliders.
+ *
+ * Calls the appropriate collision detection function based on the collider types.
+ *
+ * \param first_info Collision data for the first collider.
+ * \param second_info Collision data for the second collider.
+ * \param type The type of collider pair.
+ * \return True if a collision is detected, otherwise false.
+ */
+ bool get_collision(const CollisionInternal & first_info,
+ const CollisionInternal & second_info,
+ CollisionInternalType type) const;
+
+ /**
+ * \brief Detects collisions between two BoxColliders.
+ *
+ * \param box1 The first BoxCollider.
+ * \param box2 The second BoxCollider.
+ * \param transform1 Transform of the first object.
+ * \param transform2 Transform of the second object.
+ * \param rigidbody1 Rigidbody of the first object.
+ * \param rigidbody2 Rigidbody of the second object.
+ * \return True if a collision is detected, otherwise false.
+ */
+ bool get_box_box_collision(const BoxCollider & box1, const BoxCollider & box2,
+ const Transform & transform1, const Transform & transform2,
+ const Rigidbody & rigidbody1,
+ const Rigidbody & rigidbody2) const;
+
+ /**
+ * \brief Check collision for box on circle collider
+ *
+ * \param box1 The BoxCollider
+ * \param circle2 The CircleCollider
+ * \param transform1 Transform of the first object.
+ * \param transform2 Transform of the second object.
+ * \param rigidbody1 Rigidbody of the first object.
+ * \param rigidbody2 Rigidbody of the second object.
+ * \return True if a collision is detected, otherwise false.
+ */
+ bool get_box_circle_collision(const BoxCollider & box1, const CircleCollider & circle2,
+ const Transform & transform1, const Transform & transform2,
+ const Rigidbody & rigidbody1,
+ const Rigidbody & rigidbody2) const;
+
+ /**
+ * \brief Check collision for circle on circle collider
+ *
+ * \param circle1 First CircleCollider
+ * \param circle2 Second CircleCollider
+ * \param transform1 Transform of the first object.
+ * \param transform2 Transform of the second object.
+ * \param rigidbody1 Rigidbody of the first object.
+ * \param rigidbody2 Rigidbody of the second object.
+ * \return True if a collision is detected, otherwise false.
+ *
+ * \return status of collision
+ */
+ bool get_circle_circle_collision(const CircleCollider & circle1,
+ const CircleCollider & circle2,
+ const Transform & transform1,
+ const Transform & transform2,
+ const Rigidbody & rigidbody1,
+ const Rigidbody & rigidbody2) const;
+};
+
+/**
+ * \brief Event triggered during a collision between objects.
+ */
+class CollisionEvent : public Event {
+public:
+ crepe::CollisionSystem::CollisionInfo info;
+ CollisionEvent(const crepe::CollisionSystem::CollisionInfo & collisionInfo)
+ : info(collisionInfo) {}
};
} // namespace crepe
diff --git a/src/crepe/system/InputSystem.cpp b/src/crepe/system/InputSystem.cpp
index 7cc8d30..aaa8bdf 100644
--- a/src/crepe/system/InputSystem.cpp
+++ b/src/crepe/system/InputSystem.cpp
@@ -24,10 +24,10 @@ void InputSystem::update() {
RefVector<Transform> transform_vec
= mgr.get_components_by_id<Transform>(current_cam.game_object_id);
Transform & cam_transform = transform_vec.front().get();
- int camera_origin_x
- = cam_transform.position.x + current_cam.offset.x - (current_cam.viewport_size.x / 2);
- int camera_origin_y
- = cam_transform.position.y + current_cam.offset.y - (current_cam.viewport_size.y / 2);
+ int camera_origin_x = cam_transform.position.x + current_cam.data.postion_offset.x
+ - (current_cam.viewport_size.x / 2);
+ int camera_origin_y = cam_transform.position.y + current_cam.data.postion_offset.y
+ - (current_cam.viewport_size.y / 2);
for (const SDLContext::EventData & event : event_list) {
int world_mouse_x = event.mouse_position.x + camera_origin_x;
diff --git a/src/crepe/system/ParticleSystem.h b/src/crepe/system/ParticleSystem.h
index c647284..068f01c 100644
--- a/src/crepe/system/ParticleSystem.h
+++ b/src/crepe/system/ParticleSystem.h
@@ -25,7 +25,7 @@ public:
private:
/**
* \brief Emits a particle from the specified emitter based on its emission properties.
- *
+ *
* \param emitter Reference to the ParticleEmitter.
* \param transform Const reference to the Transform component associated with the emitter.
*/
@@ -34,7 +34,7 @@ private:
/**
* \brief Calculates the number of times particles should be emitted based on emission rate
* and update count.
- *
+ *
* \param count Current update count.
* \param emission Emission rate.
* \return The number of particles to emit.
@@ -44,7 +44,7 @@ private:
/**
* \brief Checks whether particles are within the emitter’s boundary, resets or stops
* particles if they exit.
- *
+ *
* \param emitter Reference to the ParticleEmitter.
* \param transform Const reference to the Transform component associated with the emitter.
*/
@@ -52,7 +52,7 @@ private:
/**
* \brief Generates a random angle for particle emission within the specified range.
- *
+ *
* \param min_angle Minimum emission angle in degrees.
* \param max_angle Maximum emission angle in degrees.
* \return Random angle in degrees.
@@ -61,7 +61,7 @@ private:
/**
* \brief Generates a random speed for particle emission within the specified range.
- *
+ *
* \param min_speed Minimum emission speed.
* \param max_speed Maximum emission speed.
* \return Random speed.
diff --git a/src/crepe/system/PhysicsSystem.cpp b/src/crepe/system/PhysicsSystem.cpp
index bebcf3d..ebf4439 100644
--- a/src/crepe/system/PhysicsSystem.cpp
+++ b/src/crepe/system/PhysicsSystem.cpp
@@ -25,17 +25,20 @@ void PhysicsSystem::update() {
if (transform.game_object_id == rigidbody.game_object_id) {
// Add gravity
- if (rigidbody.data.use_gravity) {
+ if (rigidbody.data.gravity_scale > 0) {
rigidbody.data.linear_velocity.y
+= (rigidbody.data.mass * rigidbody.data.gravity_scale
* gravity);
}
// Add damping
- if (rigidbody.data.angular_damping != 0) {
- rigidbody.data.angular_velocity *= rigidbody.data.angular_damping;
+ if (rigidbody.data.angular_velocity_coefficient > 0) {
+ rigidbody.data.angular_velocity
+ *= rigidbody.data.angular_velocity_coefficient;
}
- if (rigidbody.data.linear_damping != vec2{0, 0}) {
- rigidbody.data.linear_velocity *= rigidbody.data.linear_damping;
+ if (rigidbody.data.linear_velocity_coefficient.x > 0
+ && rigidbody.data.linear_velocity_coefficient.y > 0) {
+ rigidbody.data.linear_velocity
+ *= rigidbody.data.linear_velocity_coefficient;
}
// Max velocity check
diff --git a/src/crepe/system/PhysicsSystem.h b/src/crepe/system/PhysicsSystem.h
index 227ab69..26152a5 100644
--- a/src/crepe/system/PhysicsSystem.h
+++ b/src/crepe/system/PhysicsSystem.h
@@ -6,7 +6,7 @@ namespace crepe {
/**
* \brief System that controls all physics
- *
+ *
* This class is a physics system that uses a rigidbody and transform to add physics to a game
* object.
*/
@@ -15,7 +15,7 @@ public:
using System::System;
/**
* \brief updates the physics system.
- *
+ *
* It calculates new velocties and changes the postion in the transform.
*/
void update() override;
diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp
index 92dba43..26f2c85 100644
--- a/src/crepe/system/RenderSystem.cpp
+++ b/src/crepe/system/RenderSystem.cpp
@@ -17,13 +17,19 @@
using namespace crepe;
using namespace std;
-void RenderSystem::clear_screen() { this->context.clear_screen(); }
+void RenderSystem::clear_screen() {
+ SDLContext & ctx = this->mediator.sdl_context;
+ ctx.clear_screen();
+}
-void RenderSystem::present_screen() { this->context.present_screen(); }
+void RenderSystem::present_screen() {
+ SDLContext & ctx = this->mediator.sdl_context;
+ ctx.present_screen();
+}
-const Camera & RenderSystem::update_camera() {
+SDLContext::CameraValues RenderSystem::update_camera() {
ComponentManager & mgr = this->mediator.component_manager;
-
+ SDLContext & ctx = this->mediator.sdl_context;
RefVector<Camera> cameras = mgr.get_components_by_type<Camera>();
if (cameras.size() == 0) throw std::runtime_error("No cameras in current scene");
@@ -32,16 +38,18 @@ const Camera & RenderSystem::update_camera() {
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->cam_pos = transform.position + cam.offset;
- return cam;
+ SDLContext::CameraValues cam_val = ctx.set_camera(cam);
+ cam_val.cam_pos = transform.position + cam.data.postion_offset;
+ return cam_val;
}
throw std::runtime_error("No active cameras in current scene");
}
bool sorting_comparison(const Sprite & a, const Sprite & b) {
- if (a.sorting_in_layer < b.sorting_in_layer) return true;
- if (a.sorting_in_layer == b.sorting_in_layer) return a.order_in_layer < b.order_in_layer;
+ if (a.data.sorting_in_layer != b.data.sorting_in_layer)
+ return a.data.sorting_in_layer < b.data.sorting_in_layer;
+ if (a.data.order_in_layer != b.data.order_in_layer)
+ return a.data.order_in_layer < b.data.order_in_layer;
return false;
}
@@ -59,10 +67,11 @@ void RenderSystem::update() {
this->present_screen();
}
-bool RenderSystem::render_particle(const Sprite & sprite, const Camera & cam,
+bool RenderSystem::render_particle(const Sprite & sprite, const SDLContext::CameraValues & cam,
const double & scale) {
ComponentManager & mgr = this->mediator.component_manager;
+ SDLContext & ctx = this->mediator.sdl_context;
vector<reference_wrapper<ParticleEmitter>> emitters
= mgr.get_components_by_id<ParticleEmitter>(sprite.game_object_id);
@@ -77,10 +86,9 @@ bool RenderSystem::render_particle(const Sprite & sprite, const Camera & cam,
for (const Particle & p : em.data.particles) {
if (!p.active) continue;
- this->context.draw(SDLContext::RenderContext{
+ ctx.draw(SDLContext::RenderContext{
.sprite = sprite,
.cam = cam,
- .cam_pos = this->cam_pos,
.pos = p.position,
.angle = p.angle,
.scale = scale,
@@ -89,12 +97,12 @@ bool RenderSystem::render_particle(const Sprite & sprite, const Camera & cam,
}
return rendering_particles;
}
-void RenderSystem::render_normal(const Sprite & sprite, const Camera & cam,
+void RenderSystem::render_normal(const Sprite & sprite, const SDLContext::CameraValues & cam,
const Transform & tm) {
- this->context.draw(SDLContext::RenderContext{
+ SDLContext & ctx = this->mediator.sdl_context;
+ ctx.draw(SDLContext::RenderContext{
.sprite = sprite,
.cam = cam,
- .cam_pos = this->cam_pos,
.pos = tm.position,
.angle = tm.rotation,
.scale = tm.scale,
@@ -103,7 +111,7 @@ void RenderSystem::render_normal(const Sprite & sprite, const Camera & cam,
void RenderSystem::render() {
ComponentManager & mgr = this->mediator.component_manager;
- const Camera & cam = this->update_camera();
+ const SDLContext::CameraValues & cam = this->update_camera();
RefVector<Sprite> sprites = mgr.get_components_by_type<Sprite>();
RefVector<Sprite> sorted_sprites = this->sort(sprites);
diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h
index 096d058..e270a6b 100644
--- a/src/crepe/system/RenderSystem.h
+++ b/src/crepe/system/RenderSystem.h
@@ -18,7 +18,7 @@ class Transform;
* \brief Manages rendering operations for all game objects.
*
* RenderSystem is responsible for rendering, clearing and presenting the screen, and
- * managing the active camera.
+ * managing the active camera.
*/
class RenderSystem : public System {
public:
@@ -37,7 +37,7 @@ private:
void present_screen();
//! Updates the active camera used for rendering.
- const Camera & update_camera();
+ SDLContext::CameraValues update_camera();
//! Renders the whole screen
void render();
@@ -52,20 +52,22 @@ private:
* constructor is now protected i cannot make tmp inside
* \return true if particles have been rendered
*/
- bool render_particle(const Sprite & sprite, const Camera & cam, const double & scale);
+ bool render_particle(const Sprite & sprite, const SDLContext::CameraValues & cam,
+ const double & scale);
/**
- * \brief renders a sprite with a Transform component on the screen
+ * \brief renders a sprite with a Transform component on the screen
*
* \param sprite the sprite component that holds all the data
- * \param tm the Transform component that holds the position,rotation and scale
+ * \param tm the Transform component that holds the position,rotation and scale
*/
- void render_normal(const Sprite & sprite, const Camera & cam, const Transform & tm);
+ void render_normal(const Sprite & sprite, const SDLContext::CameraValues & cam,
+ const Transform & tm);
/**
* \brief sort a vector sprite objects with
*
- * \param objs the vector that will do a sorting algorithm on
+ * \param objs the vector that will do a sorting algorithm on
* \return returns a sorted reference vector
*/
RefVector<Sprite> sort(RefVector<Sprite> & objs) const;
@@ -75,13 +77,6 @@ private:
* \todo Implement a text component and a button component.
* \todo Consider adding text input functionality.
*/
-
-private:
- // FIXME: retrieve sdlcontext via mediator after #PR57
- SDLContext & context = SDLContext::get_instance();
-
- //! camera postion in the current scene
- vec2 cam_pos;
};
} // namespace crepe
diff --git a/src/crepe/system/ScriptSystem.h b/src/crepe/system/ScriptSystem.h
index 936e9ca..3db1b1e 100644
--- a/src/crepe/system/ScriptSystem.h
+++ b/src/crepe/system/ScriptSystem.h
@@ -8,7 +8,7 @@ class Script;
/**
* \brief Script system
- *
+ *
* The script system is responsible for all \c BehaviorScript components, and
* calls the methods on classes derived from \c Script.
*/