From 23c2e18a70c0e00d79da3c03b829b89b98d0c209 Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Fri, 14 Oct 2022 02:19:39 -0700 Subject: [PATCH] Some kind of physics? Something wrong... --- .vscode/settings.json | 3 +- gamestate.c | 95 +++++++++++++++++++++++++++++++++++++++++-- server.c | 6 ++- types.h | 41 ++++++++++++++++++- 4 files changed, 139 insertions(+), 6 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index bca0399..997c8bf 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,6 +28,7 @@ "stdbool.h": "c", "sokol_time.h": "c", "enet.h": "c", - "types.h": "c" + "types.h": "c", + "cmath": "c" } } \ No newline at end of file diff --git a/gamestate.c b/gamestate.c index 945a11c..85dbfc3 100644 --- a/gamestate.c +++ b/gamestate.c @@ -1,7 +1,23 @@ #include "types.h" +#include // malloc +#include + +void __assert(bool cond, const char * file, int line, const char * cond_string) +{ + if(!cond) + { + fprintf(stderr, "%s:%d | Assertion %s failed\n", file, line, cond_string); + } +} + +#define assert(condition) __assert(condition, __FILE__, __LINE__, #condition) + // do not use any global variables to process gamestate +// super try not to depend on external libraries like enet or sokol to keep build process simple, +// gamestate its own portable submodule. If need to link to other stuff document here: + static void integrate_acceleration(struct Body *body, float dt) { // position @@ -21,8 +37,31 @@ static void integrate_acceleration(struct Body *body, float dt) } } +static void modify_interval(struct Body *from, float *from_interval, V2 center, V2 axis) +{ + V2 points[4] = { + V2add(from->position, V2rotate((V2){.x = 0.5f, .y = -0.5f}, from->rotation)), // upper right + V2add(from->position, V2rotate((V2){.x = 0.5f, .y = 0.5f}, from->rotation)), // bottom right + V2add(from->position, V2rotate((V2){.x = -0.5f, .y = 0.5f}, from->rotation)), // lower left + V2add(from->position, V2rotate((V2){.x = -0.5f, .y = -0.5f}, 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]) + { + from_interval[0] = value; + } + } +} + void process(struct GameState *gs, float dt) { + int num_bodies = gs->num_boxes; for (int i = 0; i < MAX_PLAYERS; i++) { struct Player *p = &gs->players[i]; @@ -30,13 +69,63 @@ void process(struct GameState *gs, float dt) continue; p->body.acceleration = V2scale(p->input, 5.0f); p->body.angular_acceleration = p->input.x * 10.0f; - integrate_acceleration(&p->body, dt); + num_bodies += 1; + } + + // @Robust do this without malloc + struct Body **bodies = malloc(sizeof *bodies * num_bodies); + int cur_body_index = 0; + + for (int i = 0; i < MAX_PLAYERS; i++) + { + struct Player *p = &gs->players[i]; + if (!p->connected) + continue; + bodies[cur_body_index] = &p->body; + cur_body_index++; } for (int i = 0; i < gs->num_boxes; i++) { - integrate_acceleration(&gs->boxes[i].body, dt); + bodies[cur_body_index] = &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); + } + + // @Robust handle when bodies are overlapping (even perfectly) + for (int i = 0; i < num_bodies; i++) + { + for (int ii = 0; ii < num_bodies; ii++) + { + 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); + + 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]); + + if (to_interval[0] < from_interval[1]) // intersecting + { + from->position = V2add(from->position, V2scale(axis, -0.5f)); + to->position = V2add(from->position, V2scale(axis, 0.5f)); + } + } } - + free(bodies); } \ No newline at end of file diff --git a/server.c b/server.c index c0e44ce..e0445e7 100644 --- a/server.c +++ b/server.c @@ -92,7 +92,11 @@ void server(void *data) else { event.peer->data = (void *)player_slot; - gs.players[player_slot] = (struct Player){ 0 }; + gs.players[player_slot] = (struct Player){ .body.position = (V2){ + .x = 0.0f, + .y = 1.0f*(float)player_slot, + }}; + gs.players[player_slot].body.old_position = gs.players[player_slot].body.position; gs.players[player_slot].connected = true; } diff --git a/types.h b/types.h index 0ecb010..90c655f 100644 --- a/types.h +++ b/types.h @@ -1,5 +1,8 @@ #pragma once +// @Robust remove this include somehow, needed for sqrt and cos +#include + // including headers from headers bad #ifndef SOKOL_GP_INCLUDED @@ -25,7 +28,9 @@ typedef sgp_vec2 sgp_point; typedef sgp_vec2 V2; typedef sgp_point P2; -#define Log(...) fprintf(stdout, "%s:%d | ", __FILE__, __LINE__); fprintf(stdout, __VA_ARGS__) +#define Log(...) \ + fprintf(stdout, "%s:%d | ", __FILE__, __LINE__); \ + fprintf(stdout, __VA_ARGS__) #define MAX_BOXES 32 #define MAX_PLAYERS 4 #define BOX_SIZE 0.5f @@ -96,6 +101,40 @@ static V2 V2scale(V2 a, float f) }; } +static float V2length(V2 v) +{ + return sqrtf(v.x * v.x + v.y * v.y); +} + +static V2 V2normalize(V2 v) +{ + return V2scale(v, 1.0f / V2length(v)); +} + +static float V2dot(V2 a, V2 b) +{ + return a.x * b.x + a.y * b.y; +} + +static float V2projectvalue(V2 vec, V2 onto) +{ + float length_onto = V2length(onto); + return V2dot(vec, onto) / (length_onto * length_onto); +} + +static V2 V2project(V2 vec, V2 onto) +{ + return V2scale(onto, V2projectvalue(vec, onto)); +} + +static V2 V2rotate(V2 vec, float theta) +{ + return (V2){ + .x = vec.x * cos(theta) - vec.y * sin(theta), + .y = vec.x * sin(theta) + vec.y * cos(theta), + }; +} + static V2 V2sub(V2 a, V2 b) { return (V2){