From 5c94921eb55144bdbff5aebdd84deef72cab14e8 Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Mon, 24 Oct 2022 10:00:12 -0700 Subject: [PATCH] Y+ is up on coord system, send build rel to grid --- gamestate.c | 143 +++++++++++++++++++++++++++++----------------------- main.c | 34 ++++++++----- types.h | 6 +++ 3 files changed, 107 insertions(+), 76 deletions(-) diff --git a/gamestate.c b/gamestate.c index 16bd61c..0b4405b 100644 --- a/gamestate.c +++ b/gamestate.c @@ -189,6 +189,10 @@ V2 grid_world_to_local(struct Grid *grid, V2 world) { return cp_to_v2(cpBodyWorldToLocal(grid->body, v2_to_cp(world))); } +V2 grid_local_to_world(struct Grid *grid, V2 local) +{ + return cp_to_v2(cpBodyLocalToWorld(grid->body, v2_to_cp(local))); +} // returned snapped position is in world coordinates V2 grid_snapped_box_pos(struct Grid *grid, V2 world) { @@ -511,61 +515,11 @@ void process(struct GameState *gs, float dt) if (!p->connected) continue; - if(V2length(V2sub(p->pos, gs->goldpos)) < GOLD_COLLECT_RADIUS) + // update gold win condition + if (V2length(V2sub(p->pos, gs->goldpos)) < GOLD_COLLECT_RADIUS) { p->goldness += 0.2; - gs->goldpos = (V2){.x = hash11(gs->time)*20.0f, .y = hash11(gs->time-13.6f)*20.0f}; - } - - if (p->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... - - cpPointQueryInfo info = {0}; - // @Robust make sure to query only against boxes... - cpShape *nearest = cpSpacePointQueryNearest(gs->space, v2_to_cp(p->build), 0.01f, cpShapeFilterNew(CP_NO_GROUP, CP_ALL_CATEGORIES, CP_ALL_CATEGORIES), &info); - if (nearest != NULL) - { - struct Box *cur_box = (struct Box *)cpShapeGetUserData(nearest); - struct Grid *cur_grid = (struct Grid *)cpBodyGetUserData(cpShapeGetBody(nearest)); - grid_remove_box(gs->space, cur_grid, cur_box); - p->spice_taken_away -= 0.1f; - } - else if(p->grid_index == -1) - { - // @Robust better memory mgmt - struct Grid *empty_grid = NULL; - for (int ii = 0; ii < MAX_GRIDS; ii++) - { - if (gs->grids[ii].body == NULL) - { - empty_grid = &gs->grids[ii]; - break; - } - } - p->spice_taken_away += 0.2f; - grid_new(empty_grid, gs, p->build); - cpBodySetVelocity(empty_grid->body, v2_to_cp(p->vel)); - box_new(&empty_grid->boxes[0], gs, empty_grid, (V2){0}); - } - else - { - struct Grid *g = &gs->grids[p->grid_index]; - - struct Box *empty_box = NULL; - for (int ii = 0; ii < MAX_BOXES_PER_GRID; ii++) - { - if (g->boxes[ii].shape == NULL) - { - empty_box = &g->boxes[ii]; - break; - } - } - // @Robust cleanly fail when not enough boxes - assert(empty_box != NULL); - p->spice_taken_away += 0.1f; - box_new(empty_box, gs, g, grid_world_to_local(g, p->build)); - } + gs->goldpos = (V2){.x = hash11(gs->time) * 20.0f, .y = hash11(gs->time - 13.6f) * 20.0f}; } if (gs->grids[p->currently_inhabiting_index].body == NULL) @@ -612,23 +566,84 @@ void process(struct GameState *gs, float dt) } } - if (p->currently_inhabiting_index == -1) + // process movement { - // @Robust make sure movement vector is normalized so player can't cheat - p->vel = V2add(p->vel, V2scale(p->movement, dt*0.5f)); + 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); + } + else + { + 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))); + // 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->pos = V2add(p->pos, V2scale(p->vel, dt)); - p->spice_taken_away += dt*0.15f*V2length(p->movement); } - else + + if (p->dobuild) { - struct Grid *g = &gs->grids[p->currently_inhabiting_index]; - p->pos = V2lerp(p->pos, grid_com(g), dt * 20.0f); - 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->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) + { + world_build = grid_local_to_world(&gs->grids[p->grid_index], p->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) + { + struct Box *cur_box = (struct Box *)cpShapeGetUserData(nearest); + struct Grid *cur_grid = (struct Grid *)cpBodyGetUserData(cpShapeGetBody(nearest)); + grid_remove_box(gs->space, cur_grid, cur_box); + p->spice_taken_away -= 0.1f; + } + else if (p->grid_index == -1) + { + // @Robust better memory mgmt + struct Grid *empty_grid = NULL; + for (int ii = 0; ii < MAX_GRIDS; ii++) + { + if (gs->grids[ii].body == NULL) + { + empty_grid = &gs->grids[ii]; + break; + } + } + 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}); + cpBodySetVelocity(empty_grid->body, v2_to_cp(p->vel)); + } + else + { + struct Grid *g = &gs->grids[p->grid_index]; + + struct Box *empty_box = NULL; + for (int ii = 0; ii < MAX_BOXES_PER_GRID; ii++) + { + if (g->boxes[ii].shape == NULL) + { + empty_box = &g->boxes[ii]; + break; + } + } + // @Robust cleanly fail when not enough boxes + assert(empty_box != NULL); + p->spice_taken_away += 0.1f; + box_new(empty_box, gs, g, grid_world_to_local(g, world_build)); + } } - if(p->spice_taken_away >= 1.0f) + if (p->spice_taken_away >= 1.0f) { reset_player(p); p->connected = true; diff --git a/main.c b/main.c index 7b8afa8..0a24d44 100644 --- a/main.c +++ b/main.c @@ -233,7 +233,7 @@ static void frame(void) } world_mouse_pos = V2sub(world_mouse_pos, (V2){.x = width / 2.0f, .y = height / 2.0f}); world_mouse_pos.x /= zoom; - world_mouse_pos.y /= zoom; + world_mouse_pos.y /= -zoom; world_mouse_pos = V2add(world_mouse_pos, (V2){.x = camera_pos.x, .y = camera_pos.y}); } @@ -288,13 +288,25 @@ static void frame(void) struct ClientToServer curmsg = {0}; V2 input = (V2){ .x = (float)keydown[SAPP_KEYCODE_D] - (float)keydown[SAPP_KEYCODE_A], - .y = (float)keydown[SAPP_KEYCODE_S] - (float)keydown[SAPP_KEYCODE_W], + .y = (float)keydown[SAPP_KEYCODE_W] - (float)keydown[SAPP_KEYCODE_S], }; curmsg.movement = input; curmsg.inhabit = keypressed[SAPP_KEYCODE_G].pressed; - curmsg.build = build_preview.pos; curmsg.dobuild = mouse_pressed; curmsg.grid_index = grid_index; + if (curmsg.dobuild) + { + if (grid_index != -1) + { + curmsg.build = grid_world_to_local(&gs.grids[curmsg.grid_index], build_preview.pos); + V2 untransformed = grid_local_to_world(&gs.grids[curmsg.grid_index], curmsg.build); + untransformed.x += 5.0f; + } + else + { + curmsg.build = build_preview.pos; + } + } // @BeforeShip figure out why tf the possess ship key is so unreliable ENetPacket *packet = enet_packet_create((void *)&curmsg, sizeof(curmsg), ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT); @@ -303,7 +315,7 @@ static void frame(void) // @BeforeShip client side prediction and rollback to previous server authoritative state, then replay inputs // no need to store copies of game state, just player input frame to frame. Then know how many frames ago the server game state arrived, it's that easy! - process(&gs, (float)sapp_frame_duration()); + // process(&gs, (float)sapp_frame_duration()); } // drawing @@ -329,9 +341,10 @@ static void frame(void) } // sokol drawing library draw in world space + // world space coordinates are +Y up, -Y down. Like normal cartesian coords { sgp_translate(width / 2, height / 2); - sgp_scale_at(zoom, zoom, 0.0f, 0.0f); + sgp_scale_at(zoom, -zoom, 0.0f, 0.0f); // camera go to player @@ -411,10 +424,6 @@ static void frame(void) 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); - if (b->damage > 0.01f) - { - Log("Damage: %f\n", b->damage); - } } sgp_set_color(1.0f, 0.0f, 0.0f, 1.0f); V2 vel = grid_vel(&gs.grids[i]); @@ -423,11 +432,12 @@ static void frame(void) } } + set_color(RED); + sgp_draw_filled_rect(1.0f, 0.5f, 0.3f, 0.3f); + // gold target set_color(GOLD); - sgp_draw_filled_rect(gs.goldpos.x, gs.goldpos.y,0.1f,0.1f); - - + 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(); diff --git a/types.h b/types.h index 36a0c92..72c9d5f 100644 --- a/types.h +++ b/types.h @@ -73,6 +73,7 @@ struct GameState V2 movement; 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; @@ -103,6 +104,8 @@ struct ClientToServer { V2 movement; bool inhabit; + + // if grid_index != -1, this is in local coordinates to the grid V2 build; bool dobuild; int grid_index; @@ -127,6 +130,8 @@ void grid_new(struct Grid *to_modify, struct GameState *gs, V2 pos); V2 grid_com(struct Grid *grid); V2 grid_pos(struct Grid *grid); V2 grid_vel(struct Grid *grid); +V2 grid_local_to_world(struct Grid *grid, V2 local); +V2 grid_world_to_local(struct Grid *grid, V2 world); V2 grid_snapped_box_pos(struct Grid *grid, V2 world); // returns the snapped pos in world coords float grid_rotation(struct Grid *grid); float grid_angular_velocity(struct Grid *grid); @@ -268,4 +273,5 @@ static void set_color(Color c) } #define WHITE (Color){.r=1.0f,.g=1.0f,.b=1.0f,.a=1.0f} +#define RED (Color){.r=1.0f,.g=0.0f,.b=0.0f,.a=1.0f} #define GOLD colhex(255, 215, 0) \ No newline at end of file