From 4d147e77de9ce9991e8a8390a61f98a2ff9a77e2 Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Tue, 25 Oct 2022 19:39:53 -0700 Subject: [PATCH] Add thruster block and thruster thrust --- gamestate.c | 74 ++++++++++++++++++++++++++++++-- loaded/box.png | Bin 1019 -> 0 bytes loaded/hullpiece.png | Bin 0 -> 5741 bytes loaded/thruster.png | Bin 0 -> 720 bytes main.c | 98 ++++++++++++++++++++++++++----------------- server.c | 5 +++ types.h | 59 ++++++++++++++++++++++++-- 7 files changed, 189 insertions(+), 47 deletions(-) delete mode 100644 loaded/box.png create mode 100644 loaded/hullpiece.png create mode 100644 loaded/thruster.png diff --git a/gamestate.c b/gamestate.c index c483775..64c79cd 100644 --- a/gamestate.c +++ b/gamestate.c @@ -217,7 +217,8 @@ float grid_angular_velocity(struct Grid *grid) V2 box_pos(struct Box *box) { struct Grid *g = (struct Grid *)cpBodyGetUserData(cpShapeGetBody(box->shape)); - return V2add(grid_pos(g), cp_to_v2(cpShapeGetCenterOfGravity(box->shape))); + V2 local_pos = cp_to_v2(cpShapeGetCenterOfGravity(box->shape)); + return V2add(grid_pos(g), V2rotate(local_pos, grid_rotation(g))); } float box_rotation(struct Box *box) { @@ -319,6 +320,10 @@ void ser_grid(char **out, struct Grid *g) if (exists) { ser_V2(out, cp_to_v2(cpShapeGetCenterOfGravity(g->boxes[i].shape))); + + ser_int(out, g->boxes[i].type); // @Robust separate enum serialization that checks for out of bounds enum + ser_int(out, g->boxes[i].rotation); + ser_float(out, g->boxes[i].thrust); ser_float(out, g->boxes[i].damage); } } @@ -353,6 +358,10 @@ void des_grid(char **in, struct Grid *g, struct GameState *gs) V2 pos = {0}; des_V2(in, &pos); box_new(&g->boxes[i], gs, g, pos); + + des_int(in, (int *)&g->boxes[i].type); + des_int(in, (int *)&g->boxes[i].rotation); + des_float(in, &g->boxes[i].thrust); des_float(in, &g->boxes[i].damage); } } @@ -529,6 +538,22 @@ static float hash11(float p) return fract(p); } +V2 thruster_direction(struct Box *box) +{ + assert(box->type == BoxThruster); + V2 to_return = (V2){.x = 1.0f, .y = 0.0f}; + + to_return = V2rotate(to_return, rotangle(box->rotation)); + to_return = V2rotate(to_return, box_rotation(box)); + + return to_return; +} + +V2 thruster_force(struct Box *box) +{ + return V2scale(thruster_direction(box), -box->thrust * THRUSTER_FORCE); +} + uint64_t tick(struct GameState *gs) { return (uint64_t)floor(gs->time / ((double)TIMESTEP)); @@ -618,6 +643,11 @@ void process(struct GameState *gs, float dt) // process movement { + // no cheating by making movement bigger than length 1 + if (V2length(p->movement) != 0.0f) + { + p->movement = V2scale(V2normalize(p->movement), clamp(V2length(p->movement), 0.0f, 1.0f)); + } if (p->currently_inhabiting_index == -1) { // @Robust make sure movement vector is normalized so player can't cheat @@ -628,10 +658,32 @@ void process(struct GameState *gs, float dt) { struct Grid *g = &gs->grids[p->currently_inhabiting_index]; V2 target_new_pos = V2lerp(p->pos, grid_com(g), dt * 20.0f); - p->vel = V2scale(V2sub(target_new_pos, p->pos), 1.0f / dt); - cpBodyApplyForceAtWorldPoint(g->body, v2_to_cp(V2scale(p->movement, 5.0f)), v2_to_cp(grid_com(g))); + p->vel = V2scale(V2sub(target_new_pos, p->pos), 1.0f / dt); // set vel correctly so newly built grids have the correct velocity copied from it + + // set thruster forces from movement + float thruster_spice_consumption = 0.0f; + { + V2 target_direction = {0}; + if (V2length(p->movement) > 0.0f) + { + target_direction = V2normalize(p->movement); + } + for (int ii = 0; ii < MAX_BOXES_PER_GRID; ii++) + { + SKIPNULL(g->boxes[ii].shape); + if (g->boxes[ii].type != BoxThruster) + continue; + + float wanted_thrust = -V2dot(target_direction, thruster_direction(&g->boxes[ii])); + wanted_thrust = clamp01(wanted_thrust); + thruster_spice_consumption += wanted_thrust; + g->boxes[ii].thrust = wanted_thrust; + } + } + + // cpBodyApplyForceAtWorldPoint(g->body, v2_to_cp(V2scale(p->movement, 5.0f)), v2_to_cp(grid_com(g))); // bigger the ship, the more efficient the spice usage - p->spice_taken_away += dt * 0.15f / (cpBodyGetMass(g->body) * 2.0f) * V2length(p->movement); + p->spice_taken_away += dt * thruster_spice_consumption * THRUSTER_SPICE_PER_SECOND; } p->pos = V2add(p->pos, V2scale(p->vel, dt)); } @@ -702,5 +754,19 @@ void process(struct GameState *gs, float dt) p->spice_taken_away = clamp01(p->spice_taken_away); } + // add thrust from thruster blocks + for (int i = 0; i < MAX_GRIDS; i++) + { + SKIPNULL(gs->grids[i].body); + for (int ii = 0; ii < MAX_BOXES_PER_GRID; ii++) + { + SKIPNULL(gs->grids[i].boxes[ii].shape); + if (gs->grids[i].boxes[ii].type == BoxThruster) + { + cpBodyApplyForceAtWorldPoint(gs->grids[i].body, v2_to_cp(thruster_force(&gs->grids[i].boxes[ii])), v2_to_cp(box_pos(&gs->grids[i].boxes[ii]))); + } + } + } + cpSpaceStep(gs->space, dt); } \ No newline at end of file diff --git a/loaded/box.png b/loaded/box.png deleted file mode 100644 index 2a8820d44847b0dfaa03cfe79d56dd613764f8b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1019 zcmVEX>4Tx04R}tkv&MmKpe$iQ$;Bi2Md1SkfFM0K~%(1s#pXIrLEAagUO{|(4-+r zad8w}3l4rPRvlcNb#-tR1i=pwM<*vm7b)?7NufoI2gm(*ckglc4iM^PrkWiSfT~$W zG8Ppx*;TRY6#)#QA7g;TOg)}jOv7`0-NVP%y9m$nKKJM7QF0~&d?N82(+!JwgLr1s z(mC%FhgeZkh|h_~4Z0xlBiCh@-#8Z>7Ik9zor9DjmbGPz1% zOtZfqj3;ujCMn4>00006VoOIv0LTE(0NUKs^3nhR010qNS#tmY zE+YT{E+YYWr9XB6000McNliru<_Z}XEF51k(4PPR02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00GlUL_t(o!|j(pZk#|AhrgK>^-2`JfEywWqR0WTl#;^I zy2u@}9S7Nt+#$toM;A+`cM8N1hMdb3O#^C$DYw9oHt5WLE zqk#P6L?_Tzow&QR(jL*ci?k<@g zYwhI80h*@4T00IK-Q93KRaG$;4(&5NzFy0+oXvnkTj_D6uIt$hxU`=bcRhx~pD$!Z4i8fJ6IUcg4uR-;*(T zo;P`N&+{&KJV_GbI39-|fc^4C p>C$ES;*H7w)0!>SoT{bU^S`sQAWaGx0mT3S002ovPDHLkV1h&%$2R}~ diff --git a/loaded/hullpiece.png b/loaded/hullpiece.png new file mode 100644 index 0000000000000000000000000000000000000000..920b032b92f562bd255485e1e487e359a3c274a5 GIT binary patch literal 5741 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 literal 0 HcmV?d00001 diff --git a/loaded/thruster.png b/loaded/thruster.png new file mode 100644 index 0000000000000000000000000000000000000000..f1c69ce95a981eab73d457631a1f52a8c4657b29 GIT binary patch literal 720 zcmV;>0x$iEP)EX>4Tx04R}tkv&MmKpe$iQ$;Bi2Md1SkfFM0K~%(1s#pXIrLEAagUO{|(4-+r zad8w}3l4rPRvlcNb#-tR1i=pwM<*vm7b)?7NufoI2gm(*ckglc4iM^PrkWiSfT~$W zG8Ppx*;TRY6#)#QA7g;TOg)}jOv7`0-NVP%y9m$nKKJM7QF0~&d?N82(+!JwgLr1s z(mC%FhgeZkh|h_~4Z0xlBiCh@-#8Z>7Ik9zor9DjmbGPz1% zOtZfqj3;ujCMn4>00006VoOIv0LTE(0NUKs^3nhR010qNS#tmY zE+YT{E+YYWr9XB6000McNliru<_a1C3^jro9DM))02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{005{-L_t(o!|j(b4uBvGMTKw{cQ>!(?&j>~?v>o!y^KyI z#9%3vwo5xh-lHM;ZPzK6qh37D>!#ivhu)C|{(y55K^pw7paCrkNPx2f6!0=n#WU-+ z!vb7jR0nF|t-z>H$OT0UaDqVr32-d0odqUf0w!Pr{wqGA2o>vqga|4PQ;F6&;nNWr zE7P(oPHQBK4|iHaDJUQzf)e1AsTSZ`&D57u^?CrGmQNw`zfau&0000 0.0f) { sgp_set_color(0.5f, 0.1f, 0.1f, damage); - sgp_draw_filled_rect(bpos.x - halfbox, bpos.y - halfbox, BOX_SIZE, BOX_SIZE); + sgp_draw_filled_rect(boxpos.x - halfbox, boxpos.y - halfbox, BOX_SIZE, BOX_SIZE); } sgp_pop_transform(); @@ -438,7 +453,6 @@ static void frame(void) float halfbox = BOX_SIZE / 2.0f; - // mouse if (mouse_frozen) { @@ -449,7 +463,7 @@ static void frame(void) // building preview { sgp_set_color(0.5f, 0.5f, 0.5f, (sin(time * 9.0f) + 1.0) / 3.0f + 0.2); - drawbox(build_preview.grid_pos, build_preview.grid_rotation, build_preview.pos, 0.0f, false); + drawbox(build_preview.pos, build_preview.grid_rotation, 0.0f, BoxHullpiece, Right); } // grids @@ -463,7 +477,14 @@ static void frame(void) SKIPNULL(g->boxes[ii].shape); struct Box *b = &g->boxes[ii]; sgp_set_color(0.5f, 0.5f, 0.5f, 1.0f); - drawbox(grid_pos(g), grid_rotation(g), box_pos(b), b->damage, true); + // debug draw force vectors for thrusters + if (false){ + if(b->type == BoxThruster) { + dbg_rect(box_pos(b)); + dbg_line(box_pos(b), V2add(box_pos(b), V2scale(thruster_force(b), -1.0f))); + } + } + drawbox(box_pos(b), grid_rotation(g), b->damage, b->type, b->rotation); } sgp_set_color(1.0f, 0.0f, 0.0f, 1.0f); V2 vel = grid_vel(&gs.grids[i]); @@ -499,7 +520,6 @@ static void frame(void) // sgp_draw_line(grid_pos(p->grid).x, grid_pos(p->grid).y, to.x, to.y); } - // gold target set_color(GOLD); sgp_draw_filled_rect(gs.goldpos.x, gs.goldpos.y, 0.1f, 0.1f); diff --git a/server.c b/server.c index df62796..3acbe9f 100644 --- a/server.c +++ b/server.c @@ -22,6 +22,11 @@ void server(void *data) box_new(&gs.grids[0].boxes[1], &gs, &gs.grids[0], (V2){0, BOX_SIZE}); box_new(&gs.grids[0].boxes[2], &gs, &gs.grids[0], (V2){0, BOX_SIZE*2.0}); box_new(&gs.grids[0].boxes[3], &gs, &gs.grids[0], (V2){BOX_SIZE, BOX_SIZE*2.0}); + gs.grids[0].boxes[3].type = BoxThruster; + gs.grids[0].boxes[3].rotation = Right; + box_new(&gs.grids[0].boxes[4], &gs, &gs.grids[0], (V2){0, BOX_SIZE*3.0}); + gs.grids[0].boxes[4].type = BoxThruster; + gs.grids[0].boxes[4].rotation = Up; grid_new(&gs.grids[1], &gs, (V2){.x = -BOX_SIZE*1.5, .y = 0.0}); box_new(&gs.grids[1].boxes[0], &gs, &gs.grids[1], (V2){0}); diff --git a/types.h b/types.h index 47a427f..c385240 100644 --- a/types.h +++ b/types.h @@ -8,6 +8,9 @@ #define BUILD_BOX_SNAP_DIST_TO_SHIP 0.2f #define MAX_BOXES_PER_GRID 32 #define BOX_MASS 1.0f +#define THRUSTER_FORCE 2.0f +#define THRUSTER_SPICE_PER_SECOND 0.1f + #define TIMESTEP (1.0f / 60.0f) // not required to simulate at this, but this defines what tick the game is on #define TIME_BETWEEN_INPUT_PACKETS (1.0f / 20.0f) #define SERVER_PORT 2551 @@ -19,6 +22,7 @@ // @Robust remove this include somehow, needed for sqrt and cos #include #include // tick is unsigned integer +#include // logging on errors for functions // including headers from headers bad #ifndef SOKOL_GP_INCLUDED @@ -80,7 +84,9 @@ struct GameState float goldness; // how much the player is a winner // input - V2 movement; + // @Cleanup make this a frameinput struct instead of copying over all the fields like this + + V2 movement; // can be at maximum length 1.0 bool inhabit; // if grid_index != -1, this is in local coordinates to the grid @@ -98,12 +104,54 @@ struct GameState struct Box { + enum BoxType + { + BoxHullpiece, + BoxThruster, + } type; + enum Rotation + { + Right, + Down, + Left, + Up, + } rotation; + + // thruster + float thrust; // must be between 0 and 1 + cpShape *shape; float damage; } boxes[MAX_BOXES_PER_GRID]; // @Robust this needs to be dynamically allocated, huge disparity in how many blocks a body can have... } grids[MAX_GRIDS]; }; +#define PI 3.14159f + +// returns in radians +static float rotangle(enum Rotation rot) +{ + switch(rot) + { + case Right: + return 0.0f; + break; + case Down: + return -PI/2.0f; + break; + case Left: + return -PI; + break; + case Up: + return -3.0f * PI/2.0f; + break; + default: + Log("Unknown rotation %d\n", rot); + return -0.0f; + break; + } +} + struct ServerToClient { struct GameState *cur_gs; @@ -154,6 +202,10 @@ void box_new(struct Box *to_modify, struct GameState *gs, struct Grid *grid, V2 V2 box_pos(struct Box *box); float box_rotation(struct Box *box); +// thruster +V2 thruster_direction(struct Box *box); +V2 thruster_force(struct Box *box); + // debug draw void dbg_drawall(); void dbg_line(V2 from, V2 to); @@ -166,7 +218,6 @@ 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) { @@ -244,9 +295,9 @@ static inline float clamp01(float f) static inline float clamp(float f, float minimum, float maximum) { - if(f < minimum) + if (f < minimum) return minimum; - if(f > maximum) + if (f > maximum) return maximum; return f; }