diff --git a/coresdk/src/coresdk/circle_geometry.cpp b/coresdk/src/coresdk/circle_geometry.cpp index 696e18e6..77fdd3a5 100644 --- a/coresdk/src/coresdk/circle_geometry.cpp +++ b/coresdk/src/coresdk/circle_geometry.cpp @@ -192,4 +192,19 @@ namespace splashkit_lib return true; } + + bool circle_quad_intersect(const circle &c, const quad &q) + { + vector q_tris = triangles_from(q); + + for (size_t i = 0; i < q_tris.size(); i++) + { + if (circle_triangle_intersect(c, q_tris[i])) + { + return true; + } + } + + return false; + } } diff --git a/coresdk/src/coresdk/circle_geometry.h b/coresdk/src/coresdk/circle_geometry.h index 8da2bb97..215d576b 100644 --- a/coresdk/src/coresdk/circle_geometry.h +++ b/coresdk/src/coresdk/circle_geometry.h @@ -213,5 +213,13 @@ namespace splashkit_lib */ bool tangent_points(const point_2d &from_pt, const circle &c, point_2d &p1, point_2d &p2); + /** + * Detects if a circle intersects with a quad. + * + * @param c The circle to test + * @param q The quad to test + * @return True if the circle and quad intersect, false otherwise + */ + bool circle_quad_intersect(const circle &c, const quad &q); } #endif /* circle_geometry_hpp */ diff --git a/coresdk/src/coresdk/collisions.cpp b/coresdk/src/coresdk/collisions.cpp index e3969291..caba83c1 100644 --- a/coresdk/src/coresdk/collisions.cpp +++ b/coresdk/src/coresdk/collisions.cpp @@ -17,10 +17,23 @@ #include "graphics.h" #include "utils.h" +constexpr int BRACKET_ITERATIONS = 40; +constexpr double ITERATION_POWER = 1.5; + using std::function; namespace splashkit_lib { + const vector_2d _DIRECTION_TOP = vector_to(0.0, -1.0); + const vector_2d _DIRECTION_BOTTOM = vector_to(0.0, 1.0); + const vector_2d _DIRECTION_LEFT = vector_to(-1.0, 0.0); + const vector_2d _DIRECTION_RIGHT = vector_to(1.0, 0.0); + const vector_2d _DIRECTION_TOP_LEFT = unit_vector(vector_to(-1.0, -1.0)); + const vector_2d _DIRECTION_TOP_RIGHT = unit_vector(vector_to(1.0, -1.0)); + const vector_2d _DIRECTION_BOTTOM_LEFT = unit_vector(vector_to(-1.0, 1.0)); + const vector_2d _DIRECTION_BOTTOM_RIGHT = unit_vector(vector_to(1.0, 1.0)); + const vector_2d _DIRECTION_NONE = vector_to(0.0, 0.0); + //#define DEBUG_STEP // Step over pixels in the two areas based on the supplied matrix @@ -144,6 +157,502 @@ namespace splashkit_lib }); } + vector_2d _opposite_direction(const vector_2d& dir) + { + return vector_to(-dir.x, -dir.y); + } + + template + bool _test_collision(const A& a, const B& b) + { + return false; + } + + template <> + bool _test_collision(const sprite& s1, const sprite& s2) + { + return sprite_collision(s1, s2); + } + + template <> + bool _test_collision(const sprite& s, const rectangle& r) + { + return sprite_rectangle_collision(s, r); + } + + template <> + bool _test_collision(const sprite& s, const circle& c) + { + return sprite_circle_collision(s, c); + } + + template <> + bool _test_collision(const sprite& s, const triangle& t) + { + return sprite_triangle_collision(s, t); + } + + template <> + bool _test_collision(const sprite& s, const quad& q) + { + return sprite_quad_collision(s, q); + } + + template <> + bool _test_collision(const rectangle& r, const sprite& s) + { + return sprite_rectangle_collision(s, r); + } + + template <> + bool _test_collision(const rectangle& r1, const rectangle& r2) + { + return rectangles_intersect(r1, r2); + } + + template <> + bool _test_collision(const rectangle& r, const circle& c) + { + return rectangle_circle_intersect(r, c); + } + + template <> + bool _test_collision(const rectangle& r, const triangle& t) + { + return triangle_rectangle_intersect(t, r); + } + + template <> + bool _test_collision(const rectangle& r, const quad& q) + { + return quads_intersect(quad_from(r), q); + } + + template <> + bool _test_collision(const circle& c, const sprite& s) + { + return sprite_circle_collision(s, c); + } + + template <> + bool _test_collision(const circle& c, const rectangle& r) + { + return rectangle_circle_intersect(r, c); + } + + template <> + bool _test_collision(const circle& c1, const circle& c2) + { + return circles_intersect(c1, c2); + } + + template <> + bool _test_collision(const circle& c, const triangle& t) + { + return circle_triangle_intersect(c, t); + } + + template <> + bool _test_collision(const circle& c, const quad& q) + { + return circle_quad_intersect(c, q); + } + + template <> + bool _test_collision(const triangle& t, const sprite& s) + { + return sprite_triangle_collision(s, t); + } + + template <> + bool _test_collision(const triangle& t, const rectangle& r) + { + return triangle_rectangle_intersect(t, r); + } + + template <> + bool _test_collision(const triangle& t, const circle& c) + { + return circle_triangle_intersect(c, t); + } + + template <> + bool _test_collision(const triangle& t1, const triangle& t2) + { + return triangles_intersect(t1, t2); + } + + template <> + bool _test_collision(const triangle& t, const quad& q) + { + return triangle_quad_intersect(t, q); + } + + template <> + bool _test_collision(const quad& q, const sprite& s) + { + return sprite_quad_collision(s, q); + } + + template <> + bool _test_collision(const quad& q, const rectangle& r) + { + return quads_intersect(q, quad_from(r)); + } + + template <> + bool _test_collision(const quad& q, const circle& c) + { + return circle_quad_intersect(c, q); + } + + template <> + bool _test_collision(const quad& q, const triangle& t) + { + return triangle_quad_intersect(t, q); + } + + template <> + bool _test_collision(const quad& q1, const quad& q2) + { + return quads_intersect(q1, q2); + } + + template + void _move_obj_by_vector(T& obj, const vector_2d& amount) + { + return; + } + + template <> + void _move_obj_by_vector(sprite& obj, const vector_2d& amount) + { + sprite_set_x(obj, sprite_x(obj) + amount.x); + sprite_set_y(obj, sprite_y(obj) + amount.y); + } + + template <> + void _move_obj_by_vector(rectangle& obj, const vector_2d& amount) + { + obj.x += amount.x; + obj.y += amount.y; + } + + template <> + void _move_obj_by_vector(circle& obj, const vector_2d& amount) + { + obj.center.x += amount.x; + obj.center.y += amount.y; + } + + template <> + void _move_obj_by_vector(triangle& obj, const vector_2d& amount) + { + obj.points[0].x += amount.x; + obj.points[0].y += amount.y; + obj.points[1].x += amount.x; + obj.points[1].y += amount.y; + obj.points[2].x += amount.x; + obj.points[2].y += amount.y; + } + + template <> + void _move_obj_by_vector(quad& obj, const vector_2d& amount) + { + obj.points[0].x += amount.x; + obj.points[0].y += amount.y; + obj.points[1].x += amount.x; + obj.points[1].y += amount.y; + obj.points[2].x += amount.x; + obj.points[2].y += amount.y; + obj.points[3].x += amount.x; + obj.points[3].y += amount.y; + } + + template + rectangle _object_AABB(const T& obj) + { + return rectangle_from(0.0, 0.0, 0.0, 0.0); + } + + template <> + rectangle _object_AABB(const sprite& obj) + { + return sprite_collision_rectangle(obj); + } + + template <> + rectangle _object_AABB(const rectangle& obj) + { + return obj; + } + + template <> + rectangle _object_AABB(const circle& obj) + { + return rectangle_around(obj); + } + + template <> + rectangle _object_AABB(const triangle& obj) + { + return rectangle_around(obj); + } + + template <> + rectangle _object_AABB(const quad& obj) + { + return rectangle_around(obj); + } + + template + collision_test_kind _collision_kind(const T& obj) + { + return PIXEL_COLLISIONS; + } + + template<> + collision_test_kind _collision_kind(const rectangle& obj) + { + return AABB_COLLISIONS; + } + + template<> + collision_test_kind _collision_kind(const sprite& obj) + { + return sprite_collision_kind(obj); + } + + vector_2d _compare_point_collision_depth_horizontal(const point_2d& collider, const point_2d& collidee) + { + if (collider.x < collidee.x) + { + return _DIRECTION_RIGHT; + } + return _DIRECTION_LEFT; + } + + vector_2d _compare_point_collision_depth_vertical(const point_2d& collider, const point_2d& collidee) + { + if (collider.y < collidee.y) + { + return _DIRECTION_BOTTOM; + } + return _DIRECTION_TOP; + } + + vector_2d _calculate_containing_collision_direction(const rectangle& collider, const rectangle& collidee) + { + // calculate the direction of the greatest distance between the two sprites + point_2d collider_center = rectangle_center(collider); + point_2d collidee_center = rectangle_center(collidee); + double x_distance = collider_center.x - collidee_center.x; + if (x_distance < 0.0) + { + x_distance *= -1; + } + + double y_distance = collider_center.y - collidee_center.y; + if (y_distance < 0.0) + { + y_distance *= -1; + } + + if (x_distance < y_distance) + { + return _compare_point_collision_depth_horizontal(collider_center, collidee_center); + } + return _compare_point_collision_depth_vertical(collider_center, collidee_center); + } + + vector_2d _rectangle_rectangle_collision_direction(const rectangle& collider, const rectangle& collidee) + { + vector collider_lines = lines_from(collider); + line collider_top_edge = collider_lines[0]; + line collider_left_edge = collider_lines[1]; + line collider_right_edge = collider_lines[2]; + line collider_bottom_edge = collider_lines[3]; + + bool left_edge = line_intersects_rect(collider_left_edge, collidee); + bool right_edge = line_intersects_rect(collider_right_edge, collidee); + bool top_edge = line_intersects_rect(collider_top_edge, collidee); + bool bottom_edge = line_intersects_rect(collider_bottom_edge, collidee); + + if (left_edge && right_edge && top_edge && bottom_edge) // collidee is equal size of collider + { + return _calculate_containing_collision_direction(collider, collidee); + } + if ((left_edge && right_edge && top_edge) || (top_edge && !(left_edge || right_edge || bottom_edge))) + { + return _DIRECTION_TOP; + } + if ((left_edge && right_edge && bottom_edge) || (bottom_edge && !(left_edge || right_edge || top_edge))) + { + return _DIRECTION_BOTTOM; + } + if ((top_edge && bottom_edge && right_edge) || (right_edge && !(left_edge || top_edge || bottom_edge))) + { + return _DIRECTION_RIGHT; + } + if ((top_edge && bottom_edge && left_edge) || (left_edge && !(right_edge || top_edge || bottom_edge))) + { + return _DIRECTION_LEFT; + } + if (left_edge && right_edge) + { + // check if the collider is more to the left or right of the collidee + return _compare_point_collision_depth_horizontal(rectangle_center(collider), rectangle_center(collidee)); + } + if (top_edge && bottom_edge) + { + // check if the collider is more to the top or bottom of the collidee + return _compare_point_collision_depth_vertical(rectangle_center(collider), rectangle_center(collidee)); + } + if (left_edge && top_edge) + { + return _DIRECTION_TOP_LEFT; + } + if (left_edge && bottom_edge) + { + return _DIRECTION_BOTTOM_LEFT; + } + if (right_edge && top_edge) + { + return _DIRECTION_TOP_RIGHT; + } + if (right_edge && bottom_edge) + { + return _DIRECTION_BOTTOM_RIGHT; + } + + // collider contains collidee or collidee contains collider + return _calculate_containing_collision_direction(collider, collidee); + } + + template + void _move_object_by_direction(T& obj, const vector_2d& direction, const vector_2d& amount) + { + if (is_zero_vector(amount)) + { + return; + } + + _move_obj_by_vector(obj, vector_to(amount.x * direction.x, amount.y * direction.y)); + } + + template + void _move_object_by_direction_relative_to_size(T& obj, const vector_2d& direction, + double relative_amount = 1.0) + { + if (is_zero_vector(direction)) + { + return; + } + + if (relative_amount == 0.0) + { + return; + } + + rectangle obj_aabb = _object_AABB(obj); + + double relative_width = obj_aabb.width * relative_amount; + double relative_height = obj_aabb.height * relative_amount; + + if (direction.x == 0.0) + { + relative_width = 0.0; + } + else if (direction.y == 0.0) + { + relative_height = 0.0; + } + + _move_object_by_direction(obj, direction, vector_to(relative_width, relative_height)); + } + + /** + * Moves the object back and forth with decreasing step size for + * the given number of iterations. + */ + template + bool _bracket_obj_collision_single(bool colliding, int i, T& collider, + const vector_2d& collider_direction) + { + if (colliding) + { + _move_object_by_direction_relative_to_size(collider, _opposite_direction(collider_direction), + 1.0 / pow(ITERATION_POWER, static_cast(i))); + } + else if (i == 1) // no collision in the first iteration + { + return false; + } + else + { + _move_object_by_direction_relative_to_size(collider, collider_direction, + 1.0 / pow(ITERATION_POWER, static_cast(i))); + } + return true; + } + + template + void _bracket_obj_obj_collision(A& collider, const B& collidee, const vector_2d& collider_direction, + int iterations) + { + for (int i = 1; i <= iterations; i++) + { + if (!_bracket_obj_collision_single(_test_collision(collider, collidee), i, collider, + collider_direction)) + { + return; + } + } + } + + template + vector_2d _calculate_object_collision_direction(const A& collider, const B& collidee) + { + if (!_test_collision(collider, collidee)) + { + return vector_to(0.0, 0.0); + } + + return _rectangle_rectangle_collision_direction(_object_AABB(collider), _object_AABB(collidee)); + } + + template + void _resolve_object_AABB_collision(T& collider, const rectangle& collidee_rect, const vector_2d& direction) + { + // get the intersection rectangle + rectangle inter = intersection(_object_AABB(collider), collidee_rect); + vector_2d amount = vector_to(inter.width, inter.height); + + _move_object_by_direction(collider, direction, amount); + } + + template + bool _resolve_object_collision(A& collider, const B& collidee, const vector_2d& direction) + { + if (is_zero_vector(direction) || !_test_collision(collider, collidee)) + { + return false; + } + + vector_2d unit_dir = unit_vector(direction); + + if (_collision_kind(collider) == AABB_COLLISIONS && _collision_kind(collidee) == AABB_COLLISIONS) + { + _resolve_object_AABB_collision(collider, _object_AABB(collidee), unit_dir); + } + else // one or both of the sprites are using pixel collision + { + _bracket_obj_obj_collision(collider, collidee, unit_dir, BRACKET_ITERATIONS); + } + + return true; + } + bool bitmap_point_collision(bitmap bmp, int cell, const matrix_2d& translation, const point_2d& pt ) { if (INVALID_PTR(bmp, BITMAP_PTR)) @@ -274,6 +783,85 @@ namespace splashkit_lib return bitmap_circle_collision(bmp, cell, translation_matrix(x, y), circ); } + bool bitmap_triangle_collision(bitmap bmp, int cell, const matrix_2d &translation, const triangle &tri) + { + if (INVALID_PTR(bmp, BITMAP_PTR)) + { + return false; + } + + quad q1 = quad_from(bitmap_cell_rectangle(bmp), translation); + rectangle rect = rectangle_around(tri); + + if (! triangle_quad_intersect(tri, q1)) + { + return false; + } + + return _step_through_pixels(rect.width, rect.height, translation_matrix(rect.x, rect.y), bmp->cell_w, bmp->cell_h, translation, [&] (int ax, int ay, int bx, int by) + { + return pixel_drawn_at_point(bmp, cell, bx, by) && point_in_triangle(point_at(rect.x + ax, rect.y + ay), tri); + }); + } + + bool bitmap_triangle_collision(bitmap bmp, int cell, const point_2d& pt, const triangle &tri) + { + return bitmap_triangle_collision(bmp, cell, translation_matrix(pt), tri); + } + + bool bitmap_triangle_collision(bitmap bmp, int cell, double x, double y, const triangle &tri) + { + return bitmap_triangle_collision(bmp, cell, translation_matrix(x, y), tri); + } + + bool bitmap_triangle_collision(bitmap bmp, double x, double y, const triangle &tri) + { + return bitmap_triangle_collision(bmp, 0, translation_matrix(x, y), tri); + } + + bool bitmap_triangle_collision(bitmap bmp, const point_2d& pt, const triangle &tri) + { + return bitmap_triangle_collision(bmp, 0, translation_matrix(pt), tri); + } + + bool bitmap_quad_collision(bitmap bmp, int cell, const matrix_2d &translation, const quad &q) + { + if (INVALID_PTR(bmp, BITMAP_PTR)) + { + return false; + } + + quad q1 = quad_from(bitmap_cell_rectangle(bmp), translation); + rectangle rect = rectangle_around(q); + + if ( not quads_intersect(q1, q) ) return false; + + return _step_through_pixels(rect.width, rect.height, translation_matrix(rect.x, rect.y), bmp->cell_w, bmp->cell_h, translation, [&] (int ax, int ay, int bx, int by) + { + return pixel_drawn_at_point(bmp, cell, bx, by) && point_in_quad(point_at(rect.x + ax, rect.y + ay), q); + }); + } + + bool bitmap_quad_collision(bitmap bmp, int cell, const point_2d& pt, const quad &q) + { + return bitmap_quad_collision(bmp, cell, translation_matrix(pt), q); + } + + bool bitmap_quad_collision(bitmap bmp, int cell, double x, double y, const quad &q) + { + return bitmap_quad_collision(bmp, cell, translation_matrix(x, y), q); + } + + bool bitmap_quad_collision(bitmap bmp, double x, double y, const quad &q) + { + return bitmap_quad_collision(bmp, 0, translation_matrix(x, y), q); + } + + bool bitmap_quad_collision(bitmap bmp, const point_2d& pt, const quad &q) + { + return bitmap_quad_collision(bmp, 0, translation_matrix(pt), q); + } + bool sprite_bitmap_collision(sprite s, bitmap bmp, int cell, double x, double y) { if (!rectangles_intersect(sprite_collision_rectangle(s), bitmap_cell_rectangle(bmp, point_at(x, y)))) @@ -329,6 +917,36 @@ namespace splashkit_lib return bitmap_rectangle_collision(sprite_collision_bitmap(s), sprite_current_cell(s), sprite_location_matrix(s), rect); } + + bool sprite_circle_collision(sprite s, const circle &c) + { + if (!circles_intersect(sprite_collision_circle(s), c)) + { + return false; + } + + return bitmap_circle_collision(sprite_collision_bitmap(s), sprite_current_cell(s), sprite_location_matrix(s), c); + } + + bool sprite_triangle_collision(sprite s, const triangle &t) + { + if (!triangle_rectangle_intersect(t, sprite_collision_rectangle(s))) + { + return false; + } + + return bitmap_triangle_collision(sprite_collision_bitmap(s), sprite_current_cell(s), sprite_location_matrix(s), t); + } + + bool sprite_quad_collision(sprite s, const quad &q) + { + if (!rectangles_intersect(sprite_collision_rectangle(s), rectangle_around(q))) + { + return false; + } + + return bitmap_quad_collision(sprite_collision_bitmap(s), sprite_current_cell(s), sprite_location_matrix(s), q); + } bool sprite_collision(sprite s1, sprite s2) { @@ -386,4 +1004,253 @@ namespace splashkit_lib return bitmap_collision(bmp1, 0, translation_matrix(x1, y1), bmp2, 0, translation_matrix(x2, y2)); } + vector_2d calculate_collision_direction(const sprite collider, const sprite collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const sprite collider, const rectangle& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const sprite collider, const circle& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const sprite collider, const triangle& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const sprite collider, const quad& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const rectangle& collider, const sprite collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const rectangle& collider, const rectangle& collidee) + { + return _rectangle_rectangle_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const rectangle& collider, const circle& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const rectangle& collider, const triangle& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const rectangle& collider, const quad& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const circle& collider, const sprite collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const circle& collider, const rectangle& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const circle& collider, const circle& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const circle& collider, const triangle& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const circle& collider, const quad& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const triangle& collider, const sprite collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const triangle& collider, const rectangle& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const triangle& collider, const circle& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const triangle& collider, const triangle& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const triangle& collider, const quad& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const quad& collider, const sprite collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const quad& collider, const rectangle& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const quad& collider, const circle& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const quad& collider, const triangle& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + vector_2d calculate_collision_direction(const quad& collider, const quad& collidee) + { + return _calculate_object_collision_direction(collider, collidee); + } + + bool resolve_collision(sprite collider, const sprite collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(sprite collider, const rectangle& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(sprite collider, const circle& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(sprite collider, const triangle& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(sprite collider, const quad& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(rectangle& collider, const sprite collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(rectangle& collider, const rectangle& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(rectangle& collider, const circle& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(rectangle& collider, const triangle& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(rectangle& collider, const quad& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(circle& collider, const sprite collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(circle& collider, const rectangle& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(circle& collider, const circle& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(circle& collider, const triangle& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(circle& collider, const quad& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(triangle& collider, const sprite collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(triangle& collider, const rectangle& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(triangle& collider, const circle& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(triangle& collider, const triangle& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(triangle& collider, const quad& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(quad& collider, const sprite collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(quad& collider, const rectangle& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(quad& collider, const circle& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(quad& collider, const triangle& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } + + bool resolve_collision(quad& collider, const quad& collidee, const vector_2d& direction) + { + return _resolve_object_collision(collider, collidee, direction); + } } diff --git a/coresdk/src/coresdk/collisions.h b/coresdk/src/coresdk/collisions.h index 2c002c84..7f080e03 100644 --- a/coresdk/src/coresdk/collisions.h +++ b/coresdk/src/coresdk/collisions.h @@ -296,6 +296,176 @@ namespace splashkit_lib * @attribute method circle_collision */ bool bitmap_circle_collision(bitmap bmp, const point_2d& pt, const circle& circ); + + /** + * Tests if a bitmap cell drawn using a passed in translation, will + * intersect with a triangle. You can use this to detect collisions between + * bitmaps and triangles. + * + * @param bmp The bitmap to test + * @param cell The cell of the bitmap to check + * @param translation The matrix used to transfrom the bitmap when drawing + * @param tri The triangle to test + * @return True if a drawn pixel in the cell of the bitmap will + * intersect with `tri` when drawn. + * + * @attribute suffix for_cell_with_translation + * + * @attribute class bitmap + * @attribute method triangle_collision + */ + bool bitmap_triangle_collision(bitmap bmp, int cell, const matrix_2d &translation, const triangle &tri); + + /** + * Tests if a bitmap cell drawn at `pt` would intersect with a triangle. + * + * @param bmp The bitmap to test + * @param cell The cell of the bitmap to check + * @param pt The location where the bitmap is drawn + * @param tri The triangle to test + * @return True if a drawn pixel in the cell of the bitmap will + * intersect with `tri` when drawn. + * + * @attribute suffix for_cell_at_point + * + * @attribute class bitmap + * @attribute method triangle_collision + */ + bool bitmap_triangle_collision(bitmap bmp, int cell, const point_2d& pt, const triangle &tri); + + /** + * Tests if a bitmap cell drawn at `x`, `y` would intersect with a triangle. + * + * @param bmp The bitmap to test + * @param cell The cell of the bitmap to check + * @param x The x location where the bitmap is drawn + * @param y The y location where the bitmap is drawn + * @param tri The triangle to test + * @return True if a drawn pixel in the bitmap will + * intersect with `tri` when drawn. + * + * @attribute suffix for_cell + * + * @attribute class bitmap + * @attribute method triangle_collision + */ + bool bitmap_triangle_collision(bitmap bmp, int cell, double x, double y, const triangle &tri); + + /** + * Tests if a bitmap drawn at `x`, `y` would intersect with a triangle. + * + * @param bmp The bitmap to test + * @param x The x location where the bitmap is drawn + * @param y The y location where the bitmap is drawn + * @param tri The triangle to test + * @return True if a drawn pixel in the bitmap will + * intersect with `tri` when drawn. + * + * @attribute class bitmap + * @attribute method triangle_collision + */ + bool bitmap_triangle_collision(bitmap bmp, double x, double y, const triangle &tri); + + /** + * Tests if a bitmap drawn at `pt` would intersect with a triangle. + * + * @param bmp The bitmap to test + * @param pt The location where the bitmap is drawn + * @param tri The triangle to test + * @return True if a drawn pixel in the cell of the bitmap will + * intersect with `tri` when drawn. + * + * @attribute suffix at_point + * + * @attribute class bitmap + * @attribute method triangle_collision + */ + bool bitmap_triangle_collision(bitmap bmp, const point_2d& pt, const triangle &tri); + + /** + * Tests if a bitmap cell drawn using a passed in translation, will + * intersect with a quad. You can use this to detect collisions between + * bitmaps and quads. + * + * @param bmp The bitmap to test + * @param cell The cell of the bitmap to check + * @param translation The matrix used to transfrom the bitmap when drawing + * @param q The quad to test + * @return True if a drawn pixel in the cell of the bitmap will + * intersect with `q` when drawn. + * + * @attribute suffix for_cell_with_translation + * + * @attribute class bitmap + * @attribute method quad_collision + */ + bool bitmap_quad_collision(bitmap bmp, int cell, const matrix_2d &translation, const quad &q); + + /** + * Tests if a bitmap cell drawn at `pt` would intersect with a quad. + * + * @param bmp The bitmap to test + * @param cell The cell of the bitmap to check + * @param pt The location where the bitmap is drawn + * @param q The quad to test + * @return True if a drawn pixel in the cell of the bitmap will + * intersect with `q` when drawn. + * + * @attribute suffix for_cell_at_point + * + * @attribute class bitmap + * @attribute method quad_collision + */ + bool bitmap_quad_collision(bitmap bmp, int cell, const point_2d& pt, const quad &q); + + /** + * Tests if a bitmap cell drawn at `x`, `y` would intersect with a quad. + * + * @param bmp The bitmap to test + * @param cell The cell of the bitmap to check + * @param x The x location where the bitmap is drawn + * @param y The y location where the bitmap is drawn + * @param q The quad to test + * @return True if a drawn pixel in the bitmap will + * intersect with `q` when drawn. + * + * @attribute suffix for_cell + * + * @attribute class bitmap + * @attribute method quad_collision + */ + bool bitmap_quad_collision(bitmap bmp, int cell, double x, double y, const quad &q); + + /** + * Tests if a bitmap drawn at `x`, `y` would intersect with a quad. + * + * @param bmp The bitmap to test + * @param x The x location where the bitmap is drawn + * @param y The y location where the bitmap is drawn + * @param q The quad to test + * @return True if a drawn pixel in the bitmap will + * intersect with `q` when drawn. + * + * @attribute class bitmap + * @attribute method quad_collision + */ + bool bitmap_quad_collision(bitmap bmp, double x, double y, const quad &q); + + /** + * Tests if a bitmap drawn at `pt` would intersect with a quad. + * + * @param bmp The bitmap to test + * @param pt The location where the bitmap is drawn + * @param q The quad to test + * @return True if a drawn pixel in the cell of the bitmap will + * intersect with `q` when drawn. + * + * @attribute suffix at_point + * + * @attribute class bitmap + * @attribute method quad_collision + */ + bool bitmap_quad_collision(bitmap bmp, const point_2d& pt, const quad &q); /** * Tests if a sprite will collide with a bitmap drawn at the indicated @@ -374,6 +544,42 @@ namespace splashkit_lib */ bool sprite_rectangle_collision(sprite s, const rectangle& rect); + /** + * Tests if a sprite is drawn within an given area (circle). + * + * @param s The sprite to test + * @param c The circle to check + * @return True if the sprite it drawn in the circle area + * + * @attribute class sprite + * @attribute method circle_collision + */ + bool sprite_circle_collision(sprite s, const circle &c); + + /** + * Tests if a sprite is drawn within an given area (triangle). + * + * @param s The sprite to test + * @param t The triangle to check + * @return True if the sprite it drawn in the triangle area + * + * @attribute class sprite + * @attribute method triangle_collision + */ + bool sprite_triangle_collision(sprite s, const triangle &t); + + /** + * Tests if a sprite is drawn within an given area (quad). + * + * @param s The sprite to test + * @param q The quad to check + * @return True if the sprite it drawn in the quad area + * + * @attribute class sprite + * @attribute method quad_collision + */ + bool sprite_quad_collision(sprite s, const quad &q); + /** * Tests if two given sprites `s1` and `s2` are collided * @param s1 the first `sprite` to test @@ -476,5 +682,880 @@ namespace splashkit_lib */ bool bitmap_collision(bitmap bmp1, double x1, double y1, bitmap bmp2, double x2, double y2); + /** + * Returns the direction of the collision between two sprites + * relative to the collider sprite. If the sprites are not colliding, + * this function will return a zero vector. + * + * @param collider The sprite that is colliding + * @param collidee The sprite that is being collided with + * @return The direction of the collision relative to the collider sprite, + * expressed as a unit vector. If the sprites are not colliding, + * this function will return a zero vector. + * + * @attribute class sprite + * @attribute suffix between_sprites + */ + vector_2d calculate_collision_direction(const sprite collider, const sprite collidee); + + /** + * Returns the direction of the collision between a sprite + * and a rectangle relative to the sprite. If the sprite and + * rectangle are not colliding, this function will return a zero vector. + * + * @param collider The sprite that is colliding + * @param collidee The rectangle that is being collided with + * @return The direction of the collision relative to the sprite, + * expressed as a unit vector. If the sprite and rectangle are not colliding, + * this function will return a zero vector. + * + * @attribute class sprite + * @attribute suffix between_sprite_and_rectangle + */ + vector_2d calculate_collision_direction(const sprite collider, const rectangle& collidee); + + /** + * Returns the direction of the collision between a sprite + * and a circle relative to the sprite. If the sprite and + * circle are not colliding, this function will return a zero vector. + * + * @param collider The sprite that is colliding + * @param collidee The circle that is being collided with + * @return The direction of the collision relative to the sprite, + * expressed as a unit vector. If the sprite and circle are not colliding, + * this function will return a zero vector. + * + * @attribute class sprite + * @attribute suffix between_sprite_and_circle + */ + vector_2d calculate_collision_direction(const sprite collider, const circle& collidee); + + /** + * Returns the direction of the collision between a sprite + * and a triangle relative to the sprite. If the sprite and + * triangle are not colliding, this function will return a zero vector. + * + * @param collider The sprite that is colliding + * @param collidee The triangle that is being collided with + * @return The direction of the collision relative to the sprite, + * expressed as a unit vector. If the sprite and triangle are not colliding, + * this function will return a zero vector. + * + * @attribute class sprite + * @attribute suffix between_sprite_and_triangle + */ + vector_2d calculate_collision_direction(const sprite collider, const triangle& collidee); + + /** + * Returns the direction of the collision between a sprite + * and a quad relative to the sprite. If the sprite and + * quad are not colliding, this function will return a zero vector. + * + * @param collider The sprite that is colliding + * @param collidee The quad that is being collided with + * @return The direction of the collision relative to the sprite, + * expressed as a unit vector. If the sprite and quad are not colliding, + * this function will return a zero vector. + * + * @attribute class sprite + * @attribute suffix between_sprite_and_quad + */ + vector_2d calculate_collision_direction(const sprite collider, const quad& collidee); + + /** + * Returns the direction of the collision between a rectangle + * and a sprite relative to the rectangle. If the rectangle and + * sprite are not colliding, this function will return a zero vector. + * + * @param collider The rectangle that is colliding + * @param collidee The sprite that is being collided with + * @return The direction of the collision relative to the rectangle, + * expressed as a unit vector. If the rectangle and sprite are not colliding, + * this function will return a zero vector. + * + * @attribute class rectangle + * @attribute suffix between_rectangle_and_sprite + */ + vector_2d calculate_collision_direction(const rectangle& collider, const sprite collidee); + + /** + * Returns the direction of the collision between a collider rectangle + * and a collidee rectangle relative to the collider rectangle. If the rectangles are not + * colliding, this function will return a zero vector. + * + * @param collider The rectangle that is colliding + * @param collidee The rectangle that is being collided with + * @return The direction of the collision relative to the collider rectangle, + * expressed as a unit vector. If the rectangles are not colliding, this function + * will return a zero vector. + * + * @attribute class rectangle + * @attribute suffix between_rectangles + */ + vector_2d calculate_collision_direction(const rectangle& collider, const rectangle& collidee); + + /** + * Returns the direction of the collision between a rectangle + * and a circle relative to the rectangle. If the rectangle and + * sprite are not colliding, this function will return a zero vector. + * + * @param collider The rectangle that is colliding + * @param collidee The circle that is being collided with + * @return The direction of the collision relative to the rectangle, + * expressed as a unit vector. If the rectangle and circle are not colliding, + * this function will return a zero vector. + * + * @attribute class rectangle + * @attribute suffix between_rectangle_and_circle + */ + vector_2d calculate_collision_direction(const rectangle& collider, const circle& collidee); + + /** + * Returns the direction of the collision between a rectangle + * and a triangle relative to the rectangle. If the rectangle and + * sprite are not colliding, this function will return a zero vector. + * + * @param collider The rectangle that is colliding + * @param collidee The triangle that is being collided with + * @return The direction of the collision relative to the rectangle, + * expressed as a unit vector. If the rectangle and triangle are not colliding, + * this function will return a zero vector. + * + * @attribute class rectangle + * @attribute suffix between_rectangle_and_triangle + */ + vector_2d calculate_collision_direction(const rectangle& collider, const triangle& collidee); + + /** + * Returns the direction of the collision between a rectangle + * and a quad relative to the rectangle. If the rectangle and + * sprite are not colliding, this function will return a zero vector. + * + * @param collider The rectangle that is colliding + * @param collidee The quad that is being collided with + * @return The direction of the collision relative to the rectangle, + * expressed as a unit vector. If the rectangle and quad are not colliding, + * this function will return a zero vector. + * + * @attribute class rectangle + * @attribute suffix between_rectangle_and_quad + */ + vector_2d calculate_collision_direction(const rectangle& collider, const quad& collidee); + + /** + * Returns the direction of the collision between a circle + * and a sprite relative to the circle. If the circle and + * sprite are not colliding, this function will return a zero vector. + * + * @param collider The circle that is colliding + * @param collidee The sprite that is being collided with + * @return The direction of the collision relative to the circle, + * expressed as a unit vector. If the circle and sprite are not colliding, + * this function will return a zero vector. + * + * @attribute class circle + * @attribute suffix between_circle_and_sprite + */ + vector_2d calculate_collision_direction(const circle& collider, const sprite collidee); + + /** + * Returns the direction of the collision between a circle + * and a rectangle relative to the circle. If the circle and + * rectangle are not colliding, this function will return a zero vector. + * + * @param collider The circle that is colliding + * @param collidee The rectangle that is being collided with + * @return The direction of the collision relative to the circle, + * expressed as a unit vector. If the circle and rectangle are not colliding, + * this function will return a zero vector. + * + * @attribute class circle + * @attribute suffix between_circle_and_rectangle + */ + vector_2d calculate_collision_direction(const circle& collider, const rectangle& collidee); + + /** + * Returns the direction of the collision between a collider circle + * and a collidee circle relative to the collider circle. If the circles are not + * colliding, this function will return a zero vector. + * + * @param collider The circle that is colliding + * @param collidee The circle that is being collided with + * @return The direction of the collision relative to the collider circle, + * expressed as a unit vector. If the circles are not colliding, this function + * will return a zero vector. + * + * @attribute class circle + * @attribute suffix between_circles + */ + vector_2d calculate_collision_direction(const circle& collider, const circle& collidee); + + /** + * Returns the direction of the collision between a circle + * and a triangle relative to the circle. If the circle and + * triangle are not colliding, this function will return a zero vector. + * + * @param collider The circle that is colliding + * @param collidee The triangle that is being collided with + * @return The direction of the collision relative to the circle, + * expressed as a unit vector. If the circle and triangle are not colliding, + * this function will return a zero vector. + * + * @attribute class circle + * @attribute suffix between_circle_and_triangle + */ + vector_2d calculate_collision_direction(const circle& collider, const triangle& collidee); + + /** + * Returns the direction of the collision between a circle + * and a quad relative to the circle. If the circle and + * quad are not colliding, this function will return a zero vector. + * + * @param collider The circle that is colliding + * @param collidee The quad that is being collided with + * @return The direction of the collision relative to the circle, + * expressed as a unit vector. If the circle and quad are not colliding, + * this function will return a zero vector. + * + * @attribute class circle + * @attribute suffix between_circle_and_quad + */ + vector_2d calculate_collision_direction(const circle& collider, const quad& collidee); + + /** + * Returns the direction of the collision between a triangle + * and a sprite relative to the triangle. If the triangle and + * sprite are not colliding, this function will return a zero vector. + * + * @param collider The triangle that is colliding + * @param collidee The sprite that is being collided with + * @return The direction of the collision relative to the triangle, + * expressed as a unit vector. If the triangle and sprite are not colliding, + * this function will return a zero vector. + * + * @attribute class triangle + * @attribute suffix between_triangle_and_sprite + */ + vector_2d calculate_collision_direction(const triangle& collider, const sprite collidee); + + /** + * Returns the direction of the collision between a triangle + * and a rectangle relative to the triangle. If the triangle and + * rectangle are not colliding, this function will return a zero vector. + * + * @param collider The triangle that is colliding + * @param collidee The rectangle that is being collided with + * @return The direction of the collision relative to the triangle, + * expressed as a unit vector. If the triangle and rectangle are not colliding, + * this function will return a zero vector. + * + * @attribute class triangle + * @attribute suffix between_triangle_and_rectangle + */ + vector_2d calculate_collision_direction(const triangle& collider, const rectangle& collidee); + + /** + * Returns the direction of the collision between a triangle + * and a circle relative to the triangle. If the triangle and + * circle are not colliding, this function will return a zero vector. + * + * @param collider The triangle that is colliding + * @param collidee The circle that is being collided with + * @return The direction of the collision relative to the triangle, + * expressed as a unit vector. If the triangle and circle are not colliding, + * this function will return a zero vector. + * + * @attribute class triangle + * @attribute suffix between_triangle_and_circle + */ + vector_2d calculate_collision_direction(const triangle& collider, const circle& collidee); + + /** + * Returns the direction of the collision between a collider triangle + * and a collidee triangle relative to the collider triangle. If the triangles are not + * colliding, this function will return a zero vector. + * + * @param collider The triangle that is colliding + * @param collidee The triangle that is being collided with + * @return The direction of the collision relative to the collider triangle, + * expressed as a unit vector. If the triangles are not colliding, this function + * will return a zero vector. + * + * @attribute class triangle + * @attribute suffix between_triangles + */ + vector_2d calculate_collision_direction(const triangle& collider, const triangle& collidee); + + /** + * Returns the direction of the collision between a triangle + * and a quad relative to the triangle. If the triangle and + * quad are not colliding, this function will return a zero vector. + * + * @param collider The triangle that is colliding + * @param collidee The quad that is being collided with + * @return The direction of the collision relative to the triangle, + * expressed as a unit vector. If the triangle and quad are not colliding, + * this function will return a zero vector. + * + * @attribute class triangle + * @attribute suffix between_triangle_and_quad + */ + vector_2d calculate_collision_direction(const triangle& collider, const quad& collidee); + + /** + * Returns the direction of the collision between a quad + * and a sprite relative to the quad. If the quad and + * sprite are not colliding, this function will return a zero vector. + * + * @param collider The quad that is colliding + * @param collidee The sprite that is being collided with + * @return The direction of the collision relative to the quad, + * expressed as a unit vector. If the quad and sprite are not colliding, + * this function will return a zero vector. + * + * @attribute class quad + * @attribute suffix between_quad_and_sprite + */ + vector_2d calculate_collision_direction(const quad& collider, const sprite collidee); + + /** + * Returns the direction of the collision between a quad + * and a rectangle relative to the quad. If the quad and + * rectangle are not colliding, this function will return a zero vector. + * + * @param collider The quad that is colliding + * @param collidee The rectangle that is being collided with + * @return The direction of the collision relative to the quad, + * expressed as a unit vector. If the quad and rectangle are not colliding, + * this function will return a zero vector. + * + * @attribute class quad + * @attribute suffix between_quad_and_rectangle + */ + vector_2d calculate_collision_direction(const quad& collider, const rectangle& collidee); + + /** + * Returns the direction of the collision between a quad + * and a circle relative to the quad. If the quad and + * circle are not colliding, this function will return a zero vector. + * + * @param collider The quad that is colliding + * @param collidee The circle that is being collided with + * @return The direction of the collision relative to the quad, + * expressed as a unit vector. If the quad and circle are not colliding, + * this function will return a zero vector. + * + * @attribute class quad + * @attribute suffix between_quad_and_circle + */ + vector_2d calculate_collision_direction(const quad& collider, const circle& collidee); + + /** + * Returns the direction of the collision between a quad + * and a triangle relative to the quad. If the quad and + * triangle are not colliding, this function will return a zero vector. + * + * @param collider The quad that is colliding + * @param collidee The triangle that is being collided with + * @return The direction of the collision relative to the quad, + * expressed as a unit vector. If the quad and triangle are not colliding, + * this function will return a zero vector. + * + * @attribute class quad + * @attribute suffix between_quad_and_triangle + */ + vector_2d calculate_collision_direction(const quad& collider, const triangle& collidee); + + /** + * Returns the direction of the collision between a collider quad + * and a collidee quad relative to the collider quad. If the quads are not + * colliding, this function will return a zero vector. + * + * @param collider The quad that is colliding + * @param collidee The quad that is being collided with + * @return The direction of the collision relative to the collider quad, + * expressed as a unit vector. If the quads are not colliding, this function + * will return a zero vector. + * + * @attribute class quad + * @attribute suffix between_quads + */ + vector_2d calculate_collision_direction(const quad& collider, const quad& collidee); + + /** + * Resolves the collision between two sprites by moving the + * collider sprite to the edge of the collidee sprite. The direction of the + * resolution is determined by the `direction` parameter. If the sprites are not + * colliding, this function will return false. + * + * @param collider The sprite which will be altered if there is a collision + * @param collidee The sprite which will not be altered + * @param direction The direction of the collision relative to the collider sprite, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the sprites are colliding and the collision was resolved, + * false if the sprites are not colliding + * + * @atrribute class sprite + * @attribute suffix between_sprites + */ + bool resolve_collision(sprite collider, const sprite collidee, const vector_2d& direction); + + /** + * Resolves the collision between a sprite and a rectangle by moving the + * sprite to the edge of the rectangle. The direction of the + * resolution is determined by the `direction` parameter. If the sprite and + * rectangle are not colliding, this function will return false. + * + * @param collider The sprite which will be altered if there is a collision + * @param collidee The rectangle which will not be altered + * @param direction The direction of the collision relative to the sprite, + * expressed as a vector. If a zero vector is passed, + * the function will not resolve the collision. + * @return True if the sprite and rectangle are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class sprite + * @attribute suffix between_sprite_and_rectangle + */ + bool resolve_collision(sprite collider, const rectangle& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a sprite and a circle by moving the + * sprite to the edge of the circle. The direction of the + * resolution is determined by the `direction` parameter. If the sprite and + * circle are not colliding, this function will return false. + * + * @param collider The sprite which will be altered if there is a collision + * @param collidee The circle which will not be altered + * @param direction The direction of the collision relative to the sprite, + * expressed as a vector. If a zero vector is passed, + * the function will not resolve the collision. + * @return True if the sprite and circle are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class sprite + * @attribute suffix between_sprite_and_circle + */ + bool resolve_collision(sprite collider, const circle& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a sprite and a triangle by moving the + * sprite to the edge of the triangle. The direction of the + * resolution is determined by the `direction` parameter. If the sprite and + * triangle are not colliding, this function will return false. + * + * @param collider The sprite which will be altered if there is a collision + * @param collidee The triangle which will not be altered + * @param direction The direction of the collision relative to the sprite, + * expressed as a vector. If a zero vector is passed, + * the function will not resolve the collision. + * @return True if the sprite and triangle are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class sprite + * @attribute suffix between_sprite_and_triangle + */ + bool resolve_collision(sprite collider, const triangle& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a sprite and a quad by moving the + * sprite to the edge of the quad. The direction of the + * resolution is determined by the `direction` parameter. If the sprite and + * quad are not colliding, this function will return false. + * + * @param collider The sprite which will be altered if there is a collision + * @param collidee The quad which will not be altered + * @param direction The direction of the collision relative to the sprite, + * expressed as a vector. If a zero vector is passed, + * the function will not resolve the collision. + * @return True if the sprite and quad are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class sprite + * @attribute suffix between_sprite_and_quad + */ + bool resolve_collision(sprite collider, const quad& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a rectangle and a sprite by moving the + * rectangle to the edge of the sprite. The direction of the + * resolution is determined by the `direction` parameter. If the rectangle and + * sprite are not colliding, this function will return false. + * + * @param collider The rectangle which will be altered if there is a collision + * @param collidee The sprite which will not be altered + * @param direction The direction of the collision relative to the rectangle, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the rectangle and sprite are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class rectangle + * @attribute suffix between_rectangle_and_sprite + */ + bool resolve_collision(rectangle& collider, const sprite collidee, const vector_2d& direction); + + /** + * Resolves the collision between two rectangles by moving the + * collider rectangle to the edge of the collidee rectangle. The direction of the + * resolution is determined by the `direction` parameter. If the rectangles are not + * colliding, this function will return false. + * + * @param collider The rectangle which will be altered if there is a collision + * @param collidee The rectangle which will not be altered + * @param direction The direction of the collision relative to the collider rectangle, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the rectangles are colliding and the collision was resolved, + * false if the rectangles are not colliding + * + * @atrribute class rectangle + * @attribute suffix between_rectangles + */ + bool resolve_collision(rectangle& collider, const rectangle& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a rectangle and a circle by moving the + * rectangle to the edge of the circle. The direction of the + * resolution is determined by the `direction` parameter. If the rectangle and + * circle are not colliding, this function will return false. + * + * @param collider The rectangle which will be altered if there is a collision + * @param collidee The circle which will not be altered + * @param direction The direction of the collision relative to the rectangle, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the rectangle and circle are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class rectangle + * @attribute suffix between_rectangle_and_circle + */ + bool resolve_collision(rectangle& collider, const circle& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a rectangle and a triangle by moving the + * rectangle to the edge of the triangle. The direction of the + * resolution is determined by the `direction` parameter. If the rectangle and + * triangle are not colliding, this function will return false. + * + * @param collider The rectangle which will be altered if there is a collision + * @param collidee The triangle which will not be altered + * @param direction The direction of the collision relative to the rectangle, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the rectangle and triangle are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class rectangle + * @attribute suffix between_rectangle_and_triangle + */ + bool resolve_collision(rectangle& collider, const triangle& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a rectangle and a quad by moving the + * rectangle to the edge of the quad. The direction of the + * resolution is determined by the `direction` parameter. If the rectangle and + * quad are not colliding, this function will return false. + * + * @param collider The rectangle which will be altered if there is a collision + * @param collidee The quad which will not be altered + * @param direction The direction of the collision relative to the rectangle, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the rectangle and quad are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class rectangle + * @attribute suffix between_rectangle_and_quad + */ + bool resolve_collision(rectangle& collider, const quad& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a circle and a sprite by moving the + * circle to the edge of the sprite. The direction of the + * resolution is determined by the `direction` parameter. If the circle and + * sprite are not colliding, this function will return false. + * + * @param collider The circle which will be altered if there is a collision + * @param collidee The sprite which will not be altered + * @param direction The direction of the collision relative to the circle, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the circle and sprite are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class circle + * @attribute suffix between_circle_and_sprite + */ + bool resolve_collision(circle& collider, const sprite collidee, const vector_2d& direction); + + /** + * Resolves the collision between a circle and a rectangle by moving the + * circle to the edge of the rectangle. The direction of the + * resolution is determined by the `direction` parameter. If the circle and + * rectangle are not colliding, this function will return false. + * + * @param collider The circle which will be altered if there is a collision + * @param collidee The rectangle which will not be altered + * @param direction The direction of the collision relative to the circle, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the circle and rectangle are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class circle + * @attribute suffix between_circle_and_rectangle + */ + bool resolve_collision(circle& collider, const rectangle& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a collider circle and a collidee circle by moving the + * collider circle to the edge of the collidee circle. The direction of the + * resolution is determined by the `direction` parameter. If the circles are not + * colliding, this function will return false. + * + * @param collider The circle which will be altered if there is a collision + * @param collidee The circle which will not be altered + * @param direction The direction of the collision relative to the collider circle, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the circles are colliding and the collision was resolved, + * false if the circles are not colliding + * + * @atrribute class circle + * @attribute suffix between_circles + */ + bool resolve_collision(circle& collider, const circle& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a circle and a triangle by moving the + * circle to the edge of the triangle. The direction of the + * resolution is determined by the `direction` parameter. If the circle and + * triangle are not colliding, this function will return false. + * + * @param collider The circle which will be altered if there is a collision + * @param collidee The triangle which will not be altered + * @param direction The direction of the collision relative to the circle, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the circle and triangle are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class circle + * @attribute suffix between_circle_and_triangle + */ + bool resolve_collision(circle& collider, const triangle& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a circle and a quad by moving the + * circle to the edge of the quad. The direction of the + * resolution is determined by the `direction` parameter. If the circle and + * quad are not colliding, this function will return false. + * + * @param collider The circle which will be altered if there is a collision + * @param collidee The quad which will not be altered + * @param direction The direction of the collision relative to the circle, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the circle and quad are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class circle + * @attribute suffix between_circle_and_quad + */ + bool resolve_collision(circle& collider, const quad& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a triangle and a sprite by moving the + * triangle to the edge of the sprite. The direction of the + * resolution is determined by the `direction` parameter. If the triangle and + * sprite are not colliding, this function will return false. + * + * @param collider The triangle which will be altered if there is a collision + * @param collidee The sprite which will not be altered + * @param direction The direction of the collision relative to the triangle, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the triangle and sprite are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class triangle + * @attribute suffix between_triangle_and_sprite + */ + bool resolve_collision(triangle& collider, const sprite collidee, const vector_2d& direction); + + /** + * Resolves the collision between a triangle and a rectangle by moving the + * triangle to the edge of the rectangle. The direction of the + * resolution is determined by the `direction` parameter. If the triangle and + * rectangle are not colliding, this function will return false. + * + * @param collider The triangle which will be altered if there is a collision + * @param collidee The rectangle which will not be altered + * @param direction The direction of the collision relative to the triangle, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the triangle and rectangle are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class triangle + * @attribute suffix between_triangle_and_rectangle + */ + bool resolve_collision(triangle& collider, const rectangle& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a triangle and a circle by moving the + * triangle to the edge of the circle. The direction of the + * resolution is determined by the `direction` parameter. If the triangle and + * circle are not colliding, this function will return false. + * + * @param collider The triangle which will be altered if there is a collision + * @param collidee The circle which will not be altered + * @param direction The direction of the collision relative to the triangle, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the triangle and circle are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class triangle + * @attribute suffix between_triangle_and_circle + */ + bool resolve_collision(triangle& collider, const circle& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a collider triangle and a collidee triangle by moving the + * collider triangle to the edge of the collidee triangle. The direction of the + * resolution is determined by the `direction` parameter. If the triangles are not + * colliding, this function will return false. + * + * @param collider The triangle which will be altered if there is a collision + * @param collidee The triangle which will not be altered + * @param direction The direction of the collision relative to the collider triangle, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the triangles are colliding and the collision was resolved, + * false if the triangles are not colliding + * + * @atrribute class triangle + * @attribute suffix between_triangles + */ + bool resolve_collision(triangle& collider, const triangle& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a triangle and a quad by moving the + * triangle to the edge of the quad. The direction of the + * resolution is determined by the `direction` parameter. If the triangle and + * quad are not colliding, this function will return false. + * + * @param collider The triangle which will be altered if there is a collision + * @param collidee The quad which will not be altered + * @param direction The direction of the collision relative to the triangle, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the triangle and quad are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class triangle + * @attribute suffix between_triangle_and_quad + */ + bool resolve_collision(triangle& collider, const quad& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a quad and a sprite by moving the + * quad to the edge of the sprite. The direction of the + * resolution is determined by the `direction` parameter. If the quad and + * sprite are not colliding, this function will return false. + * + * @param collider The quad which will be altered if there is a collision + * @param collidee The sprite which will not be altered + * @param direction The direction of the collision relative to the quad, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the quad and sprite are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class quad + * @attribute suffix between_quad_and_sprite + */ + bool resolve_collision(quad& collider, const sprite collidee, const vector_2d& direction); + + /** + * Resolves the collision between a quad and a rectangle by moving the + * quad to the edge of the rectangle. The direction of the + * resolution is determined by the `direction` parameter. If the quad and + * rectangle are not colliding, this function will return false. + * + * @param collider The quad which will be altered if there is a collision + * @param collidee The rectangle which will not be altered + * @param direction The direction of the collision relative to the quad, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the quad and rectangle are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class quad + * @attribute suffix between_quad_and_rectangle + */ + bool resolve_collision(quad& collider, const rectangle& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a quad and a circle by moving the + * quad to the edge of the circle. The direction of the + * resolution is determined by the `direction` parameter. If the quad and + * circle are not colliding, this function will return false. + * + * @param collider The quad which will be altered if there is a collision + * @param collidee The circle which will not be altered + * @param direction The direction of the collision relative to the quad, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the quad and circle are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class quad + * @attribute suffix between_quad_and_circle + */ + bool resolve_collision(quad& collider, const circle& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a quad and a triangle by moving the + * quad to the edge of the triangle. The direction of the + * resolution is determined by the `direction` parameter. If the quad and + * triangle are not colliding, this function will return false. + * + * @param collider The quad which will be altered if there is a collision + * @param collidee The triangle which will not be altered + * @param direction The direction of the collision relative to the quad, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the quad and triangle are colliding and the collision + * was resolved, false if they are not colliding + * + * @atrribute class quad + * @attribute suffix between_quad_and_triangle + */ + bool resolve_collision(quad& collider, const triangle& collidee, const vector_2d& direction); + + /** + * Resolves the collision between a collider quad and a collidee quad by moving the + * collider quad to the edge of the collidee quad. The direction of the + * resolution is determined by the `direction` parameter. If the quads are not + * colliding, this function will return false. + * + * @param collider The quad which will be altered if there is a collision + * @param collidee The quad which will not be altered + * @param direction The direction of the collision relative to the collider quad, + * expressed as a vector. If a zero vector is passed, the function will + * not resolve the collision. + * @return True if the quads are colliding and the collision was resolved, + * false if the quads are not colliding + * + * @atrribute class quad + * @attribute suffix between_quads + */ + bool resolve_collision(quad& collider, const quad& collidee, const vector_2d& direction); + } #endif /* collisions_h */ diff --git a/coresdk/src/coresdk/line_geometry.cpp b/coresdk/src/coresdk/line_geometry.cpp index 6e69411c..102a4308 100644 --- a/coresdk/src/coresdk/line_geometry.cpp +++ b/coresdk/src/coresdk/line_geometry.cpp @@ -173,6 +173,12 @@ namespace splashkit_lib bool line_intersects_rect(const line &l, const rectangle &rect) { + // if the line is completely within the rectangle, then it intersects + if (point_in_rectangle(l.start_point, rect) && point_in_rectangle(l.end_point, rect)) + { + return true; + } + return line_intersects_lines(l, lines_from(rect)); } diff --git a/coresdk/src/coresdk/rectangle_geometry.cpp b/coresdk/src/coresdk/rectangle_geometry.cpp index 6514fd0b..54c77656 100644 --- a/coresdk/src/coresdk/rectangle_geometry.cpp +++ b/coresdk/src/coresdk/rectangle_geometry.cpp @@ -223,4 +223,15 @@ namespace splashkit_lib return result; } + + bool rectangle_circle_intersect(const rectangle &rect, const circle &c) + { + if (point_in_rectangle(c.center, rect)) + { + return true; + } + + point_2d closest = closest_point_on_rect_from_circle(c, rect); + return point_in_circle(closest, c); + } } diff --git a/coresdk/src/coresdk/rectangle_geometry.h b/coresdk/src/coresdk/rectangle_geometry.h index 50cd23f0..81738c11 100644 --- a/coresdk/src/coresdk/rectangle_geometry.h +++ b/coresdk/src/coresdk/rectangle_geometry.h @@ -178,5 +178,14 @@ namespace splashkit_lib */ rectangle inset_rectangle(const rectangle &rect, float inset_amount); + /** + * Detects if a rectangle intersects with a circle. + * + * @param rect The rectangle to test + * @param c The circle to test + * @return True if the rectangle and circle intersect, false otherwise + */ + bool rectangle_circle_intersect(const rectangle &rect, const circle &c); + } #endif /* rectangle_geometry_H */ diff --git a/coresdk/src/coresdk/triangle_geometry.cpp b/coresdk/src/coresdk/triangle_geometry.cpp index 5c635133..a0540bc2 100644 --- a/coresdk/src/coresdk/triangle_geometry.cpp +++ b/coresdk/src/coresdk/triangle_geometry.cpp @@ -102,6 +102,18 @@ namespace splashkit_lib or point_in_triangle(point_at(r, b), tri); } + bool triangle_quad_intersect(const triangle &tri, const quad &q) + { + vector q_tris = triangles_from(q); + + for (size_t i = 0; i < q_tris.size(); i++) + { + if (triangles_intersect(tri, q_tris[i])) return true; + } + + return false; + } + bool triangles_intersect(const triangle &t1, const triangle &t2) { // Test if any of the points lie within the other triangle. diff --git a/coresdk/src/coresdk/triangle_geometry.h b/coresdk/src/coresdk/triangle_geometry.h index 51abd9e1..c5c5e86c 100644 --- a/coresdk/src/coresdk/triangle_geometry.h +++ b/coresdk/src/coresdk/triangle_geometry.h @@ -46,6 +46,9 @@ namespace splashkit_lib */ bool triangle_rectangle_intersect(const triangle &tri, const rectangle &rect); + // TODO + bool triangle_quad_intersect(const triangle &tri, const quad &q); + /** * Returns true if the two triangles intersect. * diff --git a/coresdk/src/test/test_sprites.cpp b/coresdk/src/test/test_sprites.cpp index 3034d8af..2c564767 100644 --- a/coresdk/src/test/test_sprites.cpp +++ b/coresdk/src/test/test_sprites.cpp @@ -13,12 +13,152 @@ #include "input.h" #include "sprites.h" #include "window_manager.h" +#include + +constexpr int COLLISION_INDICATOR_WIDTH = 4; using namespace splashkit_lib; -void run_sprite_test() +enum class object_type +{ + SPRITE, + RECTANGLE, + CIRCLE, + TRIANGLE, + QUAD, +}; + +enum class collision_test_type +{ + MULTIPLE_DYNAMIC, + SPRITE_FIXED, + RECTANGLE_FIXED, + CIRCLE_FIXED, + TRIANGLE_FIXED, + QUAD_FIXED, +}; + +enum class sprite_perimeter_segment +{ + TOP_LEFT, + TOP_CENTER, + TOP_RIGHT, + BOTTOM_LEFT, + BOTTOM_CENTER, + BOTTOM_RIGHT, + LEFT_TOP, + LEFT_CENTER, + LEFT_BOTTOM, + RIGHT_TOP, + RIGHT_CENTER, + RIGHT_BOTTOM, +}; + +const vector_2d DIRECTION_TOP = vector_to(0.0, -1.0); +const vector_2d DIRECTION_BOTTOM = vector_to(0.0, 1.0); +const vector_2d DIRECTION_LEFT = vector_to(-1.0, 0.0); +const vector_2d DIRECTION_RIGHT = vector_to(1.0, 0.0); +const vector_2d DIRECTION_TOP_LEFT = unit_vector(vector_to(-1.0, -1.0)); +const vector_2d DIRECTION_TOP_RIGHT = unit_vector(vector_to(1.0, -1.0)); +const vector_2d DIRECTION_BOTTOM_LEFT = unit_vector(vector_to(-1.0, 1.0)); +const vector_2d DIRECTION_BOTTOM_RIGHT = unit_vector(vector_to(1.0, 1.0)); +const vector_2d DIRECTION_NONE = vector_to(0.0, 0.0); + +void draw_rect_perimeter_segment(const rectangle& r, sprite_perimeter_segment segment, color clr, int line_width) +{ + switch (segment) + { + case sprite_perimeter_segment::TOP_LEFT: + draw_line(clr, r.x, r.y, r.x + r.width / 3.0, r.y, option_line_width(line_width)); + break; + case sprite_perimeter_segment::TOP_CENTER: + draw_line(clr, r.x + r.width / 3.0, r.y, r.x + r.width * 2.0 / 3.0, r.y, option_line_width(line_width)); + break; + case sprite_perimeter_segment::TOP_RIGHT: + draw_line(clr, r.x + r.width * 2.0 / 3.0, r.y, r.x + r.width, r.y, option_line_width(line_width)); + break; + case sprite_perimeter_segment::BOTTOM_LEFT: + draw_line(clr, r.x, r.y + r.height, r.x + r.width / 3.0, r.y + r.height, option_line_width(line_width)); + break; + case sprite_perimeter_segment::BOTTOM_CENTER: + draw_line(clr, r.x + r.width / 3.0, r.y + r.height, r.x + r.width * 2.0 / 3.0, r.y + r.height, option_line_width(line_width)); + break; + case sprite_perimeter_segment::BOTTOM_RIGHT: + draw_line(clr, r.x + r.width * 2.0 / 3.0, r.y + r.height, r.x + r.width, r.y + r.height, option_line_width(line_width)); + break; + case sprite_perimeter_segment::LEFT_TOP: + draw_line(clr, r.x, r.y, r.x, r.y + r.height / 3.0, option_line_width(line_width)); + break; + case sprite_perimeter_segment::LEFT_CENTER: + draw_line(clr, r.x, r.y + r.height / 3.0, r.x, r.y + r.height * 2.0 / 3.0, option_line_width(line_width)); + break; + case sprite_perimeter_segment::LEFT_BOTTOM: + draw_line(clr, r.x, r.y + r.height * 2.0 / 3.0, r.x, r.y + r.height, option_line_width(line_width)); + break; + case sprite_perimeter_segment::RIGHT_TOP: + draw_line(clr, r.x + r.width, r.y, r.x + r.width, r.y + r.height / 3.0, option_line_width(line_width)); + break; + case sprite_perimeter_segment::RIGHT_CENTER: + draw_line(clr, r.x + r.width, r.y + r.height / 3.0, r.x + r.width, r.y + r.height * 2.0 / 3.0, option_line_width(line_width)); + break; + case sprite_perimeter_segment::RIGHT_BOTTOM: + draw_line(clr, r.x + r.width, r.y + r.height * 2.0 / 3.0, r.x + r.width, r.y + r.height, option_line_width(line_width)); + break; + }; +} + +void draw_rect_perimeter_segments(const rectangle& r, const std::vector& segments, color clr, int line_width) +{ + for (const auto& segment : segments) + { + draw_rect_perimeter_segment(r, segment, clr, line_width); + } +} + +void draw_rect_perimeter_by_collision(const rectangle& r, const vector_2d& dir, color clr, int line_width) { - sprite sprt, s2; + if (dir.x == DIRECTION_NONE.x && dir.y == DIRECTION_NONE.y) + { + return; + } + + if (dir.x == DIRECTION_TOP.x && dir.y == DIRECTION_TOP.y) + { + draw_rect_perimeter_segments(r, {sprite_perimeter_segment::TOP_LEFT, sprite_perimeter_segment::TOP_CENTER, sprite_perimeter_segment::TOP_RIGHT}, clr, line_width); + } + else if (dir.x == DIRECTION_BOTTOM.x && dir.y == DIRECTION_BOTTOM.y) + { + draw_rect_perimeter_segments(r, {sprite_perimeter_segment::BOTTOM_LEFT, sprite_perimeter_segment::BOTTOM_CENTER, sprite_perimeter_segment::BOTTOM_RIGHT}, clr, line_width); + } + else if (dir.x == DIRECTION_LEFT.x && dir.y == DIRECTION_LEFT.y) + { + draw_rect_perimeter_segments(r, {sprite_perimeter_segment::LEFT_TOP, sprite_perimeter_segment::LEFT_CENTER, sprite_perimeter_segment::LEFT_BOTTOM}, clr, line_width); + } + else if (dir.x == DIRECTION_RIGHT.x && dir.y == DIRECTION_RIGHT.y) + { + draw_rect_perimeter_segments(r, {sprite_perimeter_segment::RIGHT_TOP, sprite_perimeter_segment::RIGHT_CENTER, sprite_perimeter_segment::RIGHT_BOTTOM}, clr, line_width); + } + else if (dir.x == DIRECTION_TOP_LEFT.x && dir.y == DIRECTION_TOP_LEFT.y) + { + draw_rect_perimeter_segments(r, {sprite_perimeter_segment::TOP_LEFT, sprite_perimeter_segment::LEFT_TOP}, clr, line_width); + } + else if (dir.x == DIRECTION_TOP_RIGHT.x && dir.y == DIRECTION_TOP_RIGHT.y) + { + draw_rect_perimeter_segments(r, {sprite_perimeter_segment::TOP_RIGHT, sprite_perimeter_segment::RIGHT_TOP}, clr, line_width); + } + else if (dir.x == DIRECTION_BOTTOM_LEFT.x && dir.y == DIRECTION_BOTTOM_LEFT.y) + { + draw_rect_perimeter_segments(r, {sprite_perimeter_segment::BOTTOM_LEFT, sprite_perimeter_segment::LEFT_BOTTOM}, clr, line_width); + } + else if (dir.x == DIRECTION_BOTTOM_RIGHT.x && dir.y == DIRECTION_BOTTOM_RIGHT.y) + { + draw_rect_perimeter_segments(r, {sprite_perimeter_segment::BOTTOM_RIGHT, sprite_perimeter_segment::RIGHT_BOTTOM}, clr, line_width); + } +} + +void sprite_test() +{ + sprite sprt, s2, s3, s4; triangle tri, init_tri; triangle tri_b, init_tri_b; rectangle r; @@ -38,6 +178,17 @@ void run_sprite_test() sprite_set_x(s2, 100); sprite_set_y(s2, 100); + s3 = create_sprite(bitmap_named("rocket_sprt.png")); + sprite_set_move_from_anchor_point(s3, true); + sprite_set_x(s3, 100); + sprite_set_y(s3, 400); + + s4 = create_sprite(bitmap_named("rocket_sprt.png")); + sprite_set_move_from_anchor_point(s4, true); + sprite_set_x(s4, 400); + sprite_set_y(s4, 400); + sprite_set_collision_kind(s4, AABB_COLLISIONS); + r = rectangle_from(400, 100, 100, 50); q = quad_from(r); apply_matrix(matrix_multiply(translation_matrix(0, 50), rotation_matrix(45)), q); @@ -97,6 +248,8 @@ void run_sprite_test() draw_sprite(sprt); draw_sprite(s2); + draw_sprite(s3); + draw_sprite(s4); if (sprite_rectangle_collision(sprt, r)) { @@ -132,7 +285,22 @@ void run_sprite_test() draw_circle(COLOR_RED, sprite_collision_circle(s2)); } + if (sprite_collision(sprt, s3)) + { + vector_2d dir = calculate_collision_direction(sprt, s3); + resolve_collision(sprt, s3, dir); + draw_rect_perimeter_by_collision(sprite_collision_rectangle(sprt), dir, COLOR_RED, 4); + } + + if (sprite_collision(sprt, s4)) + { + vector_2d dir = calculate_collision_direction(sprt, s4); + resolve_collision(sprt, s4, dir); + draw_rect_perimeter_by_collision(sprite_collision_rectangle(sprt), dir, COLOR_RED, 4); + } + draw_rectangle(COLOR_GREEN, sprite_collision_rectangle(sprt)); + draw_rectangle(COLOR_RED, sprite_collision_rectangle(s4)); draw_line(COLOR_GREEN, line_from(center_point(sprt), matrix_multiply(rotation_matrix(sprite_rotation(sprt)), vector_multiply(sprite_velocity(sprt), 30.0)))); @@ -143,3 +311,975 @@ void run_sprite_test() close_all_windows(); } + +void reset_sprite(sprite s) +{ + sprite_set_x(s, 300.0); + sprite_set_y(s, 300.0); + sprite_set_rotation(s, 0.0f); + sprite_set_scale(s, 1.0f); + sprite_set_dx(s, 0.0); + sprite_set_dy(s, 0.0); + sprite_set_collision_kind(s, PIXEL_COLLISIONS); +} + +void reset_rectangle(rectangle &r) +{ + r = rectangle_from(300.0, 300.0, 150.0, 50.0); +} + +void reset_circle(circle &c) +{ + c = circle_at(300.0, 300.0, 40.0); +} + +void reset_triangle(triangle &t) +{ + t = triangle_from(300.0, 300.0, 400.0, 300.0, 350.0, 250.0); +} + +void reset_quad(quad &q) +{ + rectangle r = rectangle_from(300, 300, 100, 50); + q = quad_from(r); + apply_matrix(matrix_multiply(translation_matrix(0.0, -150.0), rotation_matrix(45.0)), q); +} + +void resolve_and_draw(void* collider, const void* collidee, object_type collider_type, + object_type collidee_type, vector_2d direction) +{ + if (is_zero_vector(direction)) + { + return; + } + + rectangle perimeter; + bool collision = false; + + switch (collider_type) + { + case object_type::SPRITE: + { + sprite s = *static_cast(collider); + perimeter = sprite_collision_rectangle(s); + + switch (collidee_type) + { + case object_type::SPRITE: + collision = resolve_collision(s, *static_cast(collidee), direction); + break; + case object_type::RECTANGLE: + collision = resolve_collision(s, *static_cast(collidee), direction); + break; + case object_type::CIRCLE: + collision = resolve_collision(s, *static_cast(collidee), direction); + break; + case object_type::TRIANGLE: + collision = resolve_collision(s, *static_cast(collidee), direction); + break; + case object_type::QUAD: + collision = resolve_collision(s, *static_cast(collidee), direction); + break; + }; + break; + } + case object_type::RECTANGLE: + { + rectangle* r = static_cast(collider); + perimeter = *r; + + switch (collidee_type) + { + case object_type::SPRITE: + collision = resolve_collision(*r, *static_cast(collidee), direction); + break; + case object_type::RECTANGLE: + collision = resolve_collision(*r, *static_cast(collidee), direction); + break; + case object_type::CIRCLE: + collision = resolve_collision(*r, *static_cast(collidee), direction); + break; + case object_type::TRIANGLE: + collision = resolve_collision(*r, *static_cast(collidee), direction); + break; + case object_type::QUAD: + collision = resolve_collision(*r, *static_cast(collidee), direction); + break; + }; + break; + } + case object_type::CIRCLE: + { + circle* c = static_cast(collider); + perimeter = rectangle_around(*c); + + switch (collidee_type) + { + case object_type::SPRITE: + collision = resolve_collision(*c, *static_cast(collidee), direction); + break; + case object_type::RECTANGLE: + collision = resolve_collision(*c, *static_cast(collidee), direction); + break; + case object_type::CIRCLE: + collision = resolve_collision(*c, *static_cast(collidee), direction); + break; + case object_type::TRIANGLE: + collision = resolve_collision(*c, *static_cast(collidee), direction); + break; + case object_type::QUAD: + collision = resolve_collision(*c, *static_cast(collidee), direction); + break; + }; + break; + } + case object_type::TRIANGLE: + { + triangle* t = static_cast(collider); + perimeter = rectangle_around(*t); + + switch (collidee_type) + { + case object_type::SPRITE: + collision = resolve_collision(*t, *static_cast(collidee), direction); + break; + case object_type::RECTANGLE: + collision = resolve_collision(*t, *static_cast(collidee), direction); + break; + case object_type::CIRCLE: + collision = resolve_collision(*t, *static_cast(collidee), direction); + break; + case object_type::TRIANGLE: + collision = resolve_collision(*t, *static_cast(collidee), direction); + break; + case object_type::QUAD: + collision = resolve_collision(*t, *static_cast(collidee), direction); + break; + }; + break; + } + case object_type::QUAD: + { + quad* q = static_cast(collider); + perimeter = rectangle_around(*q); + + switch (collidee_type) + { + case object_type::SPRITE: + collision = resolve_collision(*q, *static_cast(collidee), direction); + break; + case object_type::RECTANGLE: + collision = resolve_collision(*q, *static_cast(collidee), direction); + break; + case object_type::CIRCLE: + collision = resolve_collision(*q, *static_cast(collidee), direction); + break; + case object_type::TRIANGLE: + collision = resolve_collision(*q, *static_cast(collidee), direction); + break; + case object_type::QUAD: + collision = resolve_collision(*q, *static_cast(collidee), direction); + break; + }; + break; + } + }; + + if (collision) + { + draw_rect_perimeter_by_collision(perimeter, direction, COLOR_RED, COLLISION_INDICATOR_WIDTH); + } +} + +void multi_object_collision_resolution_test() +{ + object_type collider_type = object_type::SPRITE; + collision_test_type test_type = collision_test_type::MULTIPLE_DYNAMIC; + + sprite collider_sprt, sprt_pixel, sprt_AABB, sprt_TOP, sprt_BOTTOM, sprt_LEFT, + sprt_RIGHT, sprt_TOP_LEFT, sprt_TOP_RIGHT, sprt_BOTTOM_LEFT, sprt_BOTTOM_RIGHT; + bitmap bmp; + rectangle collider_rect, rect, rect_TOP, rect_BOTTOM, rect_LEFT, rect_RIGHT, rect_TOP_LEFT, + rect_TOP_RIGHT, rect_BOTTOM_LEFT, rect_BOTTOM_RIGHT; + circle collider_circ, circ, circ_TOP, circ_BOTTOM, circ_LEFT, circ_RIGHT, circ_TOP_LEFT, + circ_TOP_RIGHT, circ_BOTTOM_LEFT, circ_BOTTOM_RIGHT; + triangle collider_tri, tri, tri_TOP, tri_BOTTOM, tri_LEFT, tri_RIGHT, tri_TOP_LEFT, + tri_TOP_RIGHT, tri_BOTTOM_LEFT, tri_BOTTOM_RIGHT; + quad collider_quad, q, quad_TOP, quad_BOTTOM, quad_LEFT, quad_RIGHT, quad_TOP_LEFT, + quad_TOP_RIGHT, quad_BOTTOM_LEFT, quad_BOTTOM_RIGHT; + + open_window("Object Collision Resolution", 600, 600); + + hide_mouse(); + + collider_sprt = create_sprite("rocket_sprt.png"); + reset_sprite(collider_sprt); + reset_rectangle(collider_rect); + reset_circle(collider_circ); + reset_triangle(collider_tri); + reset_quad(collider_quad); + + sprt_pixel = create_sprite("rocket_sprt.png"); + sprite_set_x(sprt_pixel, 100.0); + sprite_set_y(sprt_pixel, 100.0); + sprite_set_collision_kind(sprt_pixel, PIXEL_COLLISIONS); + + sprt_AABB = create_sprite("rocket_sprt.png"); + sprite_set_x(sprt_AABB, 50.0); + sprite_set_y(sprt_AABB, 400.0); + sprite_set_collision_kind(sprt_AABB, AABB_COLLISIONS); + + sprt_TOP = create_sprite("rocket_sprt.png"); + sprite_set_x(sprt_TOP, 300.0); + sprite_set_y(sprt_TOP, 100.0); + sprite_set_collision_kind(sprt_TOP, PIXEL_COLLISIONS); + + sprt_BOTTOM = create_sprite("rocket_sprt.png"); + sprite_set_x(sprt_BOTTOM, 300.0); + sprite_set_y(sprt_BOTTOM, 500.0); + sprite_set_collision_kind(sprt_BOTTOM, PIXEL_COLLISIONS); + + sprt_LEFT = create_sprite("rocket_sprt.png"); + sprite_set_x(sprt_LEFT, 100.0); + sprite_set_y(sprt_LEFT, 300.0); + sprite_set_collision_kind(sprt_LEFT, PIXEL_COLLISIONS); + + sprt_RIGHT = create_sprite("rocket_sprt.png"); + sprite_set_x(sprt_RIGHT, 500.0); + sprite_set_y(sprt_RIGHT, 300.0); + sprite_set_collision_kind(sprt_RIGHT, PIXEL_COLLISIONS); + + sprt_TOP_LEFT = create_sprite("rocket_sprt.png"); + sprite_set_x(sprt_TOP_LEFT, 100.0); + sprite_set_y(sprt_TOP_LEFT, 100.0); + sprite_set_collision_kind(sprt_TOP_LEFT, PIXEL_COLLISIONS); + + sprt_TOP_RIGHT = create_sprite("rocket_sprt.png"); + sprite_set_x(sprt_TOP_RIGHT, 500.0); + sprite_set_y(sprt_TOP_RIGHT, 100.0); + sprite_set_collision_kind(sprt_TOP_RIGHT, PIXEL_COLLISIONS); + + sprt_BOTTOM_LEFT = create_sprite("rocket_sprt.png"); + sprite_set_x(sprt_BOTTOM_LEFT, 100.0); + sprite_set_y(sprt_BOTTOM_LEFT, 500.0); + sprite_set_collision_kind(sprt_BOTTOM_LEFT, PIXEL_COLLISIONS); + + sprt_BOTTOM_RIGHT = create_sprite("rocket_sprt.png"); + sprite_set_x(sprt_BOTTOM_RIGHT, 500.0); + sprite_set_y(sprt_BOTTOM_RIGHT, 500.0); + sprite_set_collision_kind(sprt_BOTTOM_RIGHT, PIXEL_COLLISIONS); + + rect = rectangle_from(400.0, 450.0, 100.0, 50.0); + rect_TOP = rectangle_from(300.0, 100.0, 100.0, 50.0); + rect_BOTTOM = rectangle_from(300.0, 500.0, 100.0, 50.0); + rect_LEFT = rectangle_from(100.0, 300.0, 50.0, 100.0); + rect_RIGHT = rectangle_from(500.0, 300.0, 50.0, 100.0); + rect_TOP_LEFT = rectangle_from(100.0, 100.0, 50.0, 50.0); + rect_TOP_RIGHT = rectangle_from(500.0, 100.0, 50.0, 50.0); + rect_BOTTOM_LEFT = rectangle_from(100.0, 500.0, 50.0, 50.0); + rect_BOTTOM_RIGHT = rectangle_from(500.0, 500.0, 50.0, 50.0); + + circ = circle_at(400.0, 300.0, 50.0); + circ_TOP = circle_at(300.0, 100.0, 50.0); + circ_BOTTOM = circle_at(300.0, 500.0, 50.0); + circ_LEFT = circle_at(100.0, 300.0, 50.0); + circ_RIGHT = circle_at(500.0, 300.0, 50.0); + circ_TOP_LEFT = circle_at(100.0, 100.0, 50.0); + circ_TOP_RIGHT = circle_at(500.0, 100.0, 50.0); + circ_BOTTOM_LEFT = circle_at(100.0, 500.0, 50.0); + circ_BOTTOM_RIGHT = circle_at(500.0, 500.0, 50.0); + + tri_TOP = triangle_from(300.0, 100.0, 400.0, 100.0, 350.0, 150.0); + tri_BOTTOM = triangle_from(300.0, 500.0, 400.0, 500.0, 350.0, 450.0); + tri_LEFT = triangle_from(100.0, 300.0, 100.0, 400.0, 150.0, 350.0); + tri_RIGHT = triangle_from(500.0, 300.0, 500.0, 400.0, 450.0, 350.0); + tri_TOP_LEFT = triangle_from(100.0, 150.0, 150.0, 100.0, 150.0, 150.0); + tri_TOP_RIGHT = triangle_from(500.0, 150.0, 450.0, 100.0, 450.0, 150.0); + tri_BOTTOM_LEFT = triangle_from(100.0, 450.0, 150.0, 500.0, 150.0, 450.0); + tri_BOTTOM_RIGHT = triangle_from(500.0, 450.0, 450.0, 500.0, 450.0, 450.0); + + tri = triangle_from(400.0, 100.0, 500.0, 100.0, 450.0, 50.0); + + rectangle r = rectangle_from(400, 100, 100, 50); + q = quad_from(r); + apply_matrix(matrix_multiply(translation_matrix(0.0, 50.0), rotation_matrix(45.0)), q); + r = rectangle_from(0.0, 0.0, 100.0, 50.0); + quad_TOP = quad_from(r); + apply_matrix(matrix_multiply(rotation_matrix(45.0), translation_matrix(300.0, 20.0)), quad_TOP); + quad_BOTTOM = quad_from(r); + apply_matrix(matrix_multiply(rotation_matrix(45.0), translation_matrix(300.0, 470.0)), quad_BOTTOM); + quad_LEFT = quad_from(r); + apply_matrix(matrix_multiply(rotation_matrix(45.0), translation_matrix(50.0, 270.0)), quad_LEFT); + quad_RIGHT = quad_from(r); + apply_matrix(matrix_multiply(rotation_matrix(45.0), translation_matrix(500.0, 270.0)), quad_RIGHT); + quad_TOP_LEFT = quad_from(r); + apply_matrix(matrix_multiply(rotation_matrix(45.0), translation_matrix(50.0, 20.0)), quad_TOP_LEFT); + quad_TOP_RIGHT = quad_from(r); + apply_matrix(matrix_multiply(rotation_matrix(45.0), translation_matrix(500.0, 20.0)), quad_TOP_RIGHT); + quad_BOTTOM_LEFT = quad_from(r); + apply_matrix(matrix_multiply(rotation_matrix(45.0), translation_matrix(50.0, 470.0)), quad_BOTTOM_LEFT); + quad_BOTTOM_RIGHT = quad_from(r); + apply_matrix(matrix_multiply(rotation_matrix(45.0), translation_matrix(500.0, 470.0)), quad_BOTTOM_RIGHT); + + while (! quit_requested()) + { + process_events(); + + clear_screen(COLOR_WHITE); + + // Change the object type with number keys + if (key_typed(NUM_1_KEY)) + { + collider_type = object_type::SPRITE; + reset_sprite(collider_sprt); + } + if (key_typed(NUM_2_KEY)) + { + collider_type = object_type::RECTANGLE; + reset_rectangle(collider_rect); + } + if (key_typed(NUM_3_KEY)) + { + collider_type = object_type::CIRCLE; + reset_circle(collider_circ); + } + if (key_typed(NUM_4_KEY)) + { + collider_type = object_type::TRIANGLE; + reset_triangle(collider_tri); + } + if (key_typed(NUM_5_KEY)) + { + collider_type = object_type::QUAD; + reset_quad(collider_quad); + } + if (key_typed(NUM_6_KEY)) + { + test_type = collision_test_type::MULTIPLE_DYNAMIC; + } + if (key_typed(NUM_7_KEY)) + { + test_type = collision_test_type::SPRITE_FIXED; + } + if (key_typed(NUM_8_KEY)) + { + test_type = collision_test_type::RECTANGLE_FIXED; + } + if (key_typed(NUM_9_KEY)) + { + test_type = collision_test_type::CIRCLE_FIXED; + } + if (key_typed(NUM_0_KEY)) + { + test_type = collision_test_type::TRIANGLE_FIXED; + } + if (key_typed(MINUS_KEY)) + { + test_type = collision_test_type::QUAD_FIXED; + } + + if (collider_type == object_type::SPRITE) + { + if ( key_down(LEFT_KEY) ) + sprite_set_rotation(collider_sprt, sprite_rotation(collider_sprt) - 5.0); + + if ( key_down(RIGHT_KEY) ) + sprite_set_rotation(collider_sprt, sprite_rotation(collider_sprt) + 5.0); + + if ( key_down(LEFT_SHIFT_KEY) or key_down(RIGHT_SHIFT_KEY) ) + { + if ( key_down(UP_KEY) ) + sprite_set_scale(collider_sprt, sprite_scale(collider_sprt) + 0.1); + + if ( key_down(DOWN_KEY) ) + sprite_set_scale(collider_sprt, sprite_scale(collider_sprt) - 0.1); + } + else + { + if ( key_down(UP_KEY) ) + sprite_set_dy(collider_sprt, sprite_dy(collider_sprt) - 0.1); + + if ( key_down(DOWN_KEY) ) + sprite_set_dy(collider_sprt, sprite_dy(collider_sprt) + 0.1); + } + + update_sprite(collider_sprt); + } + else if (collider_type == object_type::RECTANGLE) + { + if ( key_down(LEFT_KEY) ) + collider_rect.x -= 1.0; + + if ( key_down(RIGHT_KEY) ) + collider_rect.x += 1.0; + + if ( key_down(UP_KEY) ) + collider_rect.y -= 1.0; + + if ( key_down(DOWN_KEY) ) + collider_rect.y += 1.0; + } + else if (collider_type == object_type::CIRCLE) + { + if ( key_down(LEFT_KEY) ) + collider_circ.center.x -= 1.0; + + if ( key_down(RIGHT_KEY) ) + collider_circ.center.x += 1.0; + + if ( key_down(UP_KEY) ) + collider_circ.center.y -= 1.0; + + if ( key_down(DOWN_KEY) ) + collider_circ.center.y += 1.0; + } + else if (collider_type == object_type::TRIANGLE) + { + if ( key_down(LEFT_KEY) ) + { + collider_tri.points[0].x -= 1.0; + collider_tri.points[1].x -= 1.0; + collider_tri.points[2].x -= 1.0; + } + if ( key_down(RIGHT_KEY) ) + { + collider_tri.points[0].x += 1.0; + collider_tri.points[1].x += 1.0; + collider_tri.points[2].x += 1.0; + } + if ( key_down(UP_KEY) ) + { + collider_tri.points[0].y -= 1.0; + collider_tri.points[1].y -= 1.0; + collider_tri.points[2].y -= 1.0; + } + if ( key_down(DOWN_KEY) ) + { + collider_tri.points[0].y += 1.0; + collider_tri.points[1].y += 1.0; + collider_tri.points[2].y += 1.0; + } + } + else if (collider_type == object_type::QUAD) + { + if ( key_down(LEFT_KEY) ) + { + collider_quad.points[0].x -= 1.0; + collider_quad.points[1].x -= 1.0; + collider_quad.points[2].x -= 1.0; + collider_quad.points[3].x -= 1.0; + } + if ( key_down(RIGHT_KEY) ) + { + collider_quad.points[0].x += 1.0; + collider_quad.points[1].x += 1.0; + collider_quad.points[2].x += 1.0; + collider_quad.points[3].x += 1.0; + } + if ( key_down(UP_KEY) ) + { + collider_quad.points[0].y -= 1.0; + collider_quad.points[1].y -= 1.0; + collider_quad.points[2].y -= 1.0; + collider_quad.points[3].y -= 1.0; + } + if ( key_down(DOWN_KEY) ) + { + collider_quad.points[0].y += 1.0; + collider_quad.points[1].y += 1.0; + collider_quad.points[2].y += 1.0; + collider_quad.points[3].y += 1.0; + } + } + + + + if (test_type == collision_test_type::MULTIPLE_DYNAMIC) + { + draw_rectangle(COLOR_RED, sprite_collision_rectangle(sprt_AABB)); + fill_rectangle(COLOR_GREEN, rect); + fill_circle(COLOR_GREEN, circ); + fill_triangle(COLOR_GREEN, tri); + fill_quad(COLOR_GREEN, q); + draw_sprite(sprt_pixel); + draw_sprite(sprt_AABB); + + if (collider_type == object_type::SPRITE) // sprite vs. multiple dynamic objects + { + resolve_and_draw(&collider_sprt, &sprt_pixel, collider_type, object_type::SPRITE, calculate_collision_direction(collider_sprt, sprt_pixel)); + resolve_and_draw(&collider_sprt, &sprt_AABB, collider_type, object_type::SPRITE, calculate_collision_direction(collider_sprt, sprt_AABB)); + resolve_and_draw(&collider_sprt, &rect, collider_type, object_type::RECTANGLE, calculate_collision_direction(collider_sprt, rect)); + resolve_and_draw(&collider_sprt, &circ, collider_type, object_type::CIRCLE, calculate_collision_direction(collider_sprt, circ)); + resolve_and_draw(&collider_sprt, &tri, collider_type, object_type::TRIANGLE, calculate_collision_direction(collider_sprt, tri)); + resolve_and_draw(&collider_sprt, &q, collider_type, object_type::QUAD, calculate_collision_direction(collider_sprt, q)); + + draw_sprite(collider_sprt); + draw_rectangle(COLOR_GREEN, sprite_collision_rectangle(collider_sprt)); + } + else if (collider_type == object_type::RECTANGLE) // rect vs. multiple dynamic objects + { + resolve_and_draw(&collider_rect, &sprt_pixel, collider_type, object_type::SPRITE, calculate_collision_direction(collider_rect, sprt_pixel)); + resolve_and_draw(&collider_rect, &sprt_AABB, collider_type, object_type::SPRITE, calculate_collision_direction(collider_rect, sprt_AABB)); + resolve_and_draw(&collider_rect, &rect, collider_type, object_type::RECTANGLE, calculate_collision_direction(collider_rect, rect)); + resolve_and_draw(&collider_rect, &circ, collider_type, object_type::CIRCLE, calculate_collision_direction(collider_rect, circ)); + resolve_and_draw(&collider_rect, &tri, collider_type, object_type::TRIANGLE, calculate_collision_direction(collider_rect, tri)); + resolve_and_draw(&collider_rect, &q, collider_type, object_type::QUAD, calculate_collision_direction(collider_rect, q)); + + fill_rectangle(COLOR_ORANGE, collider_rect); + } + else if (collider_type == object_type::CIRCLE) // circle vs. multiple dynamic objects + { + resolve_and_draw(&collider_circ, &sprt_pixel, collider_type, object_type::SPRITE, calculate_collision_direction(collider_circ, sprt_pixel)); + resolve_and_draw(&collider_circ, &sprt_AABB, collider_type, object_type::SPRITE, calculate_collision_direction(collider_circ, sprt_AABB)); + resolve_and_draw(&collider_circ, &rect, collider_type, object_type::RECTANGLE, calculate_collision_direction(collider_circ, rect)); + resolve_and_draw(&collider_circ, &circ, collider_type, object_type::CIRCLE, calculate_collision_direction(collider_circ, circ)); + resolve_and_draw(&collider_circ, &tri, collider_type, object_type::TRIANGLE, calculate_collision_direction(collider_circ, tri)); + resolve_and_draw(&collider_circ, &q, collider_type, object_type::QUAD, calculate_collision_direction(collider_circ, q)); + + fill_circle(COLOR_ORANGE, collider_circ); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_circ)); + } + else if (collider_type == object_type::TRIANGLE) // triangle vs. multiple dynamic objects + { + resolve_and_draw(&collider_tri, &sprt_pixel, collider_type, object_type::SPRITE, calculate_collision_direction(collider_tri, sprt_pixel)); + resolve_and_draw(&collider_tri, &sprt_AABB, collider_type, object_type::SPRITE, calculate_collision_direction(collider_tri, sprt_AABB)); + resolve_and_draw(&collider_tri, &rect, collider_type, object_type::RECTANGLE, calculate_collision_direction(collider_tri, rect)); + resolve_and_draw(&collider_tri, &circ, collider_type, object_type::CIRCLE, calculate_collision_direction(collider_tri, circ)); + resolve_and_draw(&collider_tri, &tri, collider_type, object_type::TRIANGLE, calculate_collision_direction(collider_tri, tri)); + resolve_and_draw(&collider_tri, &q, collider_type, object_type::QUAD, calculate_collision_direction(collider_tri, q)); + + fill_triangle(COLOR_ORANGE, collider_tri); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_tri)); + } + else if (collider_type == object_type::QUAD) // quad vs. multiple dynamic objects + { + resolve_and_draw(&collider_quad, &sprt_pixel, collider_type, object_type::SPRITE, calculate_collision_direction(collider_quad, sprt_pixel)); + resolve_and_draw(&collider_quad, &sprt_AABB, collider_type, object_type::SPRITE, calculate_collision_direction(collider_quad, sprt_AABB)); + resolve_and_draw(&collider_quad, &rect, collider_type, object_type::RECTANGLE, calculate_collision_direction(collider_quad, rect)); + resolve_and_draw(&collider_quad, &circ, collider_type, object_type::CIRCLE, calculate_collision_direction(collider_quad, circ)); + resolve_and_draw(&collider_quad, &tri, collider_type, object_type::TRIANGLE, calculate_collision_direction(collider_quad, tri)); + resolve_and_draw(&collider_quad, &q, collider_type, object_type::QUAD, calculate_collision_direction(collider_quad, q)); + + fill_quad(COLOR_ORANGE, collider_quad); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_quad)); + } + } + else if (test_type == collision_test_type::SPRITE_FIXED) + { + draw_sprite(sprt_TOP); + draw_sprite(sprt_BOTTOM); + draw_sprite(sprt_LEFT); + draw_sprite(sprt_RIGHT); + draw_sprite(sprt_TOP_LEFT); + draw_sprite(sprt_TOP_RIGHT); + draw_sprite(sprt_BOTTOM_LEFT); + draw_sprite(sprt_BOTTOM_RIGHT); + + if (collider_type == object_type::SPRITE) // sprite vs. fixed sprite objects + { + resolve_and_draw(&collider_sprt, &sprt_TOP, collider_type, object_type::SPRITE, DIRECTION_TOP); + resolve_and_draw(&collider_sprt, &sprt_BOTTOM, collider_type, object_type::SPRITE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_sprt, &sprt_LEFT, collider_type, object_type::SPRITE, DIRECTION_LEFT); + resolve_and_draw(&collider_sprt, &sprt_RIGHT, collider_type, object_type::SPRITE, DIRECTION_RIGHT); + resolve_and_draw(&collider_sprt, &sprt_TOP_LEFT, collider_type, object_type::SPRITE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_sprt, &sprt_TOP_RIGHT, collider_type, object_type::SPRITE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_sprt, &sprt_BOTTOM_LEFT, collider_type, object_type::SPRITE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_sprt, &sprt_BOTTOM_RIGHT, collider_type, object_type::SPRITE, DIRECTION_BOTTOM_RIGHT); + + draw_sprite(collider_sprt); + draw_rectangle(COLOR_GREEN, sprite_collision_rectangle(collider_sprt)); + } + else if (collider_type == object_type::RECTANGLE) // rect vs. fixed sprite objects + { + resolve_and_draw(&collider_rect, &sprt_TOP, collider_type, object_type::SPRITE, DIRECTION_TOP); + resolve_and_draw(&collider_rect, &sprt_BOTTOM, collider_type, object_type::SPRITE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_rect, &sprt_LEFT, collider_type, object_type::SPRITE, DIRECTION_LEFT); + resolve_and_draw(&collider_rect, &sprt_RIGHT, collider_type, object_type::SPRITE, DIRECTION_RIGHT); + resolve_and_draw(&collider_rect, &sprt_TOP_LEFT, collider_type, object_type::SPRITE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_rect, &sprt_TOP_RIGHT, collider_type, object_type::SPRITE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_rect, &sprt_BOTTOM_LEFT, collider_type, object_type::SPRITE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_rect, &sprt_BOTTOM_RIGHT, collider_type, object_type::SPRITE, DIRECTION_BOTTOM_RIGHT); + + fill_rectangle(COLOR_ORANGE, collider_rect); + } + else if (collider_type == object_type::CIRCLE) // circle vs. fixed sprite objects + { + resolve_and_draw(&collider_circ, &sprt_TOP, collider_type, object_type::SPRITE, DIRECTION_TOP); + resolve_and_draw(&collider_circ, &sprt_BOTTOM, collider_type, object_type::SPRITE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_circ, &sprt_LEFT, collider_type, object_type::SPRITE, DIRECTION_LEFT); + resolve_and_draw(&collider_circ, &sprt_RIGHT, collider_type, object_type::SPRITE, DIRECTION_RIGHT); + resolve_and_draw(&collider_circ, &sprt_TOP_LEFT, collider_type, object_type::SPRITE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_circ, &sprt_TOP_RIGHT, collider_type, object_type::SPRITE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_circ, &sprt_BOTTOM_LEFT, collider_type, object_type::SPRITE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_circ, &sprt_BOTTOM_RIGHT, collider_type, object_type::SPRITE, DIRECTION_BOTTOM_RIGHT); + + fill_circle(COLOR_ORANGE, collider_circ); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_circ)); + } + else if (collider_type == object_type::TRIANGLE) // triangle vs. fixed sprite objects + { + resolve_and_draw(&collider_tri, &sprt_TOP, collider_type, object_type::SPRITE, DIRECTION_TOP); + resolve_and_draw(&collider_tri, &sprt_BOTTOM, collider_type, object_type::SPRITE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_tri, &sprt_LEFT, collider_type, object_type::SPRITE, DIRECTION_LEFT); + resolve_and_draw(&collider_tri, &sprt_RIGHT, collider_type, object_type::SPRITE, DIRECTION_RIGHT); + resolve_and_draw(&collider_tri, &sprt_TOP_LEFT, collider_type, object_type::SPRITE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_tri, &sprt_TOP_RIGHT, collider_type, object_type::SPRITE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_tri, &sprt_BOTTOM_LEFT, collider_type, object_type::SPRITE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_tri, &sprt_BOTTOM_RIGHT, collider_type, object_type::SPRITE, DIRECTION_BOTTOM_RIGHT); + + fill_triangle(COLOR_ORANGE, collider_tri); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_tri)); + } + else if (collider_type == object_type::QUAD) // quad vs. fixed sprite objects + { + resolve_and_draw(&collider_quad, &sprt_TOP, collider_type, object_type::SPRITE, DIRECTION_TOP); + resolve_and_draw(&collider_quad, &sprt_BOTTOM, collider_type, object_type::SPRITE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_quad, &sprt_LEFT, collider_type, object_type::SPRITE, DIRECTION_LEFT); + resolve_and_draw(&collider_quad, &sprt_RIGHT, collider_type, object_type::SPRITE, DIRECTION_RIGHT); + resolve_and_draw(&collider_quad, &sprt_TOP_LEFT, collider_type, object_type::SPRITE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_quad, &sprt_TOP_RIGHT, collider_type, object_type::SPRITE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_quad, &sprt_BOTTOM_LEFT, collider_type, object_type::SPRITE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_quad, &sprt_BOTTOM_RIGHT, collider_type, object_type::SPRITE, DIRECTION_BOTTOM_RIGHT); + + fill_quad(COLOR_ORANGE, collider_quad); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_quad)); + } + } + else if (test_type == collision_test_type::RECTANGLE_FIXED) + { + fill_rectangle(COLOR_GREEN, rect_TOP); + fill_rectangle(COLOR_GREEN, rect_BOTTOM); + fill_rectangle(COLOR_GREEN, rect_LEFT); + fill_rectangle(COLOR_GREEN, rect_RIGHT); + fill_rectangle(COLOR_GREEN, rect_TOP_LEFT); + fill_rectangle(COLOR_GREEN, rect_TOP_RIGHT); + fill_rectangle(COLOR_GREEN, rect_BOTTOM_LEFT); + fill_rectangle(COLOR_GREEN, rect_BOTTOM_RIGHT); + + if (collider_type == object_type::SPRITE) // sprite vs. fixed rectangle objects + { + resolve_and_draw(&collider_sprt, &rect_TOP, collider_type, object_type::RECTANGLE, DIRECTION_TOP); + resolve_and_draw(&collider_sprt, &rect_BOTTOM, collider_type, object_type::RECTANGLE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_sprt, &rect_LEFT, collider_type, object_type::RECTANGLE, DIRECTION_LEFT); + resolve_and_draw(&collider_sprt, &rect_RIGHT, collider_type, object_type::RECTANGLE, DIRECTION_RIGHT); + resolve_and_draw(&collider_sprt, &rect_TOP_LEFT, collider_type, object_type::RECTANGLE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_sprt, &rect_TOP_RIGHT, collider_type, object_type::RECTANGLE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_sprt, &rect_BOTTOM_LEFT, collider_type, object_type::RECTANGLE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_sprt, &rect_BOTTOM_RIGHT, collider_type, object_type::RECTANGLE, DIRECTION_BOTTOM_RIGHT); + + draw_sprite(collider_sprt); + draw_rectangle(COLOR_GREEN, sprite_collision_rectangle(collider_sprt)); + } + else if (collider_type == object_type::RECTANGLE) // rect vs. fixed rectangle objects + { + resolve_and_draw(&collider_rect, &rect_TOP, collider_type, object_type::RECTANGLE, DIRECTION_TOP); + resolve_and_draw(&collider_rect, &rect_BOTTOM, collider_type, object_type::RECTANGLE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_rect, &rect_LEFT, collider_type, object_type::RECTANGLE, DIRECTION_LEFT); + resolve_and_draw(&collider_rect, &rect_RIGHT, collider_type, object_type::RECTANGLE, DIRECTION_RIGHT); + resolve_and_draw(&collider_rect, &rect_TOP_LEFT, collider_type, object_type::RECTANGLE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_rect, &rect_TOP_RIGHT, collider_type, object_type::RECTANGLE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_rect, &rect_BOTTOM_LEFT, collider_type, object_type::RECTANGLE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_rect, &rect_BOTTOM_RIGHT, collider_type, object_type::RECTANGLE, DIRECTION_BOTTOM_RIGHT); + + fill_rectangle(COLOR_ORANGE, collider_rect); + } + else if (collider_type == object_type::CIRCLE) // circle vs. fixed rectangle objects + { + resolve_and_draw(&collider_circ, &rect_TOP, collider_type, object_type::RECTANGLE, DIRECTION_TOP); + resolve_and_draw(&collider_circ, &rect_BOTTOM, collider_type, object_type::RECTANGLE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_circ, &rect_LEFT, collider_type, object_type::RECTANGLE, DIRECTION_LEFT); + resolve_and_draw(&collider_circ, &rect_RIGHT, collider_type, object_type::RECTANGLE, DIRECTION_RIGHT); + resolve_and_draw(&collider_circ, &rect_TOP_LEFT, collider_type, object_type::RECTANGLE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_circ, &rect_TOP_RIGHT, collider_type, object_type::RECTANGLE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_circ, &rect_BOTTOM_LEFT, collider_type, object_type::RECTANGLE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_circ, &rect_BOTTOM_RIGHT, collider_type, object_type::RECTANGLE, DIRECTION_BOTTOM_RIGHT); + + fill_circle(COLOR_ORANGE, collider_circ); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_circ)); + } + else if (collider_type == object_type::TRIANGLE) // triangle vs. fixed rectangle objects + { + resolve_and_draw(&collider_tri, &rect_TOP, collider_type, object_type::RECTANGLE, DIRECTION_TOP); + resolve_and_draw(&collider_tri, &rect_BOTTOM, collider_type, object_type::RECTANGLE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_tri, &rect_LEFT, collider_type, object_type::RECTANGLE, DIRECTION_LEFT); + resolve_and_draw(&collider_tri, &rect_RIGHT, collider_type, object_type::RECTANGLE, DIRECTION_RIGHT); + resolve_and_draw(&collider_tri, &rect_TOP_LEFT, collider_type, object_type::RECTANGLE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_tri, &rect_TOP_RIGHT, collider_type, object_type::RECTANGLE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_tri, &rect_BOTTOM_LEFT, collider_type, object_type::RECTANGLE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_tri, &rect_BOTTOM_RIGHT, collider_type, object_type::RECTANGLE, DIRECTION_BOTTOM_RIGHT); + + fill_triangle(COLOR_ORANGE, collider_tri); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_tri)); + } + else if (collider_type == object_type::QUAD) // quad vs. fixed rectangle objects + { + resolve_and_draw(&collider_quad, &rect_TOP, collider_type, object_type::RECTANGLE, DIRECTION_TOP); + resolve_and_draw(&collider_quad, &rect_BOTTOM, collider_type, object_type::RECTANGLE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_quad, &rect_LEFT, collider_type, object_type::RECTANGLE, DIRECTION_LEFT); + resolve_and_draw(&collider_quad, &rect_RIGHT, collider_type, object_type::RECTANGLE, DIRECTION_RIGHT); + resolve_and_draw(&collider_quad, &rect_TOP_LEFT, collider_type, object_type::RECTANGLE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_quad, &rect_TOP_RIGHT, collider_type, object_type::RECTANGLE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_quad, &rect_BOTTOM_LEFT, collider_type, object_type::RECTANGLE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_quad, &rect_BOTTOM_RIGHT, collider_type, object_type::RECTANGLE, DIRECTION_BOTTOM_RIGHT); + + fill_quad(COLOR_ORANGE, collider_quad); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_quad)); + } + } + else if (test_type == collision_test_type::CIRCLE_FIXED) + { + fill_circle(COLOR_GREEN, circ_TOP); + fill_circle(COLOR_GREEN, circ_BOTTOM); + fill_circle(COLOR_GREEN, circ_LEFT); + fill_circle(COLOR_GREEN, circ_RIGHT); + fill_circle(COLOR_GREEN, circ_TOP_LEFT); + fill_circle(COLOR_GREEN, circ_TOP_RIGHT); + fill_circle(COLOR_GREEN, circ_BOTTOM_LEFT); + fill_circle(COLOR_GREEN, circ_BOTTOM_RIGHT); + + if (collider_type == object_type::SPRITE) // sprite vs. fixed circle objects + { + resolve_and_draw(&collider_sprt, &circ_TOP, collider_type, object_type::CIRCLE, DIRECTION_TOP); + resolve_and_draw(&collider_sprt, &circ_BOTTOM, collider_type, object_type::CIRCLE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_sprt, &circ_LEFT, collider_type, object_type::CIRCLE, DIRECTION_LEFT); + resolve_and_draw(&collider_sprt, &circ_RIGHT, collider_type, object_type::CIRCLE, DIRECTION_RIGHT); + resolve_and_draw(&collider_sprt, &circ_TOP_LEFT, collider_type, object_type::CIRCLE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_sprt, &circ_TOP_RIGHT, collider_type, object_type::CIRCLE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_sprt, &circ_BOTTOM_LEFT, collider_type, object_type::CIRCLE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_sprt, &circ_BOTTOM_RIGHT, collider_type, object_type::CIRCLE, DIRECTION_BOTTOM_RIGHT); + + draw_sprite(collider_sprt); + draw_rectangle(COLOR_GREEN, sprite_collision_rectangle(collider_sprt)); + } + else if (collider_type == object_type::RECTANGLE) // rect vs. fixed circle objects + { + resolve_and_draw(&collider_rect, &circ_TOP, collider_type, object_type::CIRCLE, DIRECTION_TOP); + resolve_and_draw(&collider_rect, &circ_BOTTOM, collider_type, object_type::CIRCLE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_rect, &circ_LEFT, collider_type, object_type::CIRCLE, DIRECTION_LEFT); + resolve_and_draw(&collider_rect, &circ_RIGHT, collider_type, object_type::CIRCLE, DIRECTION_RIGHT); + resolve_and_draw(&collider_rect, &circ_TOP_LEFT, collider_type, object_type::CIRCLE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_rect, &circ_TOP_RIGHT, collider_type, object_type::CIRCLE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_rect, &circ_BOTTOM_LEFT, collider_type, object_type::CIRCLE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_rect, &circ_BOTTOM_RIGHT, collider_type, object_type::CIRCLE, DIRECTION_BOTTOM_RIGHT); + + fill_rectangle(COLOR_ORANGE, collider_rect); + } + else if (collider_type == object_type::CIRCLE) // circle vs. fixed circle objects + { + resolve_and_draw(&collider_circ, &circ_TOP, collider_type, object_type::CIRCLE, DIRECTION_TOP); + resolve_and_draw(&collider_circ, &circ_BOTTOM, collider_type, object_type::CIRCLE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_circ, &circ_LEFT, collider_type, object_type::CIRCLE, DIRECTION_LEFT); + resolve_and_draw(&collider_circ, &circ_RIGHT, collider_type, object_type::CIRCLE, DIRECTION_RIGHT); + resolve_and_draw(&collider_circ, &circ_TOP_LEFT, collider_type, object_type::CIRCLE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_circ, &circ_TOP_RIGHT, collider_type, object_type::CIRCLE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_circ, &circ_BOTTOM_LEFT, collider_type, object_type::CIRCLE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_circ, &circ_BOTTOM_RIGHT, collider_type, object_type::CIRCLE, DIRECTION_BOTTOM_RIGHT); + + fill_circle(COLOR_ORANGE, collider_circ); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_circ)); + } + else if (collider_type == object_type::TRIANGLE) // triangle vs. fixed circle objects + { + resolve_and_draw(&collider_tri, &circ_TOP, collider_type, object_type::CIRCLE, DIRECTION_TOP); + resolve_and_draw(&collider_tri, &circ_BOTTOM, collider_type, object_type::CIRCLE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_tri, &circ_LEFT, collider_type, object_type::CIRCLE, DIRECTION_LEFT); + resolve_and_draw(&collider_tri, &circ_RIGHT, collider_type, object_type::CIRCLE, DIRECTION_RIGHT); + resolve_and_draw(&collider_tri, &circ_TOP_LEFT, collider_type, object_type::CIRCLE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_tri, &circ_TOP_RIGHT, collider_type, object_type::CIRCLE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_tri, &circ_BOTTOM_LEFT, collider_type, object_type::CIRCLE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_tri, &circ_BOTTOM_RIGHT, collider_type, object_type::CIRCLE, DIRECTION_BOTTOM_RIGHT); + + fill_triangle(COLOR_ORANGE, collider_tri); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_tri)); + } + else if (collider_type == object_type::QUAD) // quad vs. fixed circle objects + { + resolve_and_draw(&collider_quad, &circ_TOP, collider_type, object_type::CIRCLE, DIRECTION_TOP); + resolve_and_draw(&collider_quad, &circ_BOTTOM, collider_type, object_type::CIRCLE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_quad, &circ_LEFT, collider_type, object_type::CIRCLE, DIRECTION_LEFT); + resolve_and_draw(&collider_quad, &circ_RIGHT, collider_type, object_type::CIRCLE, DIRECTION_RIGHT); + resolve_and_draw(&collider_quad, &circ_TOP_LEFT, collider_type, object_type::CIRCLE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_quad, &circ_TOP_RIGHT, collider_type, object_type::CIRCLE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_quad, &circ_BOTTOM_LEFT, collider_type, object_type::CIRCLE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_quad, &circ_BOTTOM_RIGHT, collider_type, object_type::CIRCLE, DIRECTION_BOTTOM_RIGHT); + + fill_quad(COLOR_ORANGE, collider_quad); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_quad)); + } + } + else if (test_type == collision_test_type::TRIANGLE_FIXED) + { + fill_triangle(COLOR_GREEN, tri_TOP); + fill_triangle(COLOR_GREEN, tri_BOTTOM); + fill_triangle(COLOR_GREEN, tri_LEFT); + fill_triangle(COLOR_GREEN, tri_RIGHT); + fill_triangle(COLOR_GREEN, tri_TOP_LEFT); + fill_triangle(COLOR_GREEN, tri_TOP_RIGHT); + fill_triangle(COLOR_GREEN, tri_BOTTOM_LEFT); + fill_triangle(COLOR_GREEN, tri_BOTTOM_RIGHT); + + if (collider_type == object_type::SPRITE) // sprite vs. fixed triangle objects + { + resolve_and_draw(&collider_sprt, &tri_TOP, collider_type, object_type::TRIANGLE, DIRECTION_TOP); + resolve_and_draw(&collider_sprt, &tri_BOTTOM, collider_type, object_type::TRIANGLE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_sprt, &tri_LEFT, collider_type, object_type::TRIANGLE, DIRECTION_LEFT); + resolve_and_draw(&collider_sprt, &tri_RIGHT, collider_type, object_type::TRIANGLE, DIRECTION_RIGHT); + resolve_and_draw(&collider_sprt, &tri_TOP_LEFT, collider_type, object_type::TRIANGLE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_sprt, &tri_TOP_RIGHT, collider_type, object_type::TRIANGLE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_sprt, &tri_BOTTOM_LEFT, collider_type, object_type::TRIANGLE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_sprt, &tri_BOTTOM_RIGHT, collider_type, object_type::TRIANGLE, DIRECTION_BOTTOM_RIGHT); + + draw_sprite(collider_sprt); + draw_rectangle(COLOR_GREEN, sprite_collision_rectangle(collider_sprt)); + } + else if (collider_type == object_type::RECTANGLE) // rect vs. fixed triangle objects + { + resolve_and_draw(&collider_rect, &tri_TOP, collider_type, object_type::TRIANGLE, DIRECTION_TOP); + resolve_and_draw(&collider_rect, &tri_BOTTOM, collider_type, object_type::TRIANGLE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_rect, &tri_LEFT, collider_type, object_type::TRIANGLE, DIRECTION_LEFT); + resolve_and_draw(&collider_rect, &tri_RIGHT, collider_type, object_type::TRIANGLE, DIRECTION_RIGHT); + resolve_and_draw(&collider_rect, &tri_TOP_LEFT, collider_type, object_type::TRIANGLE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_rect, &tri_TOP_RIGHT, collider_type, object_type::TRIANGLE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_rect, &tri_BOTTOM_LEFT, collider_type, object_type::TRIANGLE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_rect, &tri_BOTTOM_RIGHT, collider_type, object_type::TRIANGLE, DIRECTION_BOTTOM_RIGHT); + + fill_rectangle(COLOR_ORANGE, collider_rect); + } + else if (collider_type == object_type::CIRCLE) // circle vs. fixed triangle objects + { + resolve_and_draw(&collider_circ, &tri_TOP, collider_type, object_type::TRIANGLE, DIRECTION_TOP); + resolve_and_draw(&collider_circ, &tri_BOTTOM, collider_type, object_type::TRIANGLE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_circ, &tri_LEFT, collider_type, object_type::TRIANGLE, DIRECTION_LEFT); + resolve_and_draw(&collider_circ, &tri_RIGHT, collider_type, object_type::TRIANGLE, DIRECTION_RIGHT); + resolve_and_draw(&collider_circ, &tri_TOP_LEFT, collider_type, object_type::TRIANGLE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_circ, &tri_TOP_RIGHT, collider_type, object_type::TRIANGLE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_circ, &tri_BOTTOM_LEFT, collider_type, object_type::TRIANGLE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_circ, &tri_BOTTOM_RIGHT, collider_type, object_type::TRIANGLE, DIRECTION_BOTTOM_RIGHT); + + fill_circle(COLOR_ORANGE, collider_circ); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_circ)); + } + else if (collider_type == object_type::TRIANGLE) // triangle vs. fixed triangle objects + { + resolve_and_draw(&collider_tri, &tri_TOP, collider_type, object_type::TRIANGLE, DIRECTION_TOP); + resolve_and_draw(&collider_tri, &tri_BOTTOM, collider_type, object_type::TRIANGLE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_tri, &tri_LEFT, collider_type, object_type::TRIANGLE, DIRECTION_LEFT); + resolve_and_draw(&collider_tri, &tri_RIGHT, collider_type, object_type::TRIANGLE, DIRECTION_RIGHT); + resolve_and_draw(&collider_tri, &tri_TOP_LEFT, collider_type, object_type::TRIANGLE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_tri, &tri_TOP_RIGHT, collider_type, object_type::TRIANGLE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_tri, &tri_BOTTOM_LEFT, collider_type, object_type::TRIANGLE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_tri, &tri_BOTTOM_RIGHT, collider_type, object_type::TRIANGLE, DIRECTION_BOTTOM_RIGHT); + + fill_triangle(COLOR_ORANGE, collider_tri); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_tri)); + } + else if (collider_type == object_type::QUAD) // quad vs. fixed triangle objects + { + resolve_and_draw(&collider_quad, &tri_TOP, collider_type, object_type::TRIANGLE, DIRECTION_TOP); + resolve_and_draw(&collider_quad, &tri_BOTTOM, collider_type, object_type::TRIANGLE, DIRECTION_BOTTOM); + resolve_and_draw(&collider_quad, &tri_LEFT, collider_type, object_type::TRIANGLE, DIRECTION_LEFT); + resolve_and_draw(&collider_quad, &tri_RIGHT, collider_type, object_type::TRIANGLE, DIRECTION_RIGHT); + resolve_and_draw(&collider_quad, &tri_TOP_LEFT, collider_type, object_type::TRIANGLE, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_quad, &tri_TOP_RIGHT, collider_type, object_type::TRIANGLE, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_quad, &tri_BOTTOM_LEFT, collider_type, object_type::TRIANGLE, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_quad, &tri_BOTTOM_RIGHT, collider_type, object_type::TRIANGLE, DIRECTION_BOTTOM_RIGHT); + + fill_quad(COLOR_ORANGE, collider_quad); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_quad)); + } + } + else if (test_type == collision_test_type::QUAD_FIXED) + { + fill_quad(COLOR_GREEN, quad_TOP); + fill_quad(COLOR_GREEN, quad_BOTTOM); + fill_quad(COLOR_GREEN, quad_LEFT); + fill_quad(COLOR_GREEN, quad_RIGHT); + fill_quad(COLOR_GREEN, quad_TOP_LEFT); + fill_quad(COLOR_GREEN, quad_TOP_RIGHT); + fill_quad(COLOR_GREEN, quad_BOTTOM_LEFT); + fill_quad(COLOR_GREEN, quad_BOTTOM_RIGHT); + + if (collider_type == object_type::SPRITE) // sprite vs. fixed quad objects + { + resolve_and_draw(&collider_sprt, &quad_TOP, collider_type, object_type::QUAD, DIRECTION_TOP); + resolve_and_draw(&collider_sprt, &quad_BOTTOM, collider_type, object_type::QUAD, DIRECTION_BOTTOM); + resolve_and_draw(&collider_sprt, &quad_LEFT, collider_type, object_type::QUAD, DIRECTION_LEFT); + resolve_and_draw(&collider_sprt, &quad_RIGHT, collider_type, object_type::QUAD, DIRECTION_RIGHT); + resolve_and_draw(&collider_sprt, &quad_TOP_LEFT, collider_type, object_type::QUAD, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_sprt, &quad_TOP_RIGHT, collider_type, object_type::QUAD, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_sprt, &quad_BOTTOM_LEFT, collider_type, object_type::QUAD, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_sprt, &quad_BOTTOM_RIGHT, collider_type, object_type::QUAD, DIRECTION_BOTTOM_RIGHT); + + draw_sprite(collider_sprt); + draw_rectangle(COLOR_GREEN, sprite_collision_rectangle(collider_sprt)); + } + else if (collider_type == object_type::RECTANGLE) // rect vs. fixed quad objects + { + resolve_and_draw(&collider_rect, &quad_TOP, collider_type, object_type::QUAD, DIRECTION_TOP); + resolve_and_draw(&collider_rect, &quad_BOTTOM, collider_type, object_type::QUAD, DIRECTION_BOTTOM); + resolve_and_draw(&collider_rect, &quad_LEFT, collider_type, object_type::QUAD, DIRECTION_LEFT); + resolve_and_draw(&collider_rect, &quad_RIGHT, collider_type, object_type::QUAD, DIRECTION_RIGHT); + resolve_and_draw(&collider_rect, &quad_TOP_LEFT, collider_type, object_type::QUAD, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_rect, &quad_TOP_RIGHT, collider_type, object_type::QUAD, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_rect, &quad_BOTTOM_LEFT, collider_type, object_type::QUAD, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_rect, &quad_BOTTOM_RIGHT, collider_type, object_type::QUAD, DIRECTION_BOTTOM_RIGHT); + + fill_rectangle(COLOR_ORANGE, collider_rect); + } + else if (collider_type == object_type::CIRCLE) // circle vs. fixed quad objects + { + resolve_and_draw(&collider_circ, &quad_TOP, collider_type, object_type::QUAD, DIRECTION_TOP); + resolve_and_draw(&collider_circ, &quad_BOTTOM, collider_type, object_type::QUAD, DIRECTION_BOTTOM); + resolve_and_draw(&collider_circ, &quad_LEFT, collider_type, object_type::QUAD, DIRECTION_LEFT); + resolve_and_draw(&collider_circ, &quad_RIGHT, collider_type, object_type::QUAD, DIRECTION_RIGHT); + resolve_and_draw(&collider_circ, &quad_TOP_LEFT, collider_type, object_type::QUAD, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_circ, &quad_TOP_RIGHT, collider_type, object_type::QUAD, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_circ, &quad_BOTTOM_LEFT, collider_type, object_type::QUAD, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_circ, &quad_BOTTOM_RIGHT, collider_type, object_type::QUAD, DIRECTION_BOTTOM_RIGHT); + + fill_circle(COLOR_ORANGE, collider_circ); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_circ)); + } + else if (collider_type == object_type::TRIANGLE) // triangle vs. fixed quad objects + { + resolve_and_draw(&collider_tri, &quad_TOP, collider_type, object_type::QUAD, DIRECTION_TOP); + resolve_and_draw(&collider_tri, &quad_BOTTOM, collider_type, object_type::QUAD, DIRECTION_BOTTOM); + resolve_and_draw(&collider_tri, &quad_LEFT, collider_type, object_type::QUAD, DIRECTION_LEFT); + resolve_and_draw(&collider_tri, &quad_RIGHT, collider_type, object_type::QUAD, DIRECTION_RIGHT); + resolve_and_draw(&collider_tri, &quad_TOP_LEFT, collider_type, object_type::QUAD, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_tri, &quad_TOP_RIGHT, collider_type, object_type::QUAD, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_tri, &quad_BOTTOM_LEFT, collider_type, object_type::QUAD, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_tri, &quad_BOTTOM_RIGHT, collider_type, object_type::QUAD, DIRECTION_BOTTOM_RIGHT); + + fill_triangle(COLOR_ORANGE, collider_tri); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_tri)); + } + else if (collider_type == object_type::QUAD) // quad vs. fixed quad objects + { + resolve_and_draw(&collider_quad, &quad_TOP, collider_type, object_type::QUAD, DIRECTION_TOP); + resolve_and_draw(&collider_quad, &quad_BOTTOM, collider_type, object_type::QUAD, DIRECTION_BOTTOM); + resolve_and_draw(&collider_quad, &quad_LEFT, collider_type, object_type::QUAD, DIRECTION_LEFT); + resolve_and_draw(&collider_quad, &quad_RIGHT, collider_type, object_type::QUAD, DIRECTION_RIGHT); + resolve_and_draw(&collider_quad, &quad_TOP_LEFT, collider_type, object_type::QUAD, DIRECTION_TOP_LEFT); + resolve_and_draw(&collider_quad, &quad_TOP_RIGHT, collider_type, object_type::QUAD, DIRECTION_TOP_RIGHT); + resolve_and_draw(&collider_quad, &quad_BOTTOM_LEFT, collider_type, object_type::QUAD, DIRECTION_BOTTOM_LEFT); + resolve_and_draw(&collider_quad, &quad_BOTTOM_RIGHT, collider_type, object_type::QUAD, DIRECTION_BOTTOM_RIGHT); + + fill_quad(COLOR_ORANGE, collider_quad); + draw_rectangle(COLOR_GREEN, rectangle_around(collider_quad)); + } + } // end if + + refresh_screen(60); + + } // end while + + show_mouse(); + close_all_windows(); +} + +void run_sprite_test() +{ + sprite_test(); + multi_object_collision_resolution_test(); +} diff --git a/coresdk/src/test/unit_tests/unit_test_geometry.cpp b/coresdk/src/test/unit_tests/unit_test_geometry.cpp new file mode 100644 index 00000000..4c83c32b --- /dev/null +++ b/coresdk/src/test/unit_tests/unit_test_geometry.cpp @@ -0,0 +1,69 @@ +/** + * Geometry Unit Tests + */ + +#include "catch.hpp" + +#include "types.h" +#include "point_geometry.h" + +using namespace splashkit_lib; + +TEST_CASE("can perform circle geometry", "[geometry]") +{ + SECTION("can detect circle-quad intersection") + { + circle c = circle_at(100.0, 100.0, 50.0); + quad q = quad_from(rectangle_from(50.0, 50.0, 100.0, 100.0)); + REQUIRE(circle_quad_intersect(c, q)); + q = quad_from(rectangle_from(0.0, 0.0, 500.0, 500.0)); + REQUIRE(circle_quad_intersect(c, q)); + q = quad_from(rectangle_from(99.0, 99.0, 5.0, 5.0)); + REQUIRE(circle_quad_intersect(c, q)); + q = quad_from(rectangle_from(200.0, 200.0, 100.0, 100.0)); + REQUIRE_FALSE(circle_quad_intersect(c, q)); + } +} +TEST_CASE("can perform rectangle geometry", "[rectangle]") +{ + SECTION("can detect rectangle-circle intersection") + { + rectangle r = rectangle_from(100.0, 100.0, 100.0, 100.0); + circle c = circle_at(150.0, 150.0, 50.0); + REQUIRE(rectangle_circle_intersect(r, c)); + c = circle_at(150.0, 150.0, 1.0); + REQUIRE(rectangle_circle_intersect(r, c)); + c = circle_at(150.0, 150.0, 500.0); + REQUIRE(rectangle_circle_intersect(r, c)); + c = circle_at(300.0, 300.0, 50.0); + REQUIRE_FALSE(rectangle_circle_intersect(r, c)); + } +} +TEST_CASE("can perform triangle geometry", "[triangle]") +{ + SECTION("can detect triangle-quad intersection") + { + triangle t = triangle_from(100.0, 100.0, 200.0, 100.0, 150.0, 150.0); + quad q = quad_from(rectangle_from(50.0, 50.0, 100.0, 100.0)); + REQUIRE(triangle_quad_intersect(t, q)); + q = quad_from(rectangle_from(0.0, 0.0, 500.0, 500.0)); + REQUIRE(triangle_quad_intersect(t, q)); + q = quad_from(rectangle_from(150.0, 101.0, 5.0, 5.0)); + REQUIRE(triangle_quad_intersect(t, q)); + q = quad_from(rectangle_from(200.0, 200.0, 100.0, 100.0)); + REQUIRE_FALSE(triangle_quad_intersect(t, q)); + } +} +TEST_CASE("can perform line geometry", "[line]") +{ + SECTION("can detect line-rectangle intersection") + { + line l = line_from(100.0, 100.0, 200.0, 200.0); + rectangle r = rectangle_from(150.0, 150.0, 100.0, 100.0); + REQUIRE(line_intersects_rect(l, r)); + r = rectangle_from(90.0, 90.0, 200.0, 200.0); + REQUIRE(line_intersects_rect(l, r)); + r = rectangle_from(250.0, 250.0, 100.0, 100.0); + REQUIRE_FALSE(line_intersects_rect(l, r)); + } +} \ No newline at end of file