From 547727c7f32c90f1a67a76d8e43916c02334acd8 Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Wed, 26 Oct 2022 09:40:20 -0700 Subject: [PATCH] Thruster placing/rotate, toolbar UI --- gamestate.c | 77 +++++---- loaded/itemframe.png | Bin 0 -> 635 bytes loaded/itemframe_selected.png | Bin 0 -> 649 bytes main.c | 313 ++++++++++++++++++++++------------ server.c | 14 +- types.h | 115 +++++++------ 6 files changed, 324 insertions(+), 195 deletions(-) create mode 100644 loaded/itemframe.png create mode 100644 loaded/itemframe_selected.png diff --git a/gamestate.c b/gamestate.c index 64c79cd..270887e 100644 --- a/gamestate.c +++ b/gamestate.c @@ -367,6 +367,30 @@ void des_grid(char **in, struct Grid *g, struct GameState *gs) } } +void ser_inputframe(char **out, struct InputFrame *i) +{ + ser_V2(out, i->movement); + ser_bool(out, i->inhabit); + + ser_V2(out, i->build); + ser_bool(out, i->dobuild); + ser_int(out, i->build_type); + ser_int(out, i->build_rotation); + ser_int(out, i->grid_index); +} + +void des_inputframe(char **in, struct InputFrame *i) +{ + des_V2(in, &i->movement); + des_bool(in, &i->inhabit); + + des_V2(in, &i->build); + des_bool(in, &i->dobuild); + des_int(in, (int *)&i->build_type); + des_int(in, (int *)&i->build_rotation); + des_int(in, &i->grid_index); +} + void ser_player(char **out, struct Player *p) { ser_bool(out, p->connected); @@ -378,13 +402,7 @@ void ser_player(char **out, struct Player *p) ser_float(out, p->spice_taken_away); ser_float(out, p->goldness); - // input - ser_V2(out, p->movement); - ser_bool(out, p->inhabit); - - ser_V2(out, p->build); - ser_bool(out, p->dobuild); - ser_int(out, p->grid_index); + ser_inputframe(out, &p->input); } } @@ -399,13 +417,7 @@ void des_player(char **in, struct Player *p, struct GameState *gs) des_float(in, &p->spice_taken_away); des_float(in, &p->goldness); - // input - des_V2(in, &p->movement); - des_bool(in, &p->inhabit); - - des_V2(in, &p->build); - des_bool(in, &p->dobuild); - des_int(in, &p->grid_index); + des_inputframe(in, &p->input); } } @@ -586,9 +598,9 @@ void process(struct GameState *gs, float dt) p->currently_inhabiting_index = -1; } - if (p->inhabit) + if (p->input.inhabit) { - p->inhabit = false; // "handle" the input + p->input.inhabit = false; // "handle" the input if (p->currently_inhabiting_index == -1) { @@ -644,15 +656,15 @@ void process(struct GameState *gs, float dt) // process movement { // no cheating by making movement bigger than length 1 - if (V2length(p->movement) != 0.0f) + if (V2length(p->input.movement) != 0.0f) { - p->movement = V2scale(V2normalize(p->movement), clamp(V2length(p->movement), 0.0f, 1.0f)); + p->input.movement = V2scale(V2normalize(p->input.movement), clamp(V2length(p->input.movement), 0.0f, 1.0f)); } if (p->currently_inhabiting_index == -1) { // @Robust make sure movement vector is normalized so player can't cheat - p->vel = V2add(p->vel, V2scale(p->movement, dt * 0.5f)); - p->spice_taken_away += dt * 0.15f * V2length(p->movement); + p->vel = V2add(p->vel, V2scale(p->input.movement, dt * 0.5f)); + p->spice_taken_away += dt * 0.15f * V2length(p->input.movement); } else { @@ -664,9 +676,9 @@ void process(struct GameState *gs, float dt) float thruster_spice_consumption = 0.0f; { V2 target_direction = {0}; - if (V2length(p->movement) > 0.0f) + if (V2length(p->input.movement) > 0.0f) { - target_direction = V2normalize(p->movement); + target_direction = V2normalize(p->input.movement); } for (int ii = 0; ii < MAX_BOXES_PER_GRID; ii++) { @@ -681,23 +693,23 @@ void process(struct GameState *gs, float dt) } } - // cpBodyApplyForceAtWorldPoint(g->body, v2_to_cp(V2scale(p->movement, 5.0f)), v2_to_cp(grid_com(g))); + // cpBodyApplyForceAtWorldPoint(g->body, v2_to_cp(V2scale(p->input.movement, 5.0f)), v2_to_cp(grid_com(g))); // bigger the ship, the more efficient the spice usage p->spice_taken_away += dt * thruster_spice_consumption * THRUSTER_SPICE_PER_SECOND; } p->pos = V2add(p->pos, V2scale(p->vel, dt)); } - if (p->dobuild) + if (p->input.dobuild) { - p->dobuild = false; // handle the input. if didn't do this, after destruction of hovered box, would try to build on its grid with grid_index... + p->input.dobuild = false; // handle the input. if didn't do this, after destruction of hovered box, would try to build on its grid with grid_index... cpPointQueryInfo info = {0}; // @Robust make sure to query only against boxes... - V2 world_build = p->build; - if (p->grid_index != -1) + V2 world_build = p->input.build; + if (p->input.grid_index != -1) { - world_build = grid_local_to_world(&gs->grids[p->grid_index], p->build); + world_build = grid_local_to_world(&gs->grids[p->input.grid_index], p->input.build); } cpShape *nearest = cpSpacePointQueryNearest(gs->space, v2_to_cp(world_build), 0.01f, cpShapeFilterNew(CP_NO_GROUP, CP_ALL_CATEGORIES, CP_ALL_CATEGORIES), &info); if (nearest != NULL) @@ -707,7 +719,7 @@ void process(struct GameState *gs, float dt) grid_remove_box(gs->space, cur_grid, cur_box); p->spice_taken_away -= 0.1f; } - else if (p->grid_index == -1) + else if (p->input.grid_index == -1) { // @Robust better memory mgmt struct Grid *empty_grid = NULL; @@ -719,15 +731,18 @@ void process(struct GameState *gs, float dt) break; } } + // @Robust cleanly fail when not enough grids assert(empty_grid != NULL); p->spice_taken_away += 0.2f; grid_new(empty_grid, gs, world_build); box_new(&empty_grid->boxes[0], gs, empty_grid, (V2){0}); + empty_grid->boxes[0].type = p->input.build_type; + empty_grid->boxes[0].rotation = p->input.build_rotation; cpBodySetVelocity(empty_grid->body, v2_to_cp(p->vel)); } else { - struct Grid *g = &gs->grids[p->grid_index]; + struct Grid *g = &gs->grids[p->input.grid_index]; struct Box *empty_box = NULL; for (int ii = 0; ii < MAX_BOXES_PER_GRID; ii++) @@ -742,6 +757,8 @@ void process(struct GameState *gs, float dt) assert(empty_box != NULL); p->spice_taken_away += 0.1f; box_new(empty_box, gs, g, grid_world_to_local(g, world_build)); + empty_box->type = p->input.build_type; + empty_box->rotation = p->input.build_rotation; } } diff --git a/loaded/itemframe.png b/loaded/itemframe.png new file mode 100644 index 0000000000000000000000000000000000000000..4dc05b0aa6d5a991a4fe382a4ffffeb1eec9470c GIT binary patch literal 635 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=hEVFt%noI|q0=J1Z0v<)>xlq%tsQ zOst(~>v7mY=4gEM(x6p*WfLAvSokW*F~nugk}lT`0k^o;TFr?0#p)|HNkrWJ;MNBZ zjwf9`cr-GcJ={^?4?|%|QBcW5q5soGqK;G)-03g>E?54ZA%F29k;U0E0U^QuN0Xh* zwrl-}7j%%QopE%<2_D^vac2&c*4#aO`1)>*^F{XGpTC&;nT^?o>7&f$lF1d#6;+q7 zSiBc*kMNw*dA{>_$u5PD%GXuf?^}rHe*1K0!aUEj!tEWcN$lRTXS{Yf*|^F~6rK8M zZ)AJwx#&4ly?VF4I~gx=X0>+ay2~<7GTt5voQy(Q8jG2P1EWHNc$Q??KYPS~`=82A zm7=K!Pi$<^66x3`|A)V>JX=Ifea?~uo)>i+*YqbI*w1b9dfM08oXE4n2fp*ftjw+7 z%6O(`Qe1xaMCAqb(mQtKWnYpj*vZUem$^vq)};Pr+XEQxoqsXA=)eJ8fr#R&?6;4< zFrEkqKW%>CprS$0k~gK(%fFX=`}TfjSiSwfxkdLcf8n16j2E^fZ+904XArEG+!YEG z;VkfoEM{QPQwCwiilz2tKtc8rPhVH|XIxVJEaFq`e$567NtU=qlsM<-=BDPAFgO>b zCYGe8D3oWGWGJ|M`UZqI@`(c#1$nwShD02Gd)<()!GOp4Vnb29L=g}F%g)nX6Cx&i z{hhbzr{}yPk6G7dT%PrK{cpW@=kyOKC54!H@0vCfs2vIXd7u1};mI^%o4K}JeP3@q Qxek)^boFyt=akR{0R1us!~g&Q literal 0 HcmV?d00001 diff --git a/loaded/itemframe_selected.png b/loaded/itemframe_selected.png new file mode 100644 index 0000000000000000000000000000000000000000..5e1d512d8f3911c6165d1e72beaf570125a1353e GIT binary patch literal 649 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=hEVFt%noI|q0=J1Z0v<)>xlq%tsQ zOst(~>v7mY=4gEM(x6p*WfLAvSokW*F~nugk}lT`0k^o;TFr?0#p)|HNkrWJ;MNBZ zjwf9`cr-GcJ={^?4?|%|QBcW5q5soGqK;G)-03g>E?54ZA%F29k;U0E0U^QuN0Xh* zwrl-}7j%%QopE%<2_D^vac2&c*4#aO`1)>*^F{XGpTC&;nT^?o>7&f$lF1d#6;+q7 zSiBc*kMNw*dA{>_$u5PD%GXuf?^}rHe*1K0!aUEj!tEWcN$lRTXS{Yf*|^F~6rK8M zZ)AJwx#&4ly?VF4I~gx=X0>+ay2~<7GTt5voQy(Q8jG2P1EWHNc$Q??KYPS~`=82A zm7=K!Pi$<^66x3`|A)V>JX=Ifea?~uo)>i+*YqbI*w1b9dfM08oXE4n2fp*ftjw+7 z%6O(`Qe1xaMCAqb(mQtKWnYpj*vZUem$^vq)};Pr+XEQxoqsXA=)eJ8fr#R&?6;4< zFrEkqKW%>CprS$0k~gK(%fFX=`}TfjSiSwfxkdLcf8n16j2E^fZ+904XArEG+!YEG z;VkfoEM{QPQwCwiilz2tKtc8rPhVH|XIxVJELvy7wsir8BuiW)N}Tg^b5rw57@Uhz z6H8K46v{J8G8EiBeFMT9`NV;W5FlV|DJf@I fv)=5{A_jkC0O?VJ4zXcvR0tDnm{r-UW|s+kSu literal 0 HcmV?d00001 diff --git a/main.c b/main.c index e09097c..a1bf25c 100644 --- a/main.c +++ b/main.c @@ -39,8 +39,37 @@ static ENetHost *client; static ENetPeer *peer; static float zoom_target = 300.0f; static float zoom = 300.0f; -static sg_image image_hullpiece; -static sg_image image_thruster; +static sg_image image_itemframe; +static sg_image image_itemframe_selected; +static int cur_editing_boxtype = -1; +static int cur_editing_rotation = 0; + +static struct BoxInfo +{ + enum BoxType type; + const char *image_path; + sg_image image; +} boxes[] = { // if added to here will show up in toolbar, is placeable + { + .type = BoxHullpiece, + .image_path = "loaded/hullpiece.png", + }, + { + .type = BoxThruster, + .image_path = "loaded/thruster.png", + }}; +const int boxes_len = sizeof(boxes) / sizeof(*boxes); + +struct BoxInfo boxinfo(enum BoxType type) +{ + for (int i = 0; i < boxes_len; i++) + { + if (boxes[i].type == type) + return boxes[i]; + } + Log("No box info found for type %d\n", type); + return (struct BoxInfo){0}; +} static sg_image load_image(const char *path) { @@ -96,8 +125,12 @@ static void init(void) // image loading { - image_hullpiece = load_image("loaded/hullpiece.png"); - image_thruster = load_image("loaded/thruster.png"); + for (int i = 0; i < boxes_len; i++) + { + boxes[i].image = load_image(boxes[i].image_path); + } + image_itemframe = load_image("loaded/itemframe.png"); + image_itemframe_selected = load_image("loaded/itemframe_selected.png"); } // socket initialization @@ -153,20 +186,9 @@ static void drawbox(V2 boxpos, float rot, float damage, enum BoxType type, enum float halfbox = BOX_SIZE / 2.0f; sgp_push_transform(); sgp_rotate_at(rot, boxpos.x, boxpos.y); - - switch(type) - { - case BoxHullpiece: - sgp_set_image(0, image_hullpiece); - break; - case BoxThruster: - sgp_set_image(0, image_thruster); - break; - default: - Log("Unknown image for box type of type %d\n", type); - break; - } - sgp_rotate_at( rotangle(rotation),boxpos.x,boxpos.y); + + sgp_set_image(0, boxinfo(type).image); + sgp_rotate_at(rotangle(rotation), boxpos.x, boxpos.y); sgp_draw_textured_rect(boxpos.x - halfbox, boxpos.y - halfbox, BOX_SIZE, BOX_SIZE); sgp_reset_image(0); @@ -202,6 +224,69 @@ static void draw_circle(V2 point, float radius) sgp_draw_lines(lines, POINTS); } +static void ui(bool draw, float width, float height) +{ + // draw spice bar + if (draw && myplayer != -1) + { + sgp_set_color(0.5f, 0.5f, 0.5f, 1.0f); + float margin = width * 0.1; + float bar_width = width - margin * 2.0f; + sgp_draw_filled_rect(margin, 80.0f, bar_width, 30.0f); + sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); + sgp_draw_filled_rect(margin, 80.0f, bar_width * (1.0f - gs.players[myplayer].spice_taken_away), 30.0f); + } + + // draw item toolbar + { + + int itemframe_width = sg_query_image_info(image_itemframe).width * 2.0f; + int itemframe_height = sg_query_image_info(image_itemframe).height * 2.0f; + int total_width = itemframe_width * boxes_len; + float item_width = itemframe_width * 0.75; + float item_height = itemframe_height * 0.75; + float item_offset_x = (itemframe_width - item_width) / 2.0f; + float item_offset_y = (itemframe_height - item_height) / 2.0f; + + float x = width / 2.0 - total_width / 2.0; + float y = height - itemframe_height * 1.5; + for (int i = 0; i < boxes_len; i++) + { + if (has_point((AABB){ + .x = x, + .y = y, + .width = itemframe_width, + .height = itemframe_height, + }, + mouse_pos) && + mouse_pressed) + { + // "handle" mouse pressed + mouse_pressed = false; + cur_editing_boxtype = i; + } + if (draw) + { + sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); + if (cur_editing_boxtype == i) + { + sgp_set_image(0, image_itemframe_selected); + } + else + { + sgp_set_image(0, image_itemframe); + } + sgp_draw_textured_rect(x, y, itemframe_width, itemframe_height); + sgp_set_image(0, boxinfo((enum BoxType)i).image); + sgp_draw_textured_rect(x + item_offset_x, y + item_offset_y, item_width, item_height); + sgp_reset_image(0); + } + + x += itemframe_width; + } + } +} + static void frame(void) { int width = sapp_width(), height = sapp_height(); @@ -269,6 +354,7 @@ static void frame(void) } // gameplay + ui(false, width, height); // handle events V2 build_target_pos = {0}; float build_target_rotation = 0.0f; V2 camera_pos = {0}; @@ -356,6 +442,8 @@ static void frame(void) cur_input_frame.grid_index = grid_index; if (cur_input_frame.dobuild) { + cur_input_frame.build_type = cur_editing_boxtype; + cur_input_frame.build_rotation = cur_editing_rotation; if (grid_index != -1) { cur_input_frame.build = grid_world_to_local(&gs.grids[cur_input_frame.grid_index], build_preview.pos); @@ -410,122 +498,119 @@ static void frame(void) sgp_set_color(0.1f, 0.1f, 0.1f, 1.0f); sgp_clear(); - // draw spice bar - if (myplayer != -1) - { - sgp_set_color(0.5f, 0.5f, 0.5f, 1.0f); - float margin = width * 0.1; - float bar_width = width - margin * 2.0f; - sgp_draw_filled_rect(margin, 80.0f, bar_width, 30.0f); - sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); - sgp_draw_filled_rect(margin, 80.0f, bar_width * (1.0f - gs.players[myplayer].spice_taken_away), 30.0f); - } - // sokol drawing library draw in world space // world space coordinates are +Y up, -Y down. Like normal cartesian coords { + sgp_push_transform(); sgp_translate(width / 2, height / 2); sgp_scale_at(zoom, -zoom, 0.0f, 0.0f); // camera go to player - sgp_translate(-camera_pos.x, -camera_pos.y); - } - if (myplayer != -1) - { - static float hand_reach_alpha = 1.0f; - hand_reach_alpha = lerp(hand_reach_alpha, hand_at_arms_length ? 1.0f : 0.0f, dt * 5.0); - sgp_set_color(1.0f, 1.0f, 1.0f, hand_reach_alpha); - draw_circle(gs.players[myplayer].pos, MAX_HAND_REACH); - } + // hand reached limit circle + if (myplayer != -1) + { + static float hand_reach_alpha = 1.0f; + hand_reach_alpha = lerp(hand_reach_alpha, hand_at_arms_length ? 1.0f : 0.0f, dt * 5.0); + sgp_set_color(1.0f, 1.0f, 1.0f, hand_reach_alpha); + draw_circle(gs.players[myplayer].pos, MAX_HAND_REACH); + } - // stars - sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); - const int num = 50; - for (int x = -num; x < num; x++) - { - for (int y = -num; y < num; y++) + // stars + sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); + const int num = 50; + for (int x = -num; x < num; x++) { - sgp_draw_point((float)x * 0.1f, (float)y * 0.1f); + for (int y = -num; y < num; y++) + { + sgp_draw_point((float)x * 0.1f, (float)y * 0.1f); + } } - } - float halfbox = BOX_SIZE / 2.0f; + float halfbox = BOX_SIZE / 2.0f; - // mouse - if (mouse_frozen) - { - sgp_set_color(1.0f, 0.0f, 0.0f, 0.5f); - sgp_draw_filled_rect(world_mouse_pos.x, world_mouse_pos.y, 0.1f, 0.1f); - } + // mouse + if (mouse_frozen) + { + sgp_set_color(1.0f, 0.0f, 0.0f, 0.5f); + sgp_draw_filled_rect(world_mouse_pos.x, world_mouse_pos.y, 0.1f, 0.1f); + } - // building preview - { - sgp_set_color(0.5f, 0.5f, 0.5f, (sin(time * 9.0f) + 1.0) / 3.0f + 0.2); - drawbox(build_preview.pos, build_preview.grid_rotation, 0.0f, BoxHullpiece, Right); - } + // building preview + if(cur_editing_boxtype != -1){ + sgp_set_color(0.5f, 0.5f, 0.5f, (sin(time * 9.0f) + 1.0) / 3.0f + 0.2); + drawbox(build_preview.pos, build_preview.grid_rotation, 0.0f, cur_editing_boxtype, cur_editing_rotation); + } - // grids - { - for (int i = 0; i < MAX_GRIDS; i++) + // grids { - SKIPNULL(gs.grids[i].body); - struct Grid *g = &gs.grids[i]; - for (int ii = 0; ii < MAX_BOXES_PER_GRID; ii++) + for (int i = 0; i < MAX_GRIDS; i++) { - SKIPNULL(g->boxes[ii].shape); - struct Box *b = &g->boxes[ii]; - sgp_set_color(0.5f, 0.5f, 0.5f, 1.0f); - // 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))); + SKIPNULL(gs.grids[i].body); + struct Grid *g = &gs.grids[i]; + for (int ii = 0; ii < MAX_BOXES_PER_GRID; ii++) + { + SKIPNULL(g->boxes[ii].shape); + struct Box *b = &g->boxes[ii]; + sgp_set_color(0.5f, 0.5f, 0.5f, 1.0f); + // 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); } - 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]); + V2 to = V2add(grid_com(g), vel); + sgp_draw_line(grid_com(g).x, grid_com(g).y, to.x, to.y); } - sgp_set_color(1.0f, 0.0f, 0.0f, 1.0f); - V2 vel = grid_vel(&gs.grids[i]); - V2 to = V2add(grid_com(g), vel); - sgp_draw_line(grid_com(g).x, grid_com(g).y, to.x, to.y); } - } - // player - for (int i = 0; i < MAX_PLAYERS; i++) - { - struct Player *p = &gs.players[i]; - if (!p->connected) - continue; - static float opacities[MAX_PLAYERS] = {1.0f}; - opacities[i] = lerp(opacities[i], p->currently_inhabiting_index == -1 ? 1.0f : 0.1f, dt * 7.0f); - Color col_to_draw = Collerp(WHITE, GOLD, p->goldness); - col_to_draw.a = opacities[i]; - - set_color(col_to_draw); - sgp_push_transform(); - float psize = 0.1f; - sgp_draw_filled_rect(p->pos.x - psize / 2.0f, p->pos.y - psize / 2.0f, psize, psize); + // player + for (int i = 0; i < MAX_PLAYERS; i++) + { + struct Player *p = &gs.players[i]; + if (!p->connected) + continue; + static float opacities[MAX_PLAYERS] = {1.0f}; + opacities[i] = lerp(opacities[i], p->currently_inhabiting_index == -1 ? 1.0f : 0.1f, dt * 7.0f); + Color col_to_draw = Collerp(WHITE, GOLD, p->goldness); + col_to_draw.a = opacities[i]; + + set_color(col_to_draw); + sgp_push_transform(); + float psize = 0.1f; + sgp_draw_filled_rect(p->pos.x - psize / 2.0f, p->pos.y - psize / 2.0f, psize, psize); + sgp_pop_transform(); + // sgp_rotate_at(grid_rotation(p->grid), grid_pos(p->grid).x, grid_pos(p->grid).y); + // V2 bpos = grid_pos(p->grid); + // sgp_draw_filled_rect(grid_pos(p->grid).x - halfbox, grid_pos(p->grid).y - halfbox, BOX_SIZE, BOX_SIZE); + // sgp_pop_transform(); + + // sgp_set_color(1.0f, 0.0f, 0.0f, 1.0f); + // V2 vel = grid_vel(p->grid); + // V2 to = V2add(grid_pos(p->grid), vel); + // 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); + + sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); + dbg_drawall(); + sgp_pop_transform(); - // sgp_rotate_at(grid_rotation(p->grid), grid_pos(p->grid).x, grid_pos(p->grid).y); - // V2 bpos = grid_pos(p->grid); - // sgp_draw_filled_rect(grid_pos(p->grid).x - halfbox, grid_pos(p->grid).y - halfbox, BOX_SIZE, BOX_SIZE); - // sgp_pop_transform(); - - // sgp_set_color(1.0f, 0.0f, 0.0f, 1.0f); - // V2 vel = grid_vel(p->grid); - // V2 to = V2add(grid_pos(p->grid), vel); - // 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); - - sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f); - dbg_drawall(); + // UI drawn in screen space + ui(true, width, height); sg_pass_action pass_action = {0}; sg_begin_default_pass(&pass_action, width, height); @@ -553,6 +638,18 @@ void event(const sapp_event *e) { mouse_frozen = !mouse_frozen; } + if (e->key_code == SAPP_KEYCODE_R) + { + cur_editing_rotation += 1; + cur_editing_rotation %= RotationLast; + } + int key_num = e->key_code - SAPP_KEYCODE_0; + int target_box = key_num - 1; + if(target_box < BoxLast) + { + cur_editing_boxtype = target_box; + } + if (!mouse_frozen) { keydown[e->key_code] = true; diff --git a/server.c b/server.c index 3acbe9f..b0d8ad7 100644 --- a/server.c +++ b/server.c @@ -157,20 +157,22 @@ void server(void *data) if(received.inputs[i].tick <= latest_tick) continue; // don't reprocess inputs already processed struct InputFrame cur_input = received.inputs[i]; - gs.players[player_slot].movement = cur_input.movement; - gs.players[player_slot].grid_index = cur_input.grid_index; + gs.players[player_slot].input.movement = cur_input.movement; + gs.players[player_slot].input.grid_index = cur_input.grid_index; - // for these "event" inputs, only modify the game state if the event is true. + // for these "event" inputs, only modify the current input if the event is true. // while processing the gamestate, will mark it as false once processed. This // prevents setting the event input to false before it's been processed. if (cur_input.inhabit) { - gs.players[player_slot].inhabit = cur_input.inhabit; + gs.players[player_slot].input.inhabit = cur_input.inhabit; } if (cur_input.dobuild) { - gs.players[player_slot].build = cur_input.build; - gs.players[player_slot].dobuild = cur_input.dobuild; + gs.players[player_slot].input.build = cur_input.build; + gs.players[player_slot].input.dobuild = cur_input.dobuild; + gs.players[player_slot].input.build_type = cur_input.build_type; + gs.players[player_slot].input.build_rotation = cur_input.build_rotation; } } player_to_latest_tick_processed[player_slot] = received.inputs[0].tick; diff --git a/types.h b/types.h index c385240..c568304 100644 --- a/types.h +++ b/types.h @@ -8,8 +8,8 @@ #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 THRUSTER_FORCE 4.0f +#define THRUSTER_SPICE_PER_SECOND 0.02f #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) @@ -22,7 +22,7 @@ // @Robust remove this include somehow, needed for sqrt and cos #include #include // tick is unsigned integer -#include // logging on errors for functions +#include // logging on errors for functions // including headers from headers bad #ifndef SOKOL_GP_INCLUDED @@ -63,6 +63,36 @@ typedef sgp_point P2; fprintf(stdout, "%s:%d | ", __FILE__, __LINE__); \ fprintf(stdout, __VA_ARGS__) +enum BoxType +{ + BoxHullpiece, + BoxThruster, + BoxLast +}; + +enum Rotation +{ + Right, + Down, + Left, + Up, + RotationLast, +}; + +struct InputFrame +{ + uint64_t tick; + V2 movement; + bool inhabit; + + // if grid_index != -1, this is in local coordinates to the grid + V2 build; + bool dobuild; + enum BoxType build_type; + enum Rotation build_rotation; + int grid_index; +}; + // gotta update the serialization functions when this changes struct GameState { @@ -86,13 +116,7 @@ struct GameState // input // @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 - V2 build; // @Robust this is messy, clean up? - bool dobuild; - int grid_index; + struct InputFrame input; } players[MAX_PLAYERS]; // if body or shape is null, then that grid/box has been freed @@ -104,19 +128,9 @@ struct GameState struct Box { - enum BoxType - { - BoxHullpiece, - BoxThruster, - } type; - enum Rotation - { - Right, - Down, - Left, - Up, - } rotation; - + enum BoxType type; + enum Rotation rotation; + // thruster float thrust; // must be between 0 and 1 @@ -131,24 +145,24 @@ struct GameState // returns in radians static float rotangle(enum Rotation rot) { - switch(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; + 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; } } @@ -160,17 +174,7 @@ struct ServerToClient struct ClientToServer { - struct InputFrame - { - uint64_t tick; - V2 movement; - bool inhabit; - - // if grid_index != -1, this is in local coordinates to the grid - V2 build; - bool dobuild; - int grid_index; - } inputs[INPUT_BUFFER]; + struct InputFrame inputs[INPUT_BUFFER]; }; // server @@ -218,6 +222,15 @@ void dbg_rect(V2 center); // all the math is static so that it can be defined in each compilation unit its included in +typedef struct AABB +{ + float x, y, width, height; +} AABB; + +static bool has_point(AABB aabb, V2 point) +{ + return point.x > aabb.x && point.x < aabb.x + aabb.width && point.y > aabb.y && point.y < aabb.y + aabb.height; +} static V2 V2add(V2 a, V2 b) {