From b7721baeb7231bd0adb89212f5cee0f3bb5dac4a Mon Sep 17 00:00:00 2001 From: Sara Date: Sat, 7 Oct 2023 22:58:15 +0200 Subject: [PATCH] collision_check will now return 1 if there is a collision, and write collision data to the new out variables --- src/collision.c | 79 +++++++++++++++++++++++++++++++++++-------------- src/collision.h | 9 ++++-- 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/src/collision.c b/src/collision.c index d690b1f..e302e9c 100644 --- a/src/collision.c +++ b/src/collision.c @@ -8,7 +8,7 @@ typedef struct Range {float min; float max; } Range; static -Range _shape_get_range_on_axis(PhysicsEntity self, Vector axis) { +Range _internal_collision_get_range_on_axis(PhysicsEntity self, Vector axis) { Vector point = shape_get_point_transformed(self.tc->get_shape(self.data), 0, *self.transformable->get_transform(self.data)); float dot = vdotf(axis, point); Range range = {dot, dot}; @@ -26,9 +26,9 @@ Range _shape_get_range_on_axis(PhysicsEntity self, Vector axis) { } static -Vector _shape_overlap_on_axis(PhysicsEntity self, PhysicsEntity other, Vector axis) { - Range a_range = _shape_get_range_on_axis(self, axis); - Range b_range = _shape_get_range_on_axis(other, axis); +Vector _internal_collision_overlap_on_axis(PhysicsEntity self, PhysicsEntity other, Vector axis) { + Range a_range = _internal_collision_get_range_on_axis(self, axis); + Range b_range = _internal_collision_get_range_on_axis(other, axis); if(a_range.min <= b_range.max && b_range.min <= b_range.max) return vmulff(axis, fminf(b_range.max - b_range.min, b_range.min - a_range.max)); @@ -37,27 +37,31 @@ Vector _shape_overlap_on_axis(PhysicsEntity self, PhysicsEntity other, Vector ax } static -Collision _shape_get_overlap_internal(PhysicsEntity self, PhysicsEntity other) { - // The shortest escape vector found so far +int _internal_collision_get_overlap(PhysicsEntity self, PhysicsEntity other, Collision* out) { + // get components used + Shape* self_shape = self.tc->get_shape(self.data); + Transform* self_transform = self.transformable->get_transform(self.data); + + // the shortest distance to solve collision found so far Vector shortest_escape = InfinityVector; // the squared length of the shortest escape vector found so far float shortest_sqrmag = INFINITY; // the first index of the points on the edge size_t shortest_escape_edge = 0; // the number of points in the shape of self - size_t self_point_count = shape_get_points_count(self.tc->get_shape(self.data)); + size_t self_point_count = shape_get_points_count(self_shape); for(size_t point_index = 0; point_index < self_point_count; ++point_index) { // the next point on the line size_t next_index = (point_index + 1) % self_point_count; // get the two points defining the collision edge - Vector a = shape_get_point_transformed(self.tc->get_shape(self.data), point_index, *self.transformable->get_transform(self.data)); - Vector b = shape_get_point_transformed(self.tc->get_shape(self.data), next_index, *self.transformable->get_transform(self.data)); + Vector a = shape_get_point_transformed(self.tc->get_shape(self.data), point_index, *self_transform); + Vector b = shape_get_point_transformed(self.tc->get_shape(self.data), next_index, *self_transform); // the direction of the line Vector diff = vsubf(b, a); // the smallest escape vector on this axis - Vector escape = _shape_overlap_on_axis(self, other, vnormalizedf(diff)); + Vector escape = _internal_collision_overlap_on_axis(self, other, vnormalizedf(diff)); float sqr_mag = vsqrmagnitudef(escape); if(sqr_mag < shortest_sqrmag) { shortest_sqrmag = sqr_mag; @@ -69,20 +73,51 @@ Collision _shape_get_overlap_internal(PhysicsEntity self, PhysicsEntity other) { RigidBody* rba = self.tc->get_rigidbody(self.data); RigidBody* rbb = self.tc->get_rigidbody(self.data); - return (Collision) { - .edge_left = shortest_escape_edge, - .edge_right = (1 + shortest_escape_edge) % self_point_count, - .normal = vnormalizedf(shortest_escape), - .velocity = vsubf(rigidbody_get_velocity(rba), rigidbody_get_velocity(rbb)), + *out = (Collision) { .other = other, - .separation_force = shortest_escape + + .point = InfinityVector, + .normal = vnormalizedf(shortest_escape), + + .velocity = vsubf(rigidbody_get_velocity(rba), rigidbody_get_velocity(rbb)), + .separation_force = shortest_escape, + + .edge_left = shape_get_point_transformed(self_shape, shortest_escape_edge, *self_transform), + .edge_right = shape_get_point_transformed(self_shape, (1 + shortest_escape_edge) % self_point_count, *self_transform), + }; + + return shortest_sqrmag != 0; +} + +static +Collision _internal_collision_invert(Collision collision_a, PhysicsEntity a) { + return (Collision){ + .other = a, + .point = collision_a.point, + .normal = vinvf(collision_a.normal), + .velocity = vinvf(collision_a.velocity), + .separation_force = vinvf(collision_a.separation_force), + .edge_left = collision_a.edge_left, + .edge_right = collision_a.edge_right, }; } -Collision get_collision(PhysicsEntity a, PhysicsEntity b) { - Collision self_first = _shape_get_overlap_internal(a, b); - Collision other_first = _shape_get_overlap_internal(b, a); - return vsqrmagnitudef(self_first.separation_force) < vsqrmagnitudef(other_first.separation_force) - ? self_first - : other_first; +int collision_check(PhysicsEntity a, PhysicsEntity b, Collision* out_a, Collision* out_b) { + Collision collision_a, collision_b; + int collision_a_overlaps = _internal_collision_get_overlap(a, b, &collision_a); + int collision_b_overlaps = _internal_collision_get_overlap(b, a, &collision_b); + + if(!collision_a_overlaps && !collision_b_overlaps) { + return 0; + } + + if(vsqrmagnitudef(collision_a.separation_force) < vsqrmagnitudef(collision_b.separation_force)) { + collision_b = _internal_collision_invert(collision_a, a); + } else { + collision_a = _internal_collision_invert(collision_b, b); + } + + *out_a = collision_a; + *out_b = collision_b; + return 1; } \ No newline at end of file diff --git a/src/collision.h b/src/collision.h index 5e4b9db..9d639c0 100644 --- a/src/collision.h +++ b/src/collision.h @@ -7,14 +7,17 @@ typedef struct Collision { PhysicsEntity other; + Vector point; Vector normal; + Vector velocity; Vector separation_force; - size_t edge_left; - size_t edge_right; + + Vector edge_left; + Vector edge_right; } Collision; -extern Collision get_collision(PhysicsEntity a, PhysicsEntity b); +extern int collision_check(PhysicsEntity a, PhysicsEntity b, Collision* out_a, Collision* out_b); #endif // !_fencer_collision_h