aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJAROWMR <jarorutjes07@gmail.com>2024-12-02 10:41:37 +0100
committerJAROWMR <jarorutjes07@gmail.com>2024-12-02 10:41:37 +0100
commit09c4c1485ab797dc5f6f850b96262e2f7bbbd1ec (patch)
tree1dbdd6e1b0042b91904bcab64af1e430dcdb5901
parent98ab67b5c4a4f2df16089e84488148e8de1f977c (diff)
resolution for circle circle and box circle
-rw-r--r--src/crepe/system/CollisionSystem.cpp95
-rw-r--r--src/crepe/system/CollisionSystem.h28
-rw-r--r--src/test/CollisionTest.cpp35
3 files changed, 142 insertions, 16 deletions
diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp
index 48baaf5..0b83bce 100644
--- a/src/crepe/system/CollisionSystem.cpp
+++ b/src/crepe/system/CollisionSystem.cpp
@@ -97,40 +97,53 @@ void CollisionSystem::collision_handler_request(CollisionInternal& data1,Collisi
std::pair<vec2,CollisionSystem::Direction> CollisionSystem::collision_handler(CollisionInternal& data1,CollisionInternal& data2,CollisionInternalType type) {
- vec2 move_back;
+ 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 = current_position(collider1.offset, data1.transform, data1.rigidbody);
vec2 collider_pos2 = current_position(collider2.offset, data2.transform, data2.rigidbody);
- move_back = box_box_resolution(collider1,collider2,collider_pos1,collider_pos2);
+ resolution = box_box_resolution(collider1,collider2,collider_pos1,collider_pos2);
}
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 = current_position(collider1.offset, data1.transform, data1.rigidbody);
+ vec2 collider_pos2 = current_position(collider2.offset, data2.transform, data2.rigidbody);
+ resolution = circle_box_resolution(collider2,collider1,collider_pos2,collider_pos1);
+
}
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 = current_position(collider1.offset, data1.transform, data1.rigidbody);
+ vec2 collider_pos2 = current_position(collider2.offset, data2.transform, data2.rigidbody);
+ resolution = circle_circle_resolution(collider1,collider2,collider_pos1,collider_pos2);
}
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 = current_position(collider1.offset, data1.transform, data1.rigidbody);
+ vec2 collider_pos2 = current_position(collider2.offset, data2.transform, data2.rigidbody);
+ resolution = circle_box_resolution(collider1,collider2,collider_pos1,collider_pos2);
}
}
- 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;
+ 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)
- 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;
+ 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)
- move_back.x = data1.rigidbody.data.linear_velocity.x * (move_back.y/data1.rigidbody.data.linear_velocity.y);
+ resolution.x = data1.rigidbody.data.linear_velocity.x * (resolution.y/data1.rigidbody.data.linear_velocity.y);
}
- return {move_back,move_back_direction};
+ return {resolution,resolution_direction};
}
vec2 CollisionSystem::box_box_resolution(const BoxCollider& box_collider1,const BoxCollider& box_collider2,vec2 final_position1,vec2 final_position2)
@@ -167,6 +180,58 @@ vec2 CollisionSystem::box_box_resolution(const BoxCollider& box_collider1,const
return resolution;
}
+vec2 CollisionSystem::circle_circle_resolution(const CircleCollider& circle_collider1, const CircleCollider& circle_collider2, vec2 final_position1, vec2 final_position2)
+{
+ 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::circle_box_resolution(const CircleCollider& circle_collider, const BoxCollider& box_collider, vec2 circle_position, vec2 box_position)
+{
+ vec2 delta = circle_position - box_position;
+
+ // Compute half-dimensions of the box
+ float half_width = box_collider.width / 2.0f;
+ float half_height = box_collider.height / 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.first_rigidbody.data.body_type != Rigidbody::BodyType::STATIC)
diff --git a/src/crepe/system/CollisionSystem.h b/src/crepe/system/CollisionSystem.h
index ea8c1e1..86b8b7a 100644
--- a/src/crepe/system/CollisionSystem.h
+++ b/src/crepe/system/CollisionSystem.h
@@ -139,11 +139,37 @@ private:
* \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 first BoxCollider.
+ * \return The resolution vector for the collision.
*/
vec2 box_box_resolution(const BoxCollider& box_collider1,const BoxCollider& box_collider2,vec2 position1,vec2 position2);
/**
+ * \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 position1 The position of the first CircleCollider.
+ * \param position2 The position of the second CircleCollider.
+ * \return The resolution vector for the collision.
+ */
+ vec2 circle_circle_resolution(const CircleCollider& circle_collider1, const CircleCollider& circle_collider2, vec2 final_position1, vec2 final_position2);
+
+ /**
+ * \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 BocCollider.
+ * \return The resolution vector for the collision.
+ */
+ vec2 circle_box_resolution(const CircleCollider& circle_collider, const BoxCollider& box_collider, vec2 circle_position, vec2 box_position);
+
+ /**
* \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.
diff --git a/src/test/CollisionTest.cpp b/src/test/CollisionTest.cpp
index 8daf77f..ed40b1b 100644
--- a/src/test/CollisionTest.cpp
+++ b/src/test/CollisionTest.cpp
@@ -1,3 +1,4 @@
+#include "api/BoxCollider.h"
#include <cmath>
#include <cstddef>
#include <gtest/gtest.h>
@@ -345,3 +346,37 @@ TEST_F(CollisionTest, collision_box_box_static_y_direction) {
collision_sys.update();
EXPECT_TRUE(collision_happend);
}
+
+TEST_F(CollisionTest, collision_box_box_static_multiple) {//todo check visually
+ bool collision_happend = false;
+ float offset_value = 0;
+ float resolution = 0;
+ script_object1_ref->test_fn = [&](const CollisionEvent & ev) {
+ collision_happend = true;
+ EXPECT_EQ(ev.info.first_collider.game_object_id, 1);
+ EXPECT_EQ(ev.info.first_collider.offset.x , offset_value);
+ EXPECT_EQ(ev.info.resolution.x , resolution);
+ };
+ script_object2_ref->test_fn = [&](const CollisionEvent & ev) {
+ // is static should not be called
+ FAIL();
+ };
+ EXPECT_FALSE(collision_happend);
+ Transform & tf = this->mgr.get_components_by_id<Transform>(1).front().get();
+ tf.position = {45,30};
+ Rigidbody & rg1 = this->mgr.get_components_by_id<Rigidbody>(1).front().get();
+ rg1.data.linear_velocity = {10,10};
+ Rigidbody & rg2 = this->mgr.get_components_by_id<Rigidbody>(2).front().get();
+ rg2.data.body_type = crepe::Rigidbody::BodyType::STATIC;
+ BoxCollider & bxc = this->mgr.get_components_by_id<BoxCollider>(1).front().get();
+ bxc.offset = {5,0};
+ this->game_object1.add_component<BoxCollider>(vec2{-5, 0}, 10, 10);
+ offset_value = 5;
+ resolution = 10;
+ collision_sys.update();
+ offset_value = -5;
+ resolution = 10;
+ tf.position = {55,30};
+ collision_sys.update();
+ EXPECT_TRUE(collision_happend);
+}