|
|
|
@ -214,20 +214,36 @@ Vect get_normal(Vect start, Vect end) {
@@ -214,20 +214,36 @@ Vect get_normal(Vect start, Vect end) {
|
|
|
|
|
double y = (end.y - start.y); |
|
|
|
|
norm.x = -y; |
|
|
|
|
norm.y = x; |
|
|
|
|
double len = vect_mag(norm); |
|
|
|
|
norm.x /= len; |
|
|
|
|
norm.y /= len; |
|
|
|
|
|
|
|
|
|
return norm; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// reference:
|
|
|
|
|
// http://www.dyn4j.org/2010/01/sat/#sat-inter
|
|
|
|
|
//
|
|
|
|
|
// TODO: Maybe avoid calculating the centre of the boxes; have body->position
|
|
|
|
|
// be the centre and translate the collision box to be around that. It does
|
|
|
|
|
// make placing a little more complex but no bother.
|
|
|
|
|
bool sat_collision_check(Body *one, Body *two, Vect *translation) { |
|
|
|
|
int num_axes = one->collision_poly_size + two->collision_poly_size; |
|
|
|
|
Vect *axes = calloc(num_axes, sizeof(Vect)); |
|
|
|
|
|
|
|
|
|
Vect end; |
|
|
|
|
Vect start = one->collision_poly[0]; |
|
|
|
|
Vect one_position; |
|
|
|
|
Vect two_position; |
|
|
|
|
|
|
|
|
|
two_position = two->collision_poly[0]; |
|
|
|
|
one_position = one->collision_poly[0]; |
|
|
|
|
|
|
|
|
|
for (int i = 1; i < one->collision_poly_size; i++) { |
|
|
|
|
one_position = vect_add(one_position, one->collision_poly[i]); |
|
|
|
|
end = one->collision_poly[i]; |
|
|
|
|
axes[i-1] = get_normal(start, end); |
|
|
|
|
printf(".%d\n", i-1); |
|
|
|
@ -240,6 +256,7 @@ bool sat_collision_check(Body *one, Body *two, Vect *translation) {
@@ -240,6 +256,7 @@ bool sat_collision_check(Body *one, Body *two, Vect *translation) {
|
|
|
|
|
|
|
|
|
|
start = two->collision_poly[0]; |
|
|
|
|
for (int i = 1; i < two->collision_poly_size; i++) { |
|
|
|
|
two_position = vect_add(two_position, two->collision_poly[i]); |
|
|
|
|
end = two->collision_poly[i]; |
|
|
|
|
axes[i - 1 + one->collision_poly_size] = get_normal(start, end); |
|
|
|
|
printf(".%d\n", i-1 + one->collision_poly_size); |
|
|
|
@ -250,15 +267,6 @@ bool sat_collision_check(Body *one, Body *two, Vect *translation) {
@@ -250,15 +267,6 @@ bool sat_collision_check(Body *one, Body *two, Vect *translation) {
|
|
|
|
|
axes[two->collision_poly_size + one->collision_poly_size - 1] = get_normal(start, end); |
|
|
|
|
printf(".%d\n",two->collision_poly_size + one->collision_poly_size - 1); |
|
|
|
|
|
|
|
|
|
// normalise
|
|
|
|
|
for (int i = 0; i < num_axes; i++) { |
|
|
|
|
printf("AXIS TO CHECK :(num %d) %f %f\n", i, axes[i].x, axes[i].y); |
|
|
|
|
double len = vect_mag(axes[i]); |
|
|
|
|
axes[i].x = axes[i].x / len; |
|
|
|
|
axes[i].y = axes[i].y / len; |
|
|
|
|
printf("AXIS TO CHECK normed: %f %f\n", axes[i].x, axes[i].y); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
double *proj_one, *proj_two; |
|
|
|
|
proj_one = proj_two = 0; |
|
|
|
|
|
|
|
|
@ -289,17 +297,41 @@ bool sat_collision_check(Body *one, Body *two, Vect *translation) {
@@ -289,17 +297,41 @@ bool sat_collision_check(Body *one, Body *two, Vect *translation) {
|
|
|
|
|
double right = proj_one[0] > proj_two[0] ? proj_one[0] : proj_two[0]; |
|
|
|
|
overlap = left - right; |
|
|
|
|
printf("OVERLAP : %e\n", overlap); |
|
|
|
|
if (overlap < min_overlap) { |
|
|
|
|
if (overlap < min_overlap && overlap > 0) { |
|
|
|
|
min_overlap = overlap; |
|
|
|
|
min_axis = axes[i]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// return the MTV
|
|
|
|
|
// flip the MTV if it is pointing INTO the object
|
|
|
|
|
Vect trans; |
|
|
|
|
trans.x = min_overlap * min_axis.x; |
|
|
|
|
trans.y = min_overlap * min_axis.y; |
|
|
|
|
|
|
|
|
|
// https://gamedev.stackexchange.com/questions/27596/implementing-separating-axis-theorem-sat-and-minimum-translation-vector-mtv/27629#27629
|
|
|
|
|
Vect direction; |
|
|
|
|
one_position.x /= one->collision_poly_size; |
|
|
|
|
one_position.y /= one->collision_poly_size; |
|
|
|
|
two_position.x /= two->collision_poly_size; |
|
|
|
|
two_position.y /= two->collision_poly_size; |
|
|
|
|
|
|
|
|
|
printf("ONE POS: %f %f", one_position.x, one_position.y); |
|
|
|
|
printf("TWO POS: %f %f", two_position.x, one_position.y); |
|
|
|
|
|
|
|
|
|
direction.x = one_position.x - two_position.x; |
|
|
|
|
direction.y = one_position.y - two_position.y; |
|
|
|
|
|
|
|
|
|
double dot = vect_scalar_projection(trans, direction); |
|
|
|
|
|
|
|
|
|
printf("DIRECTION: %f %f\n\n", direction.x, direction.y); |
|
|
|
|
printf("DOT: %f\n\n", dot); |
|
|
|
|
|
|
|
|
|
if (dot > 0) { |
|
|
|
|
trans = vect_scalar(trans, -1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// return the MTV
|
|
|
|
|
*translation = trans; |
|
|
|
|
|
|
|
|
|
printf("Trans Vect: %e, %e\n", trans.x, trans.y); |
|
|
|
@ -440,31 +472,57 @@ void add_motor(Body *thing, double x, double y) {
@@ -440,31 +472,57 @@ void add_motor(Body *thing, double x, double y) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// basic collision handler for testing
|
|
|
|
|
int process_collisions(Body *thing, Vect **trans) { |
|
|
|
|
*trans = calloc(10, sizeof(Vect)); |
|
|
|
|
//
|
|
|
|
|
// TODO: Maybe adding all the MTVs together for the body will make it work better,
|
|
|
|
|
// will this solve the problem of negative normals? noo.. idk. But anyway it is more
|
|
|
|
|
// efficient for processing many collisions because you only do the physics for an
|
|
|
|
|
// MTV once rather than for all of the collisions separately.
|
|
|
|
|
int process_collisions(Body *thing, Vect *trans) { |
|
|
|
|
Vect translation; |
|
|
|
|
translation.x = translation.y = 0; |
|
|
|
|
Vect temptrans; |
|
|
|
|
int num_cols = 0; |
|
|
|
|
int num = 0; |
|
|
|
|
|
|
|
|
|
for (int k = 0; k < things_in_world; k++) { |
|
|
|
|
if (world[k].kind == STATIC_WALL_W
|
|
|
|
|
&& world[k].wall->physics->uid != thing->uid) { |
|
|
|
|
if (check_collision(world[k].wall->physics, thing, *trans + num_cols)) { |
|
|
|
|
num_cols++; |
|
|
|
|
if ((world[k].wall->physics->position.x - viewport_pos.x) > (width * 2)
|
|
|
|
|
|| world[k].wall->physics->position.x - viewport_pos.x < 0) { |
|
|
|
|
continue; |
|
|
|
|
} else { |
|
|
|
|
num++; |
|
|
|
|
} |
|
|
|
|
if (check_collision(world[k].wall->physics, thing, &temptrans)) { |
|
|
|
|
num++; |
|
|
|
|
thing->colliding = true; |
|
|
|
|
translation = vect_add(translation, temptrans); |
|
|
|
|
} |
|
|
|
|
} else if (world[k].kind == FLOOR) { |
|
|
|
|
for (int i = 0; i < world[k].floor->numPolys; i++) { |
|
|
|
|
if (check_collision(world[k].floor->polys[i].physics, thing, *trans + num_cols)) { |
|
|
|
|
if ((world[k].floor->polys[i].physics->position.x - viewport_pos.x) > (2 *width)
|
|
|
|
|
|| (world[k].floor->polys[i].physics->position.x - viewport_pos.x) < 0) {
|
|
|
|
|
continue; |
|
|
|
|
} else { |
|
|
|
|
num++; |
|
|
|
|
} |
|
|
|
|
if (check_collision(world[k].floor->polys[i].physics, thing, &temptrans)) { |
|
|
|
|
num_cols++; |
|
|
|
|
thing->colliding = true; |
|
|
|
|
translation = vect_add(translation, temptrans); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
printf("Tested %d collisions\n", num); |
|
|
|
|
|
|
|
|
|
if (!num_cols) { |
|
|
|
|
thing->colliding = false; |
|
|
|
|
free (*trans); |
|
|
|
|
return false; |
|
|
|
|
} else { |
|
|
|
|
return num_cols; |
|
|
|
|
*trans = translation; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -474,64 +532,71 @@ int process_collisions(Body *thing, Vect **trans) {
@@ -474,64 +532,71 @@ int process_collisions(Body *thing, Vect **trans) {
|
|
|
|
|
* object's position.
|
|
|
|
|
*/ |
|
|
|
|
void advance_thing(Body * thing) { |
|
|
|
|
// TODO: fix ordering of collision detection + physics sim so that collisions
|
|
|
|
|
// are less bad.
|
|
|
|
|
// TODO: Implement broad phase and narrow phase, else massively speed up collisions somehow.
|
|
|
|
|
thing->acc.x = 0; |
|
|
|
|
thing->acc.y = 0; |
|
|
|
|
|
|
|
|
|
printf("Position: %f %f\n", thing->position.x, thing->position.y); |
|
|
|
|
|
|
|
|
|
thing->updateCollisionPoly(thing); |
|
|
|
|
if (!thing->collision_poly[0].y) { |
|
|
|
|
thing->updateCollisionPoly(thing); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!thing->dynamics) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Vect *translations; |
|
|
|
|
thing->updateCollisionPoly(thing); |
|
|
|
|
Vect translation; |
|
|
|
|
translation.x = translation.y = 0; |
|
|
|
|
int numcols = 0; |
|
|
|
|
if ((numcols = process_collisions(thing, &translations))) { |
|
|
|
|
for (int i = 0; i < numcols; i++) { |
|
|
|
|
Vect translation = translations[i]; |
|
|
|
|
double mag = vect_mag(translation); |
|
|
|
|
|
|
|
|
|
double check = vect_scalar_projection(translation, thing->vel); |
|
|
|
|
if (check >= 0) { |
|
|
|
|
translation.x *= -1; |
|
|
|
|
translation.y *= -1; |
|
|
|
|
} |
|
|
|
|
if ((numcols = process_collisions(thing, &translation))) { |
|
|
|
|
double mag = vect_mag(translation); |
|
|
|
|
|
|
|
|
|
thing->position.x += translation.x; |
|
|
|
|
thing->position.y += translation.y; |
|
|
|
|
translation.x = translation.x / mag; |
|
|
|
|
translation.y = translation.y / mag; |
|
|
|
|
/*double check = vect_scalar_projection(translation, thing->vel);*/ |
|
|
|
|
/*if (check >= 0) {*/ |
|
|
|
|
/*translation.x *= -1;*/ |
|
|
|
|
/*translation.y *= -1;*/ |
|
|
|
|
/*}*/ |
|
|
|
|
|
|
|
|
|
mag = vect_scalar_projection(thing->vel, translation); |
|
|
|
|
thing->position.x += translation.x; |
|
|
|
|
thing->position.y += translation.y; |
|
|
|
|
|
|
|
|
|
Vect revert_vel; |
|
|
|
|
translation.x = translation.x / mag; |
|
|
|
|
translation.y = translation.y / mag; |
|
|
|
|
|
|
|
|
|
revert_vel.x = cos(vect_dir(translation)) * mag; |
|
|
|
|
revert_vel.y = sin(vect_dir(translation)) * mag; |
|
|
|
|
mag = vect_scalar_projection(thing->vel, translation); |
|
|
|
|
|
|
|
|
|
thing->vel.x -= revert_vel.x;
|
|
|
|
|
thing->vel.y -= revert_vel.y; |
|
|
|
|
Vect revert_vel; |
|
|
|
|
|
|
|
|
|
// restitution force
|
|
|
|
|
Vect rest; |
|
|
|
|
/*rest.x = 0;*/ |
|
|
|
|
/*rest.y = 0;*/ |
|
|
|
|
/*double impulse = thing->obj_mass * vect_mag(thing->vel) * thing->obj_elasticity;*/ |
|
|
|
|
/*rest.x = cos(vect_dir(translation)) * impulse;*/ |
|
|
|
|
/*rest.y = sin(vect_dir(translation)) * impulse;*/ |
|
|
|
|
/*accel_thing(thing, rest.x, rest.y);*/ |
|
|
|
|
revert_vel.x = cos(vect_dir(translation)) * mag; |
|
|
|
|
revert_vel.y = sin(vect_dir(translation)) * mag; |
|
|
|
|
|
|
|
|
|
thing->vel.x -= revert_vel.x;
|
|
|
|
|
thing->vel.y -= revert_vel.y; |
|
|
|
|
|
|
|
|
|
// restitution force
|
|
|
|
|
Vect rest; |
|
|
|
|
/*rest.x = 0;*/ |
|
|
|
|
/*rest.y = 0;*/ |
|
|
|
|
/*double impulse = thing->obj_mass * vect_mag(thing->vel) * thing->obj_elasticity;*/ |
|
|
|
|
/*rest.x = cos(vect_dir(translation)) * impulse;*/ |
|
|
|
|
/*rest.y = sin(vect_dir(translation)) * impulse;*/ |
|
|
|
|
/*accel_thing(thing, rest.x, rest.y);*/ |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
free(translations); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
uint32_t now = SDL_GetTicks(); |
|
|
|
|
|
|
|
|
|
uint32_t time_delta = now - thing->last_advance_time ; |
|
|
|
|
thing->last_advance_time = SDL_GetTicks(); // in milliseconds
|
|
|
|
|
time_delta = 15; |
|
|
|
|
if (time_delta > 18) { |
|
|
|
|
logwrite(ERROR, "Simulation too slow\n"); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// motors
|
|
|
|
|
for (int i = 0; i < thing->num_motors; i++) { |
|
|
|
@ -599,7 +664,6 @@ void advance_thing(Body * thing) {
@@ -599,7 +664,6 @@ void advance_thing(Body * thing) {
|
|
|
|
|
thing->position.y += (thing->vel.y * 1/2 * (double)time_delta);
|
|
|
|
|
|
|
|
|
|
// revert if this caused collision
|
|
|
|
|
thing->updateCollisionPoly(thing); |
|
|
|
|
/*if (process_collisions(thing)) {*/ |
|
|
|
|
/*thing->x_pos = oldx;*/ |
|
|
|
|
/*thing->y_pos = oldy;*/ |
|
|
|
@ -685,7 +749,7 @@ void startgame(SDL_Renderer * ren) {
@@ -685,7 +749,7 @@ void startgame(SDL_Renderer * ren) {
|
|
|
|
|
memset(world, 0, sizeof(world_thing) * 100); |
|
|
|
|
SDL_GetRendererOutputSize(ren, &width, &height); |
|
|
|
|
|
|
|
|
|
player = get_player(700,600); |
|
|
|
|
player = get_player(20 * width,600); |
|
|
|
|
|
|
|
|
|
world_thing player_world; |
|
|
|
|
|
|
|
|
@ -714,7 +778,7 @@ float get_abs(float x,float y) {
@@ -714,7 +778,7 @@ float get_abs(float x,float y) {
|
|
|
|
|
|
|
|
|
|
void walk_player(int x, int y) { |
|
|
|
|
if (y == -1) { |
|
|
|
|
add_motor_newtons(glob_player->physics, M_PLAYER_WALK, 0, 100 * y); |
|
|
|
|
add_motor_newtons(glob_player->physics, M_PLAYER_WALK, 0, 100 * 10 * y); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
add_motor_newtons(glob_player->physics, M_PLAYER_WALK, 100 * x , 100 * y); |
|
|
|
|