From d8b8f2c9254cf25d69213b9cb6c2b87a3ecf2605 Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Wed, 16 Nov 2022 22:59:06 -0800 Subject: [PATCH] Pixel edge rendering fix, game design fixing! --- gamestate.c | 116 +++++++++++++++++++++++++++++++++++----------------- main.c | 1 + types.h | 11 ++--- 3 files changed, 86 insertions(+), 42 deletions(-) diff --git a/gamestate.c b/gamestate.c index 9d4d70b..5c06bad 100644 --- a/gamestate.c +++ b/gamestate.c @@ -1441,20 +1441,46 @@ V2 get_world_hand_pos(GameState *gs, InputFrame *input, Entity *player) return potentially_snap_hand_pos(gs, V2add(entity_pos(player), input->hand_pos)); } -// return true if used the energy -bool possibly_use_energy(GameState *gs, Entity *grid, float wanted_energy) +bool batteries_have_capacity_for(GameState *gs, Entity *grid, float *energy_left_over, float energy_to_use) { + float seen_energy = 0.0f; BOXES_ITER(gs, possible_battery, grid) { - if (possible_battery->box_type == BoxBattery && (BATTERY_CAPACITY - possible_battery->energy_used) > wanted_energy) + if (possible_battery->box_type == BoxBattery) { - possible_battery->energy_used += wanted_energy; - return true; + Entity *battery = possible_battery; + seen_energy += BATTERY_CAPACITY - battery->energy_used; + if (seen_energy >= energy_to_use + *energy_left_over) + return true; } } return false; } +// returns any energy unable to burn +float batteries_use_energy(GameState *gs, Entity *grid, float *energy_left_over, float energy_to_use) +{ + if (*energy_left_over > 0.0f) + { + float energy_to_use_from_leftover = fminf(*energy_left_over, energy_to_use); + *energy_left_over -= energy_to_use_from_leftover; + energy_to_use -= energy_to_use_from_leftover; + } + BOXES_ITER(gs, possible_battery, grid) + { + if (possible_battery->box_type == BoxBattery) + { + Entity *battery = possible_battery; + float energy_to_burn_from_this_battery = fminf(BATTERY_CAPACITY - battery->energy_used, energy_to_use); + battery->energy_used += energy_to_burn_from_this_battery; + energy_to_use -= energy_to_burn_from_this_battery; + if (energy_to_use <= 0.0f) + return 0.0f; + } + } + return energy_to_use; +} + void entity_ensure_in_orbit(Entity *e) { cpVect pos = v2_to_cp(V2sub(entity_pos(e), SUN_POS)); @@ -1523,7 +1549,7 @@ void exit_seat(GameState *gs, Entity *seat_in, Entity *p) { V2 pilot_seat_exit_spot = V2add(entity_pos(seat_in), V2scale(box_facing_vector(seat_in), BOX_SIZE)); cpBodySetPosition(p->body, v2_to_cp(pilot_seat_exit_spot)); - //cpBodySetVelocity(p->body, v2_to_cp(player_vel(gs, p))); + // cpBodySetVelocity(p->body, v2_to_cp(player_vel(gs, p))); cpBodySetVelocity(p->body, cpBodyGetVelocity(box_grid(seat_in)->body)); } @@ -1573,17 +1599,19 @@ void process(GameState *gs, float dt) possibly_to_invite->squad_invited_to = player->squad; } Entity *p = get_entity(gs, player->entity); + // player respawning if (p == NULL) { p = new_entity(gs); create_player(gs, p); player->entity = get_id(gs, p); Entity *medbay = get_entity(gs, player->last_used_medbay); + entity_ensure_in_orbit(p); if (medbay != NULL) { exit_seat(gs, medbay, p); + p->damage = 0.95f; } - entity_ensure_in_orbit(p); } assert(p->is_player); p->presenting_squad = player->squad; @@ -1634,7 +1662,8 @@ void process(GameState *gs, float dt) { p->currently_inside_of_box = get_id(gs, potential_seat); potential_seat->player_who_is_inside_of_me = get_id(gs, p); - player->last_used_medbay = p->currently_inside_of_box; + if (potential_seat->box_type == BoxMedbay) + player->last_used_medbay = p->currently_inside_of_box; } } } @@ -1708,38 +1737,45 @@ void process(GameState *gs, float dt) // @Robust sanitize this input so player can't build on any grid in the world Entity *target_grid = grid_to_build_on(gs, world_hand_pos); - cpShape *nearest = cpSpacePointQueryNearest(gs->space, v2_to_cp(world_build), 0.01f, cpShapeFilterNew(CP_NO_GROUP, CP_ALL_CATEGORIES, BOXES), &info); - if (nearest != NULL) + cpShape *maybe_box_to_destroy = cpSpacePointQueryNearest(gs->space, v2_to_cp(world_build), 0.01f, cpShapeFilterNew(CP_NO_GROUP, CP_ALL_CATEGORIES, BOXES), &info); + if (maybe_box_to_destroy != NULL) { - Entity *cur_box = cp_shape_entity(nearest); + Entity *cur_box = cp_shape_entity(maybe_box_to_destroy); if (!cur_box->indestructible) { - Entity *cur_grid = cp_body_entity(cpShapeGetBody(nearest)); + Entity *cur_grid = cp_body_entity(cpShapeGetBody(maybe_box_to_destroy)); p->damage -= DAMAGE_TO_PLAYER_PER_BLOCK * ((BATTERY_CAPACITY - cur_box->energy_used) / BATTERY_CAPACITY); grid_remove_box(gs, cur_grid, cur_box); } } - else if (target_grid == NULL) - { - Entity *new_grid = new_entity(gs); - grid_create(gs, new_grid); - p->damage += DAMAGE_TO_PLAYER_PER_BLOCK; - entity_set_pos(new_grid, world_build); - - Entity *new_box = new_entity(gs); - box_create(gs, new_box, new_grid, (V2){0}); - new_box->box_type = player->input.build_type; - new_box->compass_rotation = player->input.build_rotation; - cpBodySetVelocity(new_grid->body, v2_to_cp(player_vel(gs, p))); - } else { - Entity *new_box = new_entity(gs); - box_create(gs, new_box, target_grid, grid_world_to_local(target_grid, world_build)); - grid_correct_for_holes(gs, target_grid); // no holey ship for you! - new_box->box_type = player->input.build_type; - new_box->compass_rotation = player->input.build_rotation; + // creating a box p->damage += DAMAGE_TO_PLAYER_PER_BLOCK; + V2 created_box_position; + if (p->damage < 1.0f) // player can't create a box that kills them by making it + { + if (target_grid == NULL) + { + Entity *new_grid = new_entity(gs); + grid_create(gs, new_grid); + entity_set_pos(new_grid, world_build); + cpBodySetVelocity(new_grid->body, v2_to_cp(player_vel(gs, p))); + target_grid = new_grid; + created_box_position = (V2){0}; + } + else + { + created_box_position = grid_world_to_local(target_grid, world_build); + } + Entity *new_box = new_entity(gs); + box_create(gs, new_box, target_grid, created_box_position); + grid_correct_for_holes(gs, target_grid); // no holey ship for you! + new_box->box_type = player->input.build_type; + new_box->compass_rotation = player->input.build_rotation; + if (new_box->box_type == BoxBattery) + new_box->energy_used = BATTERY_CAPACITY; + } } } #endif @@ -1847,17 +1883,22 @@ void process(GameState *gs, float dt) assert(energy_to_add >= 0.0f); } + // any energy_to_add existing now can also be used to power thrusters/medbay + float non_battery_energy_left_over = energy_to_add; + // use the energy, stored in the batteries, in various boxes BOXES_ITER(gs, cur, e) { if (cur->box_type == BoxThruster) { float energy_to_consume = cur->wanted_thrust * THRUSTER_ENERGY_USED_PER_SECOND * dt; - cur->thrust = 0.0f; - if (possibly_use_energy(gs, e, energy_to_consume)) + if (energy_to_consume > 0.0f) { - cur->thrust = cur->wanted_thrust; - cpBodyApplyForceAtWorldPoint(e->body, v2_to_cp(thruster_force(cur)), v2_to_cp(entity_pos(cur))); + cur->thrust = 0.0f; + float energy_unconsumed = batteries_use_energy(gs, e, &non_battery_energy_left_over, energy_to_consume); + cur->thrust = (1.0f - energy_unconsumed / energy_to_consume) * cur->wanted_thrust; + if (cur->thrust >= 0.0f) + cpBodyApplyForceAtWorldPoint(e->body, v2_to_cp(thruster_force(cur)), v2_to_cp(entity_pos(cur))); } } if (cur->box_type == BoxMedbay) @@ -1865,10 +1906,11 @@ void process(GameState *gs, float dt) Entity *potential_meatbag_to_heal = get_entity(gs, cur->player_who_is_inside_of_me); if (potential_meatbag_to_heal != NULL) { - float energy_to_recharge = fminf(potential_meatbag_to_heal->damage, PLAYER_ENERGY_RECHARGE_PER_SECOND * dt); - if (possibly_use_energy(gs, e, energy_to_recharge)) + float wanted_energy_use = fminf(potential_meatbag_to_heal->damage, PLAYER_ENERGY_RECHARGE_PER_SECOND * dt); + if (wanted_energy_use > 0.0f) { - potential_meatbag_to_heal->damage -= energy_to_recharge; + float energy_unconsumed = batteries_use_energy(gs, e, &non_battery_energy_left_over, wanted_energy_use); + potential_meatbag_to_heal->damage -= (1.0f - energy_unconsumed / wanted_energy_use) * wanted_energy_use; } } } diff --git a/main.c b/main.c index 93f6fed..ce79ac8 100644 --- a/main.c +++ b/main.c @@ -242,6 +242,7 @@ static sg_image load_image(const char *path) .pixel_format = SG_PIXELFORMAT_RGBA8, .min_filter = SG_FILTER_NEAREST, .mag_filter = SG_FILTER_NEAREST, + .wrap_u = SG_WRAP_CLAMP_TO_EDGE, .data.subimage[0][0] = { .ptr = image_data, .size = (size_t)(x * y * desired_channels), diff --git a/types.h b/types.h index ecfaec2..5ce370d 100644 --- a/types.h +++ b/types.h @@ -24,14 +24,14 @@ #define INSTANT_DEATH_DISTANCE_FROM_SUN 2000.0f #define SUN_POS ((V2){50.0f, 0.0f}) #ifdef NO_GRAVITY -#define SUN_GRAVITY_STRENGTH 0.1f +#define SUN_GRAVITY_STRENGTH 0.0f #else #define SUN_GRAVITY_STRENGTH (9.0e2f) #endif -#define SOLAR_ENERGY_PER_SECOND 0.02f +#define SOLAR_ENERGY_PER_SECOND 0.04f #define DAMAGE_TO_PLAYER_PER_BLOCK 0.1f -#define BATTERY_CAPACITY DAMAGE_TO_PLAYER_PER_BLOCK * 0.7f -#define PLAYER_ENERGY_RECHARGE_PER_SECOND 0.1f +#define BATTERY_CAPACITY 1.5f +#define PLAYER_ENERGY_RECHARGE_PER_SECOND 0.2f #define EXPLOSION_TIME 0.5f #define EXPLOSION_PUSH_STRENGTH 5.0f #define EXPLOSION_DAMAGE_PER_SEC 10.0f @@ -48,6 +48,7 @@ #define VOIP_PACKET_MAX_SIZE 4000 #define VOIP_DISTANCE_WHEN_CANT_HEAR (VISION_RADIUS * 0.8f) +// multiplayer #define MAX_REPREDICTION_TIME (TIMESTEP * 50.0f) #define TIME_BETWEEN_SEND_GAMESTATE (1.0f / 20.0f) #define TIME_BETWEEN_INPUT_PACKETS (1.0f / 20.0f) @@ -235,7 +236,7 @@ typedef struct Entity bool indestructible; float wanted_thrust; // the thrust command applied to the thruster float thrust; // the actual thrust it can provide based on energy sources in the grid - float energy_used; // battery + float energy_used; // battery, between 0 battery capacity. You have to look through code to figure out what that is! haha sucker! float sun_amount; // solar panel, between 0 and 1 EntityID player_who_is_inside_of_me; } Entity;