aboutsummaryrefslogtreecommitdiff
path: root/src/crepe
diff options
context:
space:
mode:
Diffstat (limited to 'src/crepe')
-rw-r--r--src/crepe/Collider.cpp2
-rw-r--r--src/crepe/Collider.h7
-rw-r--r--src/crepe/api/BehaviorScript.h7
-rw-r--r--src/crepe/api/BehaviorScript.hpp6
-rw-r--r--src/crepe/api/BoxCollider.cpp7
-rw-r--r--src/crepe/api/BoxCollider.h24
-rw-r--r--src/crepe/api/CMakeLists.txt4
-rw-r--r--src/crepe/api/CircleCollider.cpp6
-rw-r--r--src/crepe/api/CircleCollider.h17
-rw-r--r--src/crepe/api/Event.h7
-rw-r--r--src/crepe/api/LoopManager.cpp11
-rw-r--r--src/crepe/api/Rigidbody.h10
-rw-r--r--src/crepe/api/Script.h7
-rw-r--r--src/crepe/api/Vector2.h3
-rw-r--r--src/crepe/system/CollisionSystem.cpp356
-rw-r--r--src/crepe/system/CollisionSystem.h179
-rw-r--r--src/crepe/system/RenderSystem.cpp2
17 files changed, 635 insertions, 20 deletions
diff --git a/src/crepe/Collider.cpp b/src/crepe/Collider.cpp
index bbec488..0706371 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, Vector2 offset) : Component(id), offset(offset) {}
diff --git a/src/crepe/Collider.h b/src/crepe/Collider.h
index 827f83d..e910ae4 100644
--- a/src/crepe/Collider.h
+++ b/src/crepe/Collider.h
@@ -1,14 +1,17 @@
#pragma once
+#include "api/Vector2.h"
+
#include "Component.h"
namespace crepe {
class Collider : public Component {
public:
- Collider(game_object_id_t id);
+ Collider(game_object_id_t id, Vector2 offset);
- int size;
+ //! Offset of the collider relative to rigidbody position
+ Vector2 offset;
};
} // namespace crepe
diff --git a/src/crepe/api/BehaviorScript.h b/src/crepe/api/BehaviorScript.h
index 9d85d4c..d556fe5 100644
--- a/src/crepe/api/BehaviorScript.h
+++ b/src/crepe/api/BehaviorScript.h
@@ -39,11 +39,14 @@ public:
* \brief Set the concrete script of this component
*
* \tparam T Concrete script type (derived from \c crepe::Script)
+ * \tparam Args Arguments for concrete script constructor
+ *
+ * \param args Arguments for concrete script constructor (forwarded using perfect forwarding)
*
* \returns Reference to BehaviorScript component (`*this`)
*/
- template <class T>
- BehaviorScript & set_script();
+ template <class T, typename... Args>
+ BehaviorScript & set_script(Args &&... args);
protected:
//! Script instance
diff --git a/src/crepe/api/BehaviorScript.hpp b/src/crepe/api/BehaviorScript.hpp
index d80321d..6bd123d 100644
--- a/src/crepe/api/BehaviorScript.hpp
+++ b/src/crepe/api/BehaviorScript.hpp
@@ -9,11 +9,11 @@
namespace crepe {
-template <class T>
-BehaviorScript & BehaviorScript::set_script() {
+template <class T, typename... Args>
+BehaviorScript & BehaviorScript::set_script(Args &&... args) {
dbg_trace();
static_assert(std::is_base_of<Script, T>::value);
- Script * s = new T();
+ Script * s = new T(std::forward<Args>(args)...);
s->game_object_id = this->game_object_id;
s->component_manager_ref = &this->component_manager;
this->script = std::unique_ptr<Script>(s);
diff --git a/src/crepe/api/BoxCollider.cpp b/src/crepe/api/BoxCollider.cpp
new file mode 100644
index 0000000..eafbdb2
--- /dev/null
+++ b/src/crepe/api/BoxCollider.cpp
@@ -0,0 +1,7 @@
+#include "BoxCollider.h"
+#include "../Collider.h"
+
+using namespace crepe;
+
+
+BoxCollider::BoxCollider(game_object_id_t game_object_id,Vector2 offset, double width, double height) : Collider(game_object_id,offset), width(width), height(height) {}
diff --git a/src/crepe/api/BoxCollider.h b/src/crepe/api/BoxCollider.h
new file mode 100644
index 0000000..7f51cba
--- /dev/null
+++ b/src/crepe/api/BoxCollider.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "Vector2.h"
+#include "../Collider.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,Vector2 offset, double width, double height);
+
+ //! Width of box collider
+ double width;
+
+ //! Height of box collider
+ double height;
+};
+
+} // namespace crepe
diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt
index d6b6801..830f5bd 100644
--- a/src/crepe/api/CMakeLists.txt
+++ b/src/crepe/api/CMakeLists.txt
@@ -17,6 +17,8 @@ target_sources(crepe PUBLIC
Vector2.cpp
Camera.cpp
Animator.cpp
+ BoxCollider.cpp
+ CircleCollider.cpp
EventManager.cpp
IKeyListener.cpp
IMouseListener.cpp
@@ -48,6 +50,8 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
SceneManager.hpp
Camera.h
Animator.h
+ BoxCollider.h
+ CircleCollider.h
EventManager.h
EventManager.hpp
EventHandler.h
diff --git a/src/crepe/api/CircleCollider.cpp b/src/crepe/api/CircleCollider.cpp
new file mode 100644
index 0000000..04a4995
--- /dev/null
+++ b/src/crepe/api/CircleCollider.cpp
@@ -0,0 +1,6 @@
+#include "CircleCollider.h"
+
+using namespace crepe;
+
+
+CircleCollider::CircleCollider(game_object_id_t game_object_id,Vector2 offset, int radius) : Collider(game_object_id,offset), radius(radius) {}
diff --git a/src/crepe/api/CircleCollider.h b/src/crepe/api/CircleCollider.h
index e77a592..4e04fa4 100644
--- a/src/crepe/api/CircleCollider.h
+++ b/src/crepe/api/CircleCollider.h
@@ -1,14 +1,23 @@
#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,Vector2 offset, int radius);
+
+ //! Radius of the circle collider.
+ double radius;
};
} // namespace crepe
diff --git a/src/crepe/api/Event.h b/src/crepe/api/Event.h
index 06cf7f3..8a6b931 100644
--- a/src/crepe/api/Event.h
+++ b/src/crepe/api/Event.h
@@ -3,6 +3,8 @@
#include <string>
+#include "system/CollisionSystem.h"
+
#include "KeyCodes.h"
/**
@@ -93,8 +95,9 @@ public:
*/
class CollisionEvent : public Event {
public:
- //! Data describing the collision (currently not implemented).
- // Collision collisionData;
+ crepe::CollisionSystem::CollisionInfo info;
+ CollisionEvent(const crepe::CollisionSystem::CollisionInfo& collisionInfo)
+ : info(collisionInfo) {}
};
/**
diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp
index a64366f..586919d 100644
--- a/src/crepe/api/LoopManager.cpp
+++ b/src/crepe/api/LoopManager.cpp
@@ -6,6 +6,8 @@
#include "../system/PhysicsSystem.h"
#include "../system/RenderSystem.h"
#include "../system/ScriptSystem.h"
+#include "..//system/PhysicsSystem.h"
+#include "..//system/CollisionSystem.h"
#include "LoopManager.h"
#include "LoopTimer.h"
@@ -32,7 +34,10 @@ void LoopManager::start() {
}
void LoopManager::set_running(bool running) { this->game_running = running; }
-void LoopManager::fixed_update() {}
+void LoopManager::fixed_update() {
+ this->get_system<PhysicsSystem>().update();
+ this->get_system<CollisionSystem>().update();
+}
void LoopManager::loop() {
LoopTimer & timer = LoopTimer::get_instance();
@@ -41,11 +46,11 @@ void LoopManager::loop() {
while (game_running) {
timer.update();
- while (timer.get_lag() >= timer.get_fixed_delta_time()) {
+ //while (timer.get_lag() >= timer.get_fixed_delta_time()) {
this->process_input();
this->fixed_update();
timer.advance_fixed_update();
- }
+ //}
this->update();
this->render();
diff --git a/src/crepe/api/Rigidbody.h b/src/crepe/api/Rigidbody.h
index 3e5c7a3..fddbf5c 100644
--- a/src/crepe/api/Rigidbody.h
+++ b/src/crepe/api/Rigidbody.h
@@ -1,5 +1,7 @@
#pragma once
+#include <cmath>
+
#include "../Component.h"
#include "Vector2.h"
@@ -58,13 +60,13 @@ public:
//! linear velocity of object
Vector2 linear_velocity;
//! maximum linear velocity of object
- Vector2 max_linear_velocity;
+ Vector2 max_linear_velocity = {INFINITY ,INFINITY};
//! linear damping of object
Vector2 linear_damping;
//! angular velocity of object
double angular_velocity = 0.0;
//! max angular velocity of object
- double max_angular_velocity = 0.0;
+ double max_angular_velocity = INFINITY;
//! angular damping of object
double angular_damping = 0.0;
//! movements constraints of object
@@ -73,6 +75,10 @@ public:
bool use_gravity = true;
//! if object bounces
bool bounce = false;
+ //! bounce factor of material
+ double elastisity = 0.0;
+ //! offset of all colliders relative to transform position
+ Vector2 offset;
};
public:
diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h
index 839d937..0702e36 100644
--- a/src/crepe/api/Script.h
+++ b/src/crepe/api/Script.h
@@ -64,6 +64,13 @@ protected:
template <typename T>
RefVector<T> get_components() const;
+ /**
+ * \brief Gets game object id this script is attached to
+ *
+ * \returns game object id
+ */
+ game_object_id_t get_game_object_id() const {return this->game_object_id;};
+
protected:
// NOTE: Script must have a constructor without arguments so the game programmer doesn't need
// to manually add `using Script::Script` to their concrete script class.
diff --git a/src/crepe/api/Vector2.h b/src/crepe/api/Vector2.h
index 2fb6136..438fde6 100644
--- a/src/crepe/api/Vector2.h
+++ b/src/crepe/api/Vector2.h
@@ -35,6 +35,9 @@ struct Vector2 {
//! Checks if this vector is not equal to another vector.
bool operator!=(const Vector2 & other) const;
+
+ //!
+ double dot(const Vector2& other) const;
};
} // namespace crepe
diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp
index c74ca1d..b23e779 100644
--- a/src/crepe/system/CollisionSystem.cpp
+++ b/src/crepe/system/CollisionSystem.cpp
@@ -1,5 +1,359 @@
+#include <cmath>
+#include <algorithm>
+#include <cstddef>
+#include <utility>
+#include <variant>
+
+#include "api/Event.h"
+#include "api/EventManager.h"
+#include "api/BoxCollider.h"
+#include "api/CircleCollider.h"
+#include "api/Vector2.h"
+#include "api/Rigidbody.h"
+#include "api/Transform.h"
+
+#include "ComponentManager.h"
#include "CollisionSystem.h"
+#include "Collider.h"
using namespace crepe;
-void CollisionSystem::update() {}
+void CollisionSystem::update() {
+ // Get collider components and keep them seperate
+ ComponentManager & mgr = this->component_manager;
+ std::vector<std::reference_wrapper<BoxCollider>> boxcolliders = mgr.get_components_by_type<BoxCollider>();
+ std::vector<std::reference_wrapper<CircleCollider>> circlecolliders = mgr.get_components_by_type<CircleCollider>();
+
+ // Check between all colliders if there is a collision
+ std::vector<std::pair<CollidedInfoStor,CollidedInfoStor>> collided = check_collisions(boxcolliders,circlecolliders);
+
+ // For both objects call the collision handler
+ for (auto& collision_pair : collided) {
+ collision_handler(collision_pair.first,collision_pair.second);
+ collision_handler(collision_pair.second,collision_pair.first);
+ }
+}
+
+void CollisionSystem::collision_handler(CollidedInfoStor& data1,CollidedInfoStor& data2){
+
+ // Data needed for collision handler info
+ const Collider* collider1 = nullptr;
+ const Collider* collider2 = nullptr;
+ Vector2 move_back;
+
+ // Check collision type and get values for handler
+ if (std::holds_alternative<BoxCollider>(data1.collider)) {
+ if (std::holds_alternative<BoxCollider>(data2.collider)) {
+
+ // Get colliders from variant to be used to determine collision handler info
+ const BoxCollider& box_collider1 = std::get<BoxCollider>(data1.collider);
+ const BoxCollider& box_collider2 = std::get<BoxCollider>(data2.collider);
+ collider1 = &box_collider1;
+ collider2 = &box_collider2;
+
+ // TODO: send with the collider info to this function because this is calculated previously
+ // Get the current position of the collider
+ Vector2 final_position1 = current_position(box_collider1,data1.transform,data1.rigidbody);
+ Vector2 final_position2 = current_position(box_collider2,data2.transform,data2.rigidbody);
+
+ // Determine move_back value for smallest overlap (x or y)
+ move_back = box_box_collision_move_back(box_collider1,box_collider2,final_position1,final_position2);
+
+ }
+ else {
+ // TODO: calcualte Box - Circle collision info
+ const BoxCollider& box_collider = std::get<BoxCollider>(data1.collider);
+ const CircleCollider& circle_collider = std::get<CircleCollider>(data2.collider);
+ collider1 = &box_collider;
+ collider2 = &circle_collider;
+ }
+ }
+ else {
+ if (std::holds_alternative<CircleCollider>(data2.collider)) {
+ // TODO: calcualte Circle - Circle collision info
+ const CircleCollider& circle_collider1 = std::get<CircleCollider>(data1.collider);
+ const CircleCollider& circle_collider2 = std::get<CircleCollider>(data2.collider);
+ collider1 = &circle_collider1;
+ collider2 = &circle_collider2;
+ }
+ else {
+ // TODO: calcualte Circle - Box collision info
+ const CircleCollider& circle_collider = std::get<CircleCollider>(data1.collider);
+ const BoxCollider& box_collider = std::get<BoxCollider>(data2.collider);
+ collider1 = &circle_collider;
+ collider2 = &box_collider;
+ }
+ }
+
+ // One vaue is calculated for moving back. Calculate the other value (x or y) relateive to the move_back value.
+ Direction move_back_direction = Direction::NONE;
+ if(move_back.x != 0 && move_back.y > 0) {
+ move_back_direction = Direction::BOTH;
+ } else if (move_back.x != 0) {
+ move_back_direction = Direction::X_DIRECTION;
+ if(data1.rigidbody.data.linear_velocity.y != 0)
+ move_back.y = data1.rigidbody.data.linear_velocity.y * (move_back.x/data1.rigidbody.data.linear_velocity.x);
+ } else if (move_back.y != 0) {
+ move_back_direction = Direction::Y_DIRECTION;
+ if(data1.rigidbody.data.linear_velocity.x != 0)
+ move_back.x = data1.rigidbody.data.linear_velocity.x * (move_back.y/data1.rigidbody.data.linear_velocity.y);
+ }
+
+ // collision info
+ crepe::CollisionSystem::CollisionInfo collision_info{
+ .first={ *collider1, data1.transform, data1.rigidbody },
+ .second={ *collider2, data2.transform, data2.rigidbody },
+ .move_back_value = move_back,
+ .move_back_direction = move_back_direction,
+ };
+
+ // Determine if static needs to be called
+ determine_collision_handler(collision_info);
+}
+
+
+Vector2 CollisionSystem::box_box_collision_move_back(const BoxCollider& box_collider1,const BoxCollider& box_collider2,Vector2 final_position1,Vector2 final_position2)
+{
+ Vector2 resolution; // Default resolution vector
+ Vector2 delta = final_position2 - final_position1;
+
+ // Compute half-dimensions of the boxes
+ double half_width1 = box_collider1.width / 2.0;
+ double half_height1 = box_collider1.height / 2.0;
+ double half_width2 = box_collider2.width / 2.0;
+ double half_height2 = box_collider2.height / 2.0;
+
+ // Calculate overlaps along X and Y axes
+ double overlap_x = (half_width1 + half_width2) - std::abs(delta.x);
+ double overlap_y = (half_height1 + half_height2) - std::abs(delta.y);
+
+ // Check if there is a collision
+ if (overlap_x > 0 && overlap_y > 0) {//should always be true check if this can be removed
+ // 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;
+}
+
+void CollisionSystem::determine_collision_handler(CollisionInfo& info){
+ // Check rigidbody type for static
+ if(info.first.rigidbody.data.body_type != Rigidbody::BodyType::STATIC)
+ {
+ // If second body is static perform the static collision handler in this system
+ if(info.second.rigidbody.data.body_type == Rigidbody::BodyType::STATIC){
+ static_collision_handler(info);
+ };
+ // Call collision event for user
+ CollisionEvent data(info);
+ EventManager::get_instance().trigger_event<CollisionEvent>(data, info.first.collider.game_object_id);
+ }
+}
+
+void CollisionSystem::static_collision_handler(CollisionInfo& info){
+ // Move object back using calculate move back value
+ info.first.transform.position += info.move_back_value;
+
+ // If bounce is enabled mirror velocity
+ if(info.first.rigidbody.data.bounce) {
+ if(info.move_back_direction == Direction::BOTH)
+ {
+ info.first.rigidbody.data.linear_velocity.y = -info.first.rigidbody.data.linear_velocity.y * info.first.rigidbody.data.elastisity;
+ info.first.rigidbody.data.linear_velocity.x = -info.first.rigidbody.data.linear_velocity.x * info.first.rigidbody.data.elastisity;
+ }
+ else if(info.move_back_direction == Direction::Y_DIRECTION) {
+ info.first.rigidbody.data.linear_velocity.y = -info.first.rigidbody.data.linear_velocity.y * info.first.rigidbody.data.elastisity;
+ }
+ else if(info.move_back_direction == Direction::X_DIRECTION){
+ info.first.rigidbody.data.linear_velocity.x = -info.first.rigidbody.data.linear_velocity.x * info.first.rigidbody.data.elastisity;
+ }
+ }
+ // Stop movement if bounce is disabled
+ else {
+ info.first.rigidbody.data.linear_velocity = {0,0};
+ }
+}
+
+std::vector<std::pair<CollisionSystem::CollidedInfoStor,CollisionSystem::CollidedInfoStor>> CollisionSystem::check_collisions(const std::vector<std::reference_wrapper<BoxCollider>>& boxcolliders, const std::vector<std::reference_wrapper<CircleCollider>>& circlecolliders) {
+ ComponentManager & mgr = this->component_manager;
+ std::vector<std::pair<CollidedInfoStor,CollidedInfoStor>> collisions_ret;
+
+ // 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
+
+ // Check collisions for each collider
+ for (size_t i = 0; i < boxcolliders.size(); ++i) {
+ // Fetch components for the first box collider
+ if(!boxcolliders[i].get().active) continue;
+ int game_object_id_1 = boxcolliders[i].get().game_object_id;
+ Transform& transform1 = mgr.get_components_by_id<Transform>(game_object_id_1).front().get();
+ if(!transform1.active) continue;
+ Rigidbody& rigidbody1 = mgr.get_components_by_id<Rigidbody>(game_object_id_1).front().get();
+ if(!rigidbody1.active) continue;
+
+ // Check BoxCollider vs BoxCollider
+ for (size_t j = i + 1; j < boxcolliders.size(); ++j) {
+ if(!boxcolliders[j].get().active) continue;
+ // Skip self collision
+ int game_object_id_2 = boxcolliders[j].get().game_object_id;
+ if (game_object_id_1 == game_object_id_2) continue;
+
+ // Fetch components for the second box collider
+ Transform & transform2 = mgr.get_components_by_id<Transform>(boxcolliders[j].get().game_object_id).front().get();
+ if(!transform2.active) continue;
+ Rigidbody & rigidbody2 = mgr.get_components_by_id<Rigidbody>(boxcolliders[j].get().game_object_id).front().get();
+ if(!rigidbody2.active) continue;
+ // Check collision
+ if (check_box_box_collision(boxcolliders[i], boxcolliders[j], transform1, transform2, rigidbody1, rigidbody2)) {
+ collisions_ret.emplace_back(std::make_pair(
+ CollidedInfoStor{boxcolliders[i], transform1, rigidbody1},
+ CollidedInfoStor{boxcolliders[j], transform2, rigidbody2}
+ ));
+ }
+ }
+
+ // Check BoxCollider vs CircleCollider
+ for (size_t j = 0; j < circlecolliders.size(); ++j) {
+ if(!circlecolliders[j].get().active) continue;
+ // Skip self collision
+ int game_object_id_2 = circlecolliders[j].get().game_object_id;
+ if (game_object_id_1 == game_object_id_2) continue;
+
+ // Fetch components for the second collider (circle)
+ Transform & transform2 = mgr.get_components_by_id<Transform>(circlecolliders[j].get().game_object_id).front().get();
+ if(!transform2.active) continue;
+ Rigidbody & rigidbody2 = mgr.get_components_by_id<Rigidbody>(circlecolliders[j].get().game_object_id).front().get();
+ if(!rigidbody2.active) continue;
+
+ // Check collision
+ if (check_box_circle_collision(boxcolliders[i], circlecolliders[j], transform1, transform2, rigidbody1, rigidbody2)) {
+
+ collisions_ret.emplace_back(std::make_pair(
+ CollidedInfoStor{boxcolliders[i], transform1, rigidbody1},
+ CollidedInfoStor{circlecolliders[j], transform2, rigidbody2}
+ ));
+ }
+ }
+ }
+ // Check CircleCollider vs CircleCollider
+ for (size_t i = 0; i < circlecolliders.size(); ++i) {
+ if(!circlecolliders[i].get().active) continue;
+ // Fetch components for the first circle collider
+ int game_object_id_1 = circlecolliders[i].get().game_object_id;
+ Transform & transform1 = mgr.get_components_by_id<Transform>(circlecolliders[i].get().game_object_id).front().get();
+ if(!transform1.active) continue;
+ Rigidbody & rigidbody1 = mgr.get_components_by_id<Rigidbody>(circlecolliders[i].get().game_object_id).front().get();
+ if(!rigidbody1.active) continue;
+
+ for (size_t j = i + 1; j < circlecolliders.size(); ++j) {
+ if(!circlecolliders[j].get().active) continue;
+ // Skip self collision
+ int game_object_id_2 = circlecolliders[j].get().game_object_id;
+ if (game_object_id_1 == game_object_id_2) continue;
+
+ // Fetch components for the second circle collider
+ Transform & transform2 = mgr.get_components_by_id<Transform>(circlecolliders[j].get().game_object_id).front().get();
+ if(!transform2.active) continue;
+ Rigidbody & rigidbody2 = mgr.get_components_by_id<Rigidbody>(circlecolliders[j].get().game_object_id).front().get();
+ if(!rigidbody2.active) continue;
+
+ // Check collision
+ if (check_circle_circle_collision(circlecolliders[i], circlecolliders[j], transform1, transform2, rigidbody1, rigidbody2)) {
+ collisions_ret.emplace_back(std::make_pair(
+ CollidedInfoStor{circlecolliders[i], transform1, rigidbody1},
+ CollidedInfoStor{circlecolliders[j], transform2, rigidbody2}
+ ));
+ }
+ }
+ }
+ return collisions_ret;
+}
+
+bool CollisionSystem::check_box_box_collision(const BoxCollider& box1, const BoxCollider& box2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2)
+{
+ // Get current positions of colliders
+ Vector2 final_position1 = current_position(box1,transform1,rigidbody1);
+ Vector2 final_position2 = current_position(box2,transform2,rigidbody2);
+
+ // Calculate half-extents (half width and half height)
+ double half_width1 = box1.width / 2.0;
+ double half_height1 = box1.height / 2.0;
+ double half_width2 = box2.width / 2.0;
+ double half_height2 = box2.height / 2.0;
+
+ // Check if the boxes overlap along the X and Y axes
+ return !(final_position1.x + half_width1 <= final_position2.x - half_width2 || // box1 is left of box2
+ final_position1.x - half_width1 >= final_position2.x + half_width2 || // box1 is right of box2
+ final_position1.y + half_height1 <= final_position2.y - half_height2 || // box1 is above box2
+ final_position1.y - half_height1 >= final_position2.y + half_height2); // box1 is below box2
+}
+
+bool CollisionSystem::check_box_circle_collision(const BoxCollider& box1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) {
+ // Get current positions of colliders
+ Vector2 final_position1 = current_position(box1, transform1, rigidbody1);
+ Vector2 final_position2 = current_position(circle2, transform2, rigidbody2);
+
+ // Calculate box half-extents
+ double half_width = box1.width / 2.0;
+ double half_height = box1.height / 2.0;
+
+ // Find the closest point on the box to the circle's center
+ double closest_x = std::max(final_position1.x - half_width, std::min(final_position2.x, final_position1.x + half_width));
+ double 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
+ double distance_x = final_position2.x - closest_x;
+ double distance_y = final_position2.y - closest_y;
+ double 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::check_circle_circle_collision(const CircleCollider& circle1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) {
+ // Get current positions of colliders
+ Vector2 final_position1 = current_position(circle1,transform1,rigidbody1);
+ Vector2 final_position2 = current_position(circle2,transform2,rigidbody2);
+
+ double distance_x = final_position1.x - final_position2.x;
+ double distance_y = final_position1.y - final_position2.y;
+ double distance_squared = distance_x * distance_x + distance_y * distance_y;
+
+ // Calculate the sum of the radii
+ double 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;
+}
+
+Vector2 CollisionSystem::current_position(const Collider& collider, const Transform& transform, const Rigidbody& rigidbody) {
+ // Get the rotation in radians
+ double radians1 = transform.rotation * (M_PI / 180.0);
+
+ // Calculate total offset with scale
+ Vector2 total_offset = (rigidbody.data.offset + collider.offset) * transform.scale;
+
+ // Rotate
+ double rotated_total_offset_x1 = total_offset.x * cos(radians1) - total_offset.y * sin(radians1);
+ double rotated_total_offset_y1 = total_offset.x * sin(radians1) + total_offset.y * cos(radians1);
+
+ // Final positions considering scaling and rotation
+ return(transform.position + Vector2(rotated_total_offset_x1, rotated_total_offset_y1));
+
+}
diff --git a/src/crepe/system/CollisionSystem.h b/src/crepe/system/CollisionSystem.h
index c1a70d8..d94f6bc 100644
--- a/src/crepe/system/CollisionSystem.h
+++ b/src/crepe/system/CollisionSystem.h
@@ -1,13 +1,192 @@
#pragma once
+#include <vector>
+#include <variant>
+
+#include "api/Rigidbody.h"
+#include "api/Transform.h"
+#include "api/BoxCollider.h"
+#include "api/CircleCollider.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_stor = std::variant<BoxCollider, CircleCollider>;
+
+ /**
+ * \brief A structure to store the collision data of a single collider.
+ *
+ * This structure stores the collider type, its associated transform, and its rigidbody.
+ */
+ struct CollidedInfoStor {
+ //! Store either BoxCollider or CircleCollider
+ collider_stor collider;
+ Transform& transform;
+ Rigidbody& rigidbody;
+ };
+
+ //! Enum representing movement directions during collision resolution.
+ enum class Direction {
+ NONE,
+ X_DIRECTION,
+ Y_DIRECTION,
+ BOTH
+ };
+
+public:
+ /**
+ * \brief A structure representing the collision information between two colliders.
+ *
+ * This structure contains both colliders, their associated transforms and rigidbodies,
+ * as well as the movement vector to resolve the collision.
+ */
+ struct ColliderInfo {
+ const Collider& collider;
+ Transform& transform;
+ Rigidbody& rigidbody;
+ };
+ /**
+ * \brief A structure representing detailed collision information between two colliders.
+ *
+ * This includes the movement data required to resolve the collision.
+ */
+ struct CollisionInfo{
+ ColliderInfo first;
+ ColliderInfo second;
+ Vector2 move_back_value;
+ Direction move_back_direction = Direction::NONE;
+ };
+
+public:
+
+ //! Updates the collision system by checking for collisions between colliders and handling them.
void update() override;
+
+private:
+ /**
+ * \brief Handles a collision between two colliders.
+ *
+ * This function calculates the necessary response to resolve the collision, including
+ * moving the objects back to prevent overlap and applying any velocity changes.
+ *
+ * \param data1 The collision data for the first collider.
+ * \param data2 The collision data for the second collider.
+ */
+ void collision_handler(CollidedInfoStor& data1,CollidedInfoStor& data2);
+
+ /**
+ * \brief Resolves the movement of two box colliders that are colliding.
+ *
+ * This function calculates the smallest overlap (along the X or Y axis) and determines
+ * the move-back vector to prevent overlap.
+ *
+ * \param box_collider1 The first box collider.
+ * \param box_collider2 The second box collider.
+ * \param final_position1 The final position of the first box collider.
+ * \param final_position2 The final position of the second box collider.
+ * \return The move-back vector to resolve the collision.
+ */
+ Vector2 box_box_collision_move_back(const BoxCollider& box_collider1,const BoxCollider& box_collider2,Vector2 position1,Vector2 position2);
+
+ /**
+ * \brief Determines the appropriate collision handler based on the rigidbody types of the colliding objects.
+ *
+ * This function checks if the second object is static, and if so, it calls the static collision handler.
+ * Otherwise, it triggers a collision event.
+ *
+ * \param info The collision information containing the colliders, transforms, rigidbodies, and move-back data.
+ */
+ void determine_collision_handler(CollisionInfo& info);
+
+ /**
+ * \brief Handles the collision with a static object.
+ *
+ * This function resolves the collision by moving the object back and applying any bounce or stop behavior.
+ *
+ * \param info The collision information containing the colliders, transforms, rigidbodies, and move-back data.
+ */
+ void static_collision_handler(CollisionInfo& info);
+private: //detection
+
+ /**
+ * \brief Checks for collisions between box colliders and circle colliders
+ * and returns the collision pairs that need to be resolved.
+ *
+ * \param boxcolliders A vector of references to all box colliders.
+ * \param circlecolliders A vector of references to all circle colliders.
+ * \return A vector of pairs containing collision information for the detected collisions.
+ */
+ std::vector<std::pair<CollidedInfoStor,CollidedInfoStor>> check_collisions(const std::vector<std::reference_wrapper<BoxCollider>>& boxcolliders, const std::vector<std::reference_wrapper<CircleCollider>>& circlecolliders);
+
+ /**
+ * \brief Checks for a collision between two box colliders.
+ *
+ * This function checks if two box colliders overlap based on their positions and dimensions.
+ *
+ * \param box1 The first box collider.
+ * \param box2 The second box collider.
+ * \param transform1 The transform component of the first box collider.
+ * \param transform2 The transform component of the second box collider.
+ * \param rigidbody1 The rigidbody component of the first box collider.
+ * \param rigidbody2 The rigidbody component of the second box collider.
+ * \return True if the two box colliders overlap, otherwise false.
+ */
+ bool check_box_box_collision(const BoxCollider& box1, const BoxCollider& box2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2);
+
+ /**
+ * \brief Checks for a collision between a box collider and a circle collider.
+ *
+ * This function checks if a box collider overlaps with a circle collider based on their positions
+ * and dimensions.
+ *
+ * \param box1 The box collider.
+ * \param circle2 The circle collider.
+ * \param transform1 The transform component of the box collider.
+ * \param transform2 The transform component of the circle collider.
+ * \param rigidbody1 The rigidbody component of the box collider.
+ * \param rigidbody2 The rigidbody component of the circle collider.
+ * \return True if the box collider and circle collider overlap, otherwise false.
+ */
+ bool check_box_circle_collision(const BoxCollider& box1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2);
+
+ /**
+ * \brief Checks for a collision between two circle colliders.
+ *
+ * This function checks if two circle colliders overlap based on their positions and radii.
+ *
+ * \param circle1 The first circle collider.
+ * \param circle2 The second circle collider.
+ * \param transform1 The transform component of the first circle collider.
+ * \param transform2 The transform component of the second circle collider.
+ * \param rigidbody1 The rigidbody component of the first circle collider.
+ * \param rigidbody2 The rigidbody component of the second circle collider.
+ * \return True if the two circle colliders overlap, otherwise false.
+ */
+ bool check_circle_circle_collision(const CircleCollider& circle1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2);
+
+ /**
+ * \brief Gets the current position of a collider by combining its transform and rigidbody data.
+ *
+ * This function calculates the current position of the collider by considering its transform and
+ * rigidbody velocity.
+ *
+ * \param collider The collider whose position is being determined.
+ * \param transform The transform component associated with the collider.
+ * \param rigidbody The rigidbody component associated with the collider.
+ * \return The current position of the collider as a Vector2.
+ */
+ Vector2 current_position(const Collider& collider, const Transform& transform, const Rigidbody& rigidbody);
};
} // namespace crepe
diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp
index ad510f5..8f9467e 100644
--- a/src/crepe/system/RenderSystem.cpp
+++ b/src/crepe/system/RenderSystem.cpp
@@ -28,6 +28,8 @@ void RenderSystem::update_camera() {
if (cameras.size() == 0) throw std::runtime_error("No cameras in current scene");
+ if (cameras.size() == 0) throw std::runtime_error("No cameras in current scene");
+
for (Camera & cam : cameras) {
if (!cam.active) continue;
this->context.set_camera(cam);