Fixed most of the bugs of the collision detection (still some cases

there)
This commit is contained in:
Karma Riuk 2023-05-17 13:22:34 +02:00
parent b4203884ef
commit 487b5fe00b
2 changed files with 134 additions and 73 deletions

View File

@ -96,9 +96,10 @@ static collision penetration(segment& edge, vertex& vertex, vec2d& d) {
vec2d n = (edge.second - edge.first).orthogonal();
ret.n = vec2d::normalize(n);
if (vec2d::dot(n, d) > 0)
ret.n *= -1;
std::cout << "Double pene omg" << std::endl;
// if (vec2d::dot(n, d) > 0)
// ret.n *= -1;
std::cout << "-------------- Impact: penetration --------------"
<< std::endl;
return ret;
}
@ -135,11 +136,10 @@ static collision parallel(segment edge_p, segment edge_q, vec2d d) {
vec2d max = p_max->first < q_max->first ? p_max->second : q_max->second;
ret.impact_point = (min + max) / 2;
std::cout << "impact point: " << ret.impact_point << std::endl;
ret.n = base.orthogonal();
if (vec2d::dot(ret.n, d) > 0)
ret.n *= -1;
std::cout << "Parallel lol" << std::endl;
std::cout << "-------------- Impact: parallel --------------" << std::endl;
return ret;
}
@ -154,35 +154,61 @@ static double distance_between_parallel_segments(segment s1, segment s2) {
return std::abs(area / base);
}
#define SMALLEST_DIST 5
#define SMALLEST_DIST 3
static bool are_edges_colinear(segment& e1, segment& e2) {
vec2d e1_vec = e1.second - e1.first;
vec2d e2_vec = e2.second - e2.first;
return are_vecs_parallel(e1_vec, e2_vec) &&
distance_between_parallel_segments(e1, e2) < SMALLEST_DIST;
}
static collision vertex_edge_collision(polygon& p, polygon& q) {
std::vector<vertex> vertices_p = vertices_of(p);
std::vector<segment> edges_q = edges_of(q);
vec2d d = q.centroid() - p.centroid();
segment edge_p1, edge_p2;
bool col1, col2;
for (auto& vertex : vertices_p)
for (auto& edge : edges_q) {
col1 = do_intersect(edge, {vertex.v, vertex.p1});
col2 = do_intersect(edge, {vertex.v, vertex.p2});
for (auto& edge_q : edges_q) {
edge_p1 = {vertex.v, vertex.p1};
edge_p2 = {vertex.v, vertex.p2};
col1 = do_intersect(edge_q, edge_p1);
col2 = do_intersect(edge_q, edge_p2);
if (col1 || col2) {
if (are_edges_colinear(edge_q, edge_p1))
return parallel(edge_q, edge_p1, d);
if (are_edges_colinear(edge_q, edge_p2))
return parallel(edge_q, edge_p2, d);
if (col1 && col2)
return penetration(edge, vertex, d);
return penetration(edge_q, vertex, d);
}
}
return {false};
}
vec2d edge_v = edge.second - edge.first;
if (are_vecs_parallel(edge_v, vertex.v - vertex.p1) &&
distance_between_parallel_segments(
edge, {vertex.v, vertex.p1}) < SMALLEST_DIST)
return parallel(edge, {vertex.v, vertex.p1}, d);
static collision vertex_vertex_collision(polygon& p, polygon& q) {
std::vector<vertex> vertices_p = vertices_of(p);
std::vector<segment> edges_q = edges_of(q);
vec2d d = q.centroid() - p.centroid();
double dist = distance_between_parallel_segments(
edge, {vertex.v, vertex.p2});
std::cout << "dist: " << dist << std::endl;
if (are_vecs_parallel(edge_v, vertex.v - vertex.p2) &&
distance_between_parallel_segments(
edge, {vertex.v, vertex.p2}) < SMALLEST_DIST)
return parallel(edge, {vertex.v, vertex.p2}, d);
for (auto& vertex : vertices_p)
for (auto& edge_q : edges_q) {
if (do_intersect(edge_q, {vertex.v, vertex.p1})) {
vec2d edge_q_vec = edge_q.second - edge_q.first;
vec2d n = vec2d::normalize(edge_q_vec.orthogonal());
if (vec2d::dot(n, d) > 0)
n *= -1;
std::cout
<< "-------------- Impact: angle in angle --------------"
<< std::endl;
return {true, n, vertex.v};
}
}
return {false};
@ -191,14 +217,19 @@ static collision vertex_edge_collision(polygon& p, polygon& q) {
static collision convex_collides(polygon& p, polygon& q) {
collision ret;
std::cout << "Checking P is penetrates Q" << std::endl;
if ((ret = vertex_edge_collision(p, q)).collides)
return ret;
std::cout << "Checking Q is penetrates P" << std::endl;
if ((ret = vertex_edge_collision(q, p)).collides)
if ((ret = vertex_edge_collision(q, p)).collides) {
ret.n *= -1;
return ret;
}
if ((ret = vertex_vertex_collision(p, q)).collides)
return ret;
if ((ret = vertex_vertex_collision(q, p)).collides)
ret.n *= -1;
return ret;
}

View File

@ -6,6 +6,7 @@
#include "matrix.h"
#include "polygon_generator.h"
#include <algorithm>
#include <iostream>
#include <utility>
@ -37,11 +38,18 @@ void polygons_init_state() {
// .set_center({25 + width * 1. / 2, height / 2.})
// .set_angle(0);
polygons[4] = poly_generate::rectangle(100, 200, 3)
.set_center({200, 180})
.set_angle(45)
#define PROBLEMATIC_COUPLES 1
#if PROBLEMATIC_COUPLES == 0
polygons[4] = poly_generate::regular(100, 3)
.set_center({100, 400})
.set_angle(0)
.set_speed({200, -10});
polygons[5] = poly_generate::square(100)
.set_center({600, 400})
.set_angle(45)
.set_speed({-200, -10});
// .set_angle(45)
// .set_center({300, 650})
// .set_angular_speed(181)
@ -51,10 +59,10 @@ void polygons_init_state() {
// .set_angle(-45)
// .set_speed({200, 10});
polygons[5] = poly_generate::regular(100, 5)
.set_angle(0)
.set_center({600, 650})
.set_speed({-200, 200});
// polygons[6] = poly_generate::regular(100, 5)
// .set_angle(0)
// .set_center({600, 650})
// .set_speed({-200, 200});
// .set_angle(0)
// .set_center({600, 650})
@ -63,33 +71,28 @@ void polygons_init_state() {
polygons[6] = poly_generate::general(
{{0, 0}, {100, 0}, {100, 100}, {50, 150}, {0, 100}}, 3)
.set_center({400, 400});
#elif PROBLEMATIC_COUPLES == 1
// for this problematic couple to work, remove the gravity
n_polygons = 7;
polygons[4] = poly_generate::regular(100, 3)
.set_center({103.91, 684.587})
.set_angle(280.108)
.set_speed({190.114, 131.983})
.set_angular_speed(32.6448);
#define PROBLEMATIC_COUPLES 0
polygons[5] = poly_generate::square(100)
.set_center({614.338, 514.889})
.set_angle(-54.3526)
.set_speed({-70.0347, -62.4788})
.set_angular_speed(-39.3846);
#if PROBLEMATIC_COUPLES == 1
// After about 20 secs (when they are both in the center at the bottom)
// the square hits the octogon with a high angular speed and they get stuck,
// why?
polygons[4] = poly_generate::square(100, 1)
.set_center({300, 180})
.set_angle(-60)
.set_speed({200, -10});
polygons[5] = poly_generate::regular(100, 8)
.set_center({600, 650})
.set_speed({-200, 200});
#endif
polygons[6] = poly_generate::general(
{{0, 0}, {100, 0}, {100, 100}, {50, 150}, {0, 100}}, 3)
.set_center({261.425, 556.613})
.set_angle(-122.59)
.set_speed({-46.9522, 48.5392})
.set_angular_speed(-35.5983);
#if PROBLEMATIC_COUPLES == 2
// After a couple of frames, I think we have the case were we have vertex
// colliding with vertex (and not the vertex vs edge we usually have)
polygons[4] = poly_generate::square(100, 1)
.set_angle(45)
.set_center({300, 650})
.set_angular_speed(181)
.set_speed({200, -10});
polygons[5] = poly_generate::regular(100, 8)
.set_center({600, 650})
.set_speed({-200, -10});
#endif
}
@ -142,15 +145,6 @@ static int8_t sign(double d) {
static void handle_collision(collision& c, polygon* a, polygon* b) {
// see https://www.myphysicslab.com/engine2D/collision-en.html for the
// formulas
// avoid the polygons getting stuck if, on the frame after the impact,
// the polygon a is still inside of b
// std::cout << "sign(v_a x n) = " << << std::endl;
if (vec2d::dot(a->speed, c.n) > 0 &&
vec2d::dot(a->speed, c.impact_point - a->centroid()) > 0 &&
sign(vec2d::cross(c.n, a->speed)) == -sign(a->angular_speed))
// might have to tweak this condition
return;
double omega_a1 = to_rad(a->angular_speed);
double omega_b1 = to_rad(b->angular_speed);
@ -168,6 +162,21 @@ static void handle_collision(collision& c, polygon* a, polygon* b) {
vec2d v_ab1 = v_ap1 - v_bp1;
// std::cout << " v_ab1 = " << v_ab1 << std::endl;
// avoid the polygons getting stuck if, on the frame after the impact,
// the polygon a is still inside of b
// std::cout << "sign(v_a x n) = " << << std::endl;
if (a->collided_with.find(b) != a->collided_with.end())
// if (vec2d::dot(v_ap1, v_bp1) < 0)
// might have to tweak this condition
{
std::cout << "Lol actually no, nevermind" << std::endl;
return;
}
a->collided_with.insert(b);
b->collided_with.insert(a);
double I_a = a->inertia, I_b = b->inertia;
// std::cout << " Parameters for j: " << std::endl;
// std::cout << " v_ab1 = " << v_ab1 << std::endl;
@ -205,6 +214,7 @@ collision col; // tbd
static void check_collisions(polygon* current_p) {
rect cur_bound = current_p->get_bounding_box();
bool collided_with_something = false;
for (polygon* other_p = polygons; other_p != polygons + n_polygons;
++other_p) {
if (other_p == current_p) // polygons don't collide with themselves
@ -215,19 +225,33 @@ static void check_collisions(polygon* current_p) {
// std::cout << "Bounding boxes do collide" << std::endl;
collision c = collides(*current_p, *other_p);
if (c.collides) {
collided_with_something = true;
col = c;
std::cout << "colliding" << std::endl;
std::cout << "speed before: " << current_p->speed << std::endl;
std::cout << "angular speed before: "
<< current_p->angular_speed << std::endl;
std::cout << "Between " << current_p->label << " and "
<< other_p->label << std::endl;
std::cout << "----- BEFORE -----" << std::endl;
std::cout << *current_p << std::endl;
std::cout << *other_p << std::endl;
handle_collision(c, current_p, other_p);
std::cout << "speed after: " << current_p->speed << std::endl;
std::cout << "angular speed after: " << current_p->angular_speed
<< std::endl;
std::cout << std::endl;
std::cout << "----- AFTER -----" << std::endl;
std::cout << *current_p << std::endl;
std::cout << *other_p << std::endl;
} else if (current_p->collided_with.find(other_p) !=
current_p->collided_with.end()) {
std::cout << "Removing shit" << std::endl;
current_p->collided_with.erase(other_p);
other_p->collided_with.erase(current_p);
// std::remove(current_p->collided_with.begin(),
// current_p->collided_with.end(),
// other_p);
// std::remove(other_p->collided_with.begin(),
// other_p->collided_with.end(),
// current_p);
}
}
}
if (!collided_with_something && current_p->collided_with.size() > 0)
current_p->collided_with.clear();
}
static void check_border_collision(polygon* p) {
@ -255,8 +279,12 @@ void polygons_update_state() {
continue;
// check_border_collision(p);
check_collisions(p);
p->rotate(delta * p->angular_speed);
p->angle = std::fmod(p->angle, 360);
p->translate(delta * p->speed);
// std::cout << *p << std::endl;
}
}
@ -311,6 +339,8 @@ void polygon::draw(cairo_t* cr) const {
// draw centroid
vec2d centroid = this->centroid();
draw_circle(cr, centroid, 1);
(10 * delta * this->speed).draw(cr, centroid);
}
void polygons_draw(cairo_t* cr) {