diff --git a/core/src/collision.c b/core/src/collision.c index 11968b5..173168a 100644 --- a/core/src/collision.c +++ b/core/src/collision.c @@ -9,9 +9,9 @@ typedef struct Range {float min; Vector minpoint; float max; Vector maxpoint; } Range; static -Range _internal_collision_get_range_on_axis(PhysicsEntity self, Vector axis) { - Transform* transform = self.transformable->get_transform(self.data); - Shape* shape = self.tc->get_shape(self.data); +Range _internal_collision_get_range_on_axis(PhysicsQuery self, Vector axis) { + Transform* transform = self.transform; + Shape* shape = self.shape; Vector point = shape_get_point_transformed(shape, 0, *transform); float dot = vdotf(axis, point); Range range = {dot, point, dot, point}; @@ -33,7 +33,7 @@ Range _internal_collision_get_range_on_axis(PhysicsEntity self, Vector axis) { } static -Vector _internal_collision_overlap_on_axis(PhysicsEntity self, PhysicsEntity other, Vector axis, Vector* out_point) { +Vector _internal_collision_overlap_on_axis(PhysicsQuery self, PhysicsQuery other, Vector axis, Vector* out_point) { Range a_range = _internal_collision_get_range_on_axis(self, axis); Range b_range = _internal_collision_get_range_on_axis(other, axis); @@ -49,10 +49,20 @@ Vector _internal_collision_overlap_on_axis(PhysicsEntity self, PhysicsEntity oth } static -int _internal_collision_get_overlap(PhysicsEntity self, PhysicsEntity other, Collision* out) { +int _internal_collision_get_collisions(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); + PhysicsQuery self_query = { + .shape = self_shape, + .transform = self_transform, + .mask = 0x0 // not used + }; + PhysicsQuery other_query = { + .shape = other.tc->get_shape(other.data), + .transform = other.transformable->get_transform(other.data), + .mask = 0x0 // not used + }; // the shortest distance to solve collision found so far Vector shortest_escape = InfinityVector; @@ -74,7 +84,7 @@ int _internal_collision_get_overlap(PhysicsEntity self, PhysicsEntity other, Col Vector overlap_point; // the smallest escape vector on this axis - Vector escape = _internal_collision_overlap_on_axis(self, other, normal, &overlap_point); + Vector escape = _internal_collision_overlap_on_axis(self_query, other_query, normal, &overlap_point); float dot = vdotf(vinvf(normal), escape); if(dot <= 0.0) { return 0; @@ -90,7 +100,7 @@ int _internal_collision_get_overlap(PhysicsEntity self, PhysicsEntity other, Col RigidBody* rbb = other.tc->get_rigidbody(other.data); const Vector velocity = vsubf(rigidbody_get_velocity(rba), rigidbody_get_velocity(rbb)); const Vector normal = vnormalizedf(shortest_escape); - Vector world_point = _internal_collision_get_range_on_axis(self, normal).minpoint; + Vector world_point = _internal_collision_get_range_on_axis(self_query, normal).minpoint; *out = (Collision) { .other = other, @@ -109,8 +119,12 @@ int _internal_collision_get_overlap(PhysicsEntity self, PhysicsEntity other, Col } Collision collision_invert(Collision collision_a, PhysicsEntity a) { - Vector world_point = _internal_collision_get_range_on_axis(collision_a.other, collision_a.normal).maxpoint; RigidBody* body = collision_a.other.tc->get_rigidbody(collision_a.other.data); + Shape* shape = collision_a.other.tc->get_shape(collision_a.other.data); + Transform* transform = rigidbody_get_transform(body); + + Vector world_point = _internal_collision_get_range_on_axis((PhysicsQuery){.shape = shape, .transform = transform }, collision_a.normal).maxpoint; + return (Collision){ .other = a, .point = inverse_transform_point(rigidbody_get_transform(body), world_point), @@ -124,8 +138,8 @@ Collision collision_invert(Collision collision_a, PhysicsEntity a) { 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); + int collision_a_overlaps = _internal_collision_get_collisions(a, b, &collision_a); + int collision_b_overlaps = _internal_collision_get_collisions(b, a, &collision_b); if(!collision_a_overlaps || !collision_b_overlaps) return 0; @@ -139,3 +153,38 @@ int collision_check(PhysicsEntity a, PhysicsEntity b, Collision* out_a, Collisio *out_b = collision_b; return (collision_b_overlaps << 1) | collision_a_overlaps; } + +static +int _internal_overlap_check(PhysicsQuery a, PhysicsQuery b) { + Shape* shape = a.shape; + Transform* transform = a.transform; + const size_t shape_point_count = shape_get_points_count(shape); + + for(size_t point_index = 0; point_index < shape_point_count; ++point_index) { + // the next point on the line + size_t next_index = (point_index + 1) % shape_point_count; + // get the two points defining the collision edge + Vector edge_lhs = shape_get_point_transformed(shape, point_index, *transform); + Vector edge_rhs = shape_get_point_transformed(shape, next_index, *transform); + // the direction of the line + Vector normal = vnormalizedf(vperpendicularf(vsubf(edge_rhs, edge_lhs))); + + Vector overlap_point; + // the smallest escape vector on this axis + Vector escape = _internal_collision_overlap_on_axis(a, b, normal, &overlap_point); + float dot = vdotf(vinvf(normal), escape); + if(dot <= 0.0) { + return 0; + } + } + return 1; +} + +int overlap_check(PhysicsQuery query, PhysicsEntity entity) { + PhysicsQuery entity_q = { + .shape = entity.tc->get_shape(entity.data), + .transform = entity.transformable->get_transform(entity.data), + .mask = rigidbody_get_layers(entity.tc->get_rigidbody(entity.data)), + }; + return (query.mask & entity_q.mask) != 0 && _internal_overlap_check(query, entity_q) || _internal_overlap_check(entity_q, query); +} diff --git a/core/src/collision.h b/core/src/collision.h index 188e8e0..6e61ca6 100644 --- a/core/src/collision.h +++ b/core/src/collision.h @@ -5,6 +5,8 @@ #include "physics_entity.h" #include +typedef uint32_t PhysicsMask; + typedef struct Collision { PhysicsEntity other; @@ -18,7 +20,14 @@ typedef struct Collision { Vector edge_right; } Collision; +typedef struct PhysicsQuery { + Shape* shape; + Transform* transform; + PhysicsMask mask; +} PhysicsQuery; + extern Collision collision_invert(Collision src, PhysicsEntity new_other); extern int collision_check(PhysicsEntity a, PhysicsEntity b, Collision* out_a, Collision* out_b); +extern int overlap_check(PhysicsQuery query, PhysicsEntity entity); #endif // !_fencer_collision_h