diff --git a/.vscode/settings.json b/.vscode/settings.json
index 997c8bf..fc2cb77 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -29,6 +29,8 @@
"sokol_time.h": "c",
"enet.h": "c",
"types.h": "c",
- "cmath": "c"
+ "cmath": "c",
+ "math.h": "c",
+ "corecrt_math.h": "c"
}
}
\ No newline at end of file
diff --git a/flight.10x b/flight.10x
new file mode 100644
index 0000000..46eb060
--- /dev/null
+++ b/flight.10x
@@ -0,0 +1,46 @@
+
+
+
+ *.c,*.cc,*.cpp,*.c++,*.cp,*.cxx,*.h,*.hh,*.hpp,*.h++,*.hp,*.hxx,*.inl,*.cs,*.rs,*.java,*.jav,*.js,*.jsc,*.jsx,*.json,*.cls,*.py,*.rpy,*.php,*.php3,*.phl,*.phtml,*.rhtml,*.tpl,*.phps,*.lua,*.html,*.html5,*.htm,*.xml,*.xaml,*.css,*.ssi,*.haml,*.yaml,*.bat,*.wbf,*.wbt,*.txt,*.cmake,*.make,*.makefile,*.mak,*.mk,*.sh,*.bash,*.csv,*.asp,*.pl,*.mac,*.ws,*.vbs,*.perl,*.src,*.rss,*.inc,*.f,*.go,*.prl,*.plx,*.rb,*.lsp,*.lpx,*.ps1,*.command,*.cbl,*.cob,*.qs,*.wxs,*.ph,*.msc,*.glsl,*.hlsl,*.fx,*.vert,*.tesc,*.tese,*.geom,*.frag,*.comp,*.pssl,*.scons,
+
+ true
+ true
+ false
+ false
+ build_debug.bat
+
+
+
+
+ flight.exe
+ devenv.exe \Run $(Workspacefilename)
+
+
+
+ Debug
+ Release
+
+
+ x64
+ Win32
+
+
+
+
+
+ Debug:x64
+
+
+
+
+ Debug
+
+
+
+ x64
+
+
+
+
+
+
diff --git a/gamestate.c b/gamestate.c
index c160a3d..0f2dc6e 100644
--- a/gamestate.c
+++ b/gamestate.c
@@ -3,9 +3,9 @@
#include // malloc
#include
-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);
}
@@ -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 points[4] = {
- 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
- };
- for (int point_i = 0; point_i < 4; point_i++)
- {
- float value = V2projectvalue(V2sub(points[point_i], center), axis);
- if (value > from_interval[1])
- {
- from_interval[1] = value;
- }
- if (value < from_interval[0])
+ V2 vertices[4];
+ struct Body *body;
+};
+
+struct ProcessBody make_process_body(struct Body *from)
+{
+ float halfbox = BOX_SIZE / 2.0f;
+ struct ProcessBody to_return =
{
- 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)
{
+ // process input
int num_bodies = gs->num_boxes;
for (int i = 0; i < MAX_PLAYERS; i++)
{
@@ -76,7 +112,8 @@ void process(struct GameState *gs, float dt)
}
// @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;
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];
if (!p->connected)
continue;
- bodies[cur_body_index] = &p->body;
+ integrate_acceleration(&p->body, dt);
+ bodies[cur_body_index] = make_process_body(&p->body);
cur_body_index++;
}
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++;
}
assert(cur_body_index == num_bodies);
- for (int i = 0; i < num_bodies; i++)
- {
- struct Body *body = bodies[i];
- integrate_acceleration(body, dt);
- }
-
+ // Collision
// @Robust handle when bodies are overlapping (even perfectly)
for (int i = 0; i < num_bodies; i++)
{
@@ -109,35 +143,125 @@ void process(struct GameState *gs, float dt)
{
if (ii == i)
continue;
- struct Body *from = bodies[i];
- struct Body *to = bodies[ii];
-
- V2 axis = V2normalize(V2sub(to->position, from->position));
- V2 center = V2scale(V2add(to->position, from->position), 0.5f);
-
- dbg_line(from->position, to->position);
-
- dbg_rect(center);
-
- float from_interval[2] = {1000.0f, -1000.0f};
- float to_interval[2] = {1000.0f, -1000.0f};
- modify_interval(from, from_interval, center, axis);
- 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
-
- if (from_interval[1] > to_interval[0]) // intersecting
+ struct ProcessBody *from = &bodies[i];
+ struct ProcessBody *to = &bodies[ii];
+ dbg_line(from->body->position, to->body->position);
+
+ float MinDistance = 10000.0f;
+
+ struct Edge
+ {
+ struct ProcessBody *parent;
+ V2 *from;
+ V2 *to;
+ };
+
+ 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];
+
+ // 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 min_from, min_to, max_from, max_to = 0.0f;
+ project(from, axis, &min_from, &max_from);
+ project(to, axis, &min_to, &max_to);
+
+ float distance = interval_distance(min_from, min_to, max_from, max_to);
+
+ 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];
-
- from->position = V2add(from->position, V2scale(axis, intersection_depth*-0.5f));
- to->position = V2add(to->position, V2scale(axis, intersection_depth*0.5f));
+ 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];
+
+ V2 line = V2sub(*to, *from);
+ 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);
}
\ No newline at end of file
diff --git a/main.c b/main.c
index 0692f49..a58e1c4 100644
--- a/main.c
+++ b/main.c
@@ -158,6 +158,7 @@ static void frame(void)
ENetPacket *packet = enet_packet_create((void *)&curmsg, sizeof(curmsg), ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT);
enet_peer_send(peer, 0, packet);
+ // @BeforeShip client side prediction and rollback to previous server authoritative state, then replay inputs
process(&gs, (float)sapp_frame_duration());
}
diff --git a/types.h b/types.h
index 5203468..c349095 100644
--- a/types.h
+++ b/types.h
@@ -89,6 +89,8 @@ void dbg_rect(V2 center);
// all the math is static so that it can be defined in each compilation unit its included in
+#define PI 3.14159f
+
static V2 V2add(V2 a, V2 b)
{
return (V2){
@@ -139,6 +141,12 @@ static V2 V2rotate(V2 vec, float theta)
};
}
+// also known as atan2
+static float V2angle(V2 vec)
+{
+ return atan2f(vec.y, vec.x);
+}
+
static V2 V2sub(V2 a, V2 b)
{
return (V2){