|
|
@ -3,9 +3,9 @@
|
|
|
|
#include <stdlib.h> // malloc
|
|
|
|
#include <stdlib.h> // malloc
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
|
|
void __assert(bool cond, const char * file, int line, const char * cond_string)
|
|
|
|
void __assert(bool cond, const char *file, int line, const char *cond_string)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if(!cond)
|
|
|
|
if (!cond)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
fprintf(stderr, "%s:%d | Assertion %s failed\n", file, line, cond_string);
|
|
|
|
fprintf(stderr, "%s:%d | Assertion %s failed\n", file, line, cond_string);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -38,32 +38,68 @@ static void integrate_acceleration(struct Body *body, float dt)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void modify_interval(struct Body *from, float *from_interval, V2 center, V2 axis)
|
|
|
|
struct ProcessBody
|
|
|
|
{
|
|
|
|
{
|
|
|
|
float halfbox = BOX_SIZE/2.0f;
|
|
|
|
V2 vertices[4];
|
|
|
|
V2 points[4] = {
|
|
|
|
struct Body *body;
|
|
|
|
V2add(from->position, V2rotate((V2){.x = halfbox, .y = -halfbox}, from->rotation)), // upper right
|
|
|
|
};
|
|
|
|
V2add(from->position, V2rotate((V2){.x = halfbox, .y = halfbox}, from->rotation)), // bottom right
|
|
|
|
|
|
|
|
V2add(from->position, V2rotate((V2){.x = -halfbox, .y = halfbox}, from->rotation)), // lower left
|
|
|
|
struct ProcessBody make_process_body(struct Body *from)
|
|
|
|
V2add(from->position, V2rotate((V2){.x = -halfbox, .y = -halfbox}, from->rotation)), // upper left
|
|
|
|
{
|
|
|
|
};
|
|
|
|
float halfbox = BOX_SIZE / 2.0f;
|
|
|
|
for (int point_i = 0; point_i < 4; point_i++)
|
|
|
|
struct ProcessBody to_return =
|
|
|
|
{
|
|
|
|
|
|
|
|
float value = V2projectvalue(V2sub(points[point_i], center), axis);
|
|
|
|
|
|
|
|
if (value > from_interval[1])
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
from_interval[1] = value;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value < from_interval[0])
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
from_interval[0] = value;
|
|
|
|
.vertices = {
|
|
|
|
}
|
|
|
|
// important that the first one is the upper right, used to deduce rotation from vertex position
|
|
|
|
|
|
|
|
// @Robust instead of array of vertices have type? like struct with upper_right upper_left etc
|
|
|
|
|
|
|
|
V2add(from->position, V2rotate((V2){.x = halfbox, .y = -halfbox}, from->rotation)), // upper right
|
|
|
|
|
|
|
|
V2add(from->position, V2rotate((V2){.x = halfbox, .y = halfbox}, from->rotation)), // bottom right
|
|
|
|
|
|
|
|
V2add(from->position, V2rotate((V2){.x = -halfbox, .y = halfbox}, from->rotation)), // lower left
|
|
|
|
|
|
|
|
V2add(from->position, V2rotate((V2){.x = -halfbox, .y = -halfbox}, from->rotation)), // upper left
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
.body = from,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
return to_return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void project(struct ProcessBody *from, V2 axis, float *min, float *max)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
float DotP = V2dot(axis, from->vertices[0]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set the minimum and maximum values to the projection of the first vertex
|
|
|
|
|
|
|
|
*min = DotP;
|
|
|
|
|
|
|
|
*max = DotP;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (int I = 1; I < 4; I++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
// Project the rest of the vertices onto the axis and extend
|
|
|
|
|
|
|
|
// the interval to the left/right if necessary
|
|
|
|
|
|
|
|
DotP = V2dot(axis, from->vertices[I]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*min = fmin(DotP, *min);
|
|
|
|
|
|
|
|
*max = fmax(DotP, *max);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static float interval_distance(float min_a, float max_a, float min_b, float max_b)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (min_a < min_b)
|
|
|
|
|
|
|
|
return min_b - max_a;
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
return min_a - max_b;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void move_vertices(V2 *vertices, int num, V2 shift)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
for (int i = 0; i < num; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
vertices[i] = V2add(vertices[i], shift);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void process(struct GameState *gs, float dt)
|
|
|
|
void process(struct GameState *gs, float dt)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
// process input
|
|
|
|
int num_bodies = gs->num_boxes;
|
|
|
|
int num_bodies = gs->num_boxes;
|
|
|
|
for (int i = 0; i < MAX_PLAYERS; i++)
|
|
|
|
for (int i = 0; i < MAX_PLAYERS; i++)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -76,7 +112,8 @@ void process(struct GameState *gs, float dt)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// @Robust do this without malloc
|
|
|
|
// @Robust do this without malloc
|
|
|
|
struct Body **bodies = malloc(sizeof *bodies * num_bodies);
|
|
|
|
|
|
|
|
|
|
|
|
struct ProcessBody *bodies = malloc(sizeof *bodies * num_bodies);
|
|
|
|
int cur_body_index = 0;
|
|
|
|
int cur_body_index = 0;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < MAX_PLAYERS; i++)
|
|
|
|
for (int i = 0; i < MAX_PLAYERS; i++)
|
|
|
@ -84,24 +121,21 @@ void process(struct GameState *gs, float dt)
|
|
|
|
struct Player *p = &gs->players[i];
|
|
|
|
struct Player *p = &gs->players[i];
|
|
|
|
if (!p->connected)
|
|
|
|
if (!p->connected)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
bodies[cur_body_index] = &p->body;
|
|
|
|
integrate_acceleration(&p->body, dt);
|
|
|
|
|
|
|
|
bodies[cur_body_index] = make_process_body(&p->body);
|
|
|
|
cur_body_index++;
|
|
|
|
cur_body_index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < gs->num_boxes; i++)
|
|
|
|
for (int i = 0; i < gs->num_boxes; i++)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
bodies[cur_body_index] = &gs->boxes[i].body;
|
|
|
|
integrate_acceleration(&gs->boxes[i].body, dt);
|
|
|
|
|
|
|
|
bodies[cur_body_index] = make_process_body(&gs->boxes[i].body);
|
|
|
|
cur_body_index++;
|
|
|
|
cur_body_index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assert(cur_body_index == num_bodies);
|
|
|
|
assert(cur_body_index == num_bodies);
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < num_bodies; i++)
|
|
|
|
// Collision
|
|
|
|
{
|
|
|
|
|
|
|
|
struct Body *body = bodies[i];
|
|
|
|
|
|
|
|
integrate_acceleration(body, dt);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// @Robust handle when bodies are overlapping (even perfectly)
|
|
|
|
// @Robust handle when bodies are overlapping (even perfectly)
|
|
|
|
for (int i = 0; i < num_bodies; i++)
|
|
|
|
for (int i = 0; i < num_bodies; i++)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -109,35 +143,125 @@ void process(struct GameState *gs, float dt)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (ii == i)
|
|
|
|
if (ii == i)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
struct Body *from = bodies[i];
|
|
|
|
struct ProcessBody *from = &bodies[i];
|
|
|
|
struct Body *to = bodies[ii];
|
|
|
|
struct ProcessBody *to = &bodies[ii];
|
|
|
|
|
|
|
|
dbg_line(from->body->position, to->body->position);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
float MinDistance = 10000.0f;
|
|
|
|
|
|
|
|
|
|
|
|
V2 axis = V2normalize(V2sub(to->position, from->position));
|
|
|
|
struct Edge
|
|
|
|
V2 center = V2scale(V2add(to->position, from->position), 0.5f);
|
|
|
|
{
|
|
|
|
|
|
|
|
struct ProcessBody *parent;
|
|
|
|
|
|
|
|
V2 *from;
|
|
|
|
|
|
|
|
V2 *to;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
dbg_line(from->position, to->position);
|
|
|
|
struct ProcessBody *bodies[2] = {from, to};
|
|
|
|
|
|
|
|
bool was_collision = false;
|
|
|
|
|
|
|
|
V2 normal = {0};
|
|
|
|
|
|
|
|
struct Edge edge = {0};
|
|
|
|
|
|
|
|
for (int body_i = 0; body_i < 2; body_i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
struct ProcessBody *body = bodies[body_i];
|
|
|
|
|
|
|
|
for (int edge_from_i = 0; edge_from_i < 3; edge_from_i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int edge_to_i = edge_from_i + 1;
|
|
|
|
|
|
|
|
V2 *edge_from = &body->vertices[edge_from_i];
|
|
|
|
|
|
|
|
V2 *edge_to = &body->vertices[edge_to_i];
|
|
|
|
|
|
|
|
|
|
|
|
dbg_rect(center);
|
|
|
|
// normal vector of edge
|
|
|
|
|
|
|
|
V2 axis = (V2){
|
|
|
|
|
|
|
|
.x = edge_from->y - edge_to->y,
|
|
|
|
|
|
|
|
.y = edge_to->x - edge_from->x,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
axis = V2normalize(axis);
|
|
|
|
|
|
|
|
|
|
|
|
float from_interval[2] = {1000.0f, -1000.0f};
|
|
|
|
float min_from, min_to, max_from, max_to = 0.0f;
|
|
|
|
float to_interval[2] = {1000.0f, -1000.0f};
|
|
|
|
project(from, axis, &min_from, &max_from);
|
|
|
|
modify_interval(from, from_interval, center, axis);
|
|
|
|
project(to, axis, &min_to, &max_to);
|
|
|
|
modify_interval(to, to_interval, center, axis);
|
|
|
|
|
|
|
|
assert(from_interval[0] < from_interval[1]);
|
|
|
|
|
|
|
|
assert(to_interval[0] < to_interval[1]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// @BeforeShip debug compile time flag in preprocessor
|
|
|
|
float distance = interval_distance(min_from, min_to, max_from, max_to);
|
|
|
|
|
|
|
|
|
|
|
|
if (from_interval[1] > to_interval[0]) // intersecting
|
|
|
|
if (distance > 0.0f)
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
else if (fabsf(distance) < MinDistance)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
MinDistance = fabsf(distance);
|
|
|
|
|
|
|
|
was_collision = true;
|
|
|
|
|
|
|
|
normal = axis;
|
|
|
|
|
|
|
|
edge = (struct Edge){
|
|
|
|
|
|
|
|
.parent = &body,
|
|
|
|
|
|
|
|
.from = edge_from,
|
|
|
|
|
|
|
|
.to = edge_to,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
float depth = MinDistance;
|
|
|
|
|
|
|
|
if (was_collision)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
float intersection_depth = from_interval[1] - to_interval[0];
|
|
|
|
float intersection_depth = from_interval[1] - to_interval[0];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
move_vertices(from->vertices, 4, V2scale(axis, intersection_depth * -0.5f));
|
|
|
|
|
|
|
|
move_vertices(to->vertices, 4, V2scale(axis, intersection_depth * 0.5f));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Wall
|
|
|
|
|
|
|
|
if (true)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
for (int i = 0; i < num_bodies; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
for (int v_i = 0; v_i < 4; v_i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
V2 *vert = &bodies[i].vertices[v_i];
|
|
|
|
|
|
|
|
if (vert->x > 2.0f)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
vert->x = 2.0f;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Correct for differences in vertex position
|
|
|
|
|
|
|
|
const int edge_update_iters = 3;
|
|
|
|
|
|
|
|
for (int iter = 0; iter < edge_update_iters; iter++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
for (int i = 0; i < num_bodies; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
for (int v_i = 0; v_i < 3; v_i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
int other_v_i = v_i + 1;
|
|
|
|
|
|
|
|
V2 *from = &bodies[i].vertices[v_i];
|
|
|
|
|
|
|
|
V2 *to = &bodies[i].vertices[other_v_i];
|
|
|
|
|
|
|
|
|
|
|
|
from->position = V2add(from->position, V2scale(axis, intersection_depth*-0.5f));
|
|
|
|
V2 line = V2sub(*to, *from);
|
|
|
|
to->position = V2add(to->position, V2scale(axis, intersection_depth*0.5f));
|
|
|
|
float len = V2length(line);
|
|
|
|
|
|
|
|
float diff = len - BOX_SIZE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
line = V2normalize(line);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*from = V2add(*from, V2scale(line, diff * 0.5f));
|
|
|
|
|
|
|
|
*to = V2sub(*to, V2scale(line, diff * 0.5f));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Reupdate the positions of the bodies based on how the vertices changed
|
|
|
|
|
|
|
|
for (int i = 0; i < num_bodies; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
float upper_right_angle = V2angle(V2sub(bodies[i].vertices[0], bodies[i].body->position));
|
|
|
|
|
|
|
|
bodies[i].body->rotation = upper_right_angle - (PI / 4.0f);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
V2 avg = {0};
|
|
|
|
|
|
|
|
for (int v_i = 0; v_i < 4; v_i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
avg = V2add(avg, bodies[i].vertices[v_i]);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
avg = V2scale(avg, 1.0f / 4.0f);
|
|
|
|
|
|
|
|
bodies[i].body->position = avg;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
free(bodies);
|
|
|
|
free(bodies);
|
|
|
|
}
|
|
|
|
}
|