diff options
| author | JAROWMR <jarorutjes07@gmail.com> | 2024-12-02 10:41:37 +0100 | 
|---|---|---|
| committer | JAROWMR <jarorutjes07@gmail.com> | 2024-12-02 10:41:37 +0100 | 
| commit | 09c4c1485ab797dc5f6f850b96262e2f7bbbd1ec (patch) | |
| tree | 1dbdd6e1b0042b91904bcab64af1e430dcdb5901 | |
| parent | 98ab67b5c4a4f2df16089e84488148e8de1f977c (diff) | |
resolution for circle circle and box circle
| -rw-r--r-- | src/crepe/system/CollisionSystem.cpp | 95 | ||||
| -rw-r--r-- | src/crepe/system/CollisionSystem.h | 28 | ||||
| -rw-r--r-- | src/test/CollisionTest.cpp | 35 | 
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); +}  |