Add merge box

main
Cameron Murphy Reikes 2 years ago
parent 04057fd873
commit a9691e1f3a

Binary file not shown.

@ -485,6 +485,17 @@ void box_create(GameState *gs, Entity *new_box, Entity *grid, V2 pos)
box_add_to_boxes(gs, grid, new_box); box_add_to_boxes(gs, grid, new_box);
} }
V2 box_compass_vector(Entity *box)
{
assert(box->is_box);
V2 to_return = (V2){.x = 1.0f, .y = 0.0f};
to_return = V2rotate(to_return, rotangle(box->compass_rotation));
return to_return;
}
// removes boxes from grid, then ensures that the rule that grids must not have // removes boxes from grid, then ensures that the rule that grids must not have
// holes in them is applied. // holes in them is applied.
static void grid_correct_for_holes(GameState *gs, struct Entity *grid) static void grid_correct_for_holes(GameState *gs, struct Entity *grid)
@ -561,10 +572,16 @@ static void grid_correct_for_holes(GameState *gs, struct Entity *grid)
for (int ii = 0; ii < num_dirs; ii++) for (int ii = 0; ii < num_dirs; ii++)
{ {
V2 dir = dirs[ii]; V2 dir = dirs[ii];
EntityID box_in_direction = (EntityID){0};
// @Robust @Speed faster method, not O(N^2), of getting the box // @Robust @Speed faster method, not O(N^2), of getting the box
// in the direction currently needed // in the direction currently needed
V2 compass_vect = box_compass_vector(N);
if (N->box_type == BoxMerge && N->wants_disconnect && V2equal(compass_vect, dir, 0.01f))
{
}
else
{
V2 wanted_local_pos = V2add(cur_local_pos, V2scale(dir, BOX_SIZE)); V2 wanted_local_pos = V2add(cur_local_pos, V2scale(dir, BOX_SIZE));
EntityID box_in_direction = (EntityID){0};
BOXES_ITER(gs, cur, grid) BOXES_ITER(gs, cur, grid)
{ {
if (V2equal(entity_shape_pos(cur), wanted_local_pos, 0.01f)) if (V2equal(entity_shape_pos(cur), wanted_local_pos, 0.01f))
@ -573,8 +590,15 @@ static void grid_correct_for_holes(GameState *gs, struct Entity *grid)
break; break;
} }
} }
}
Entity *newbox = get_entity(gs, box_in_direction); Entity *newbox = get_entity(gs, box_in_direction);
if(newbox != NULL && newbox->box_type == BoxMerge && newbox->wants_disconnect && V2equal(V2scale(box_compass_vector(newbox), -1.0f), dir,0.01f))
{
newbox = NULL;
}
if (newbox != NULL) if (newbox != NULL)
{ {
box_remove_from_boxes(gs, newbox); box_remove_from_boxes(gs, newbox);
@ -1566,6 +1590,11 @@ bool client_to_server_deserialize(GameState *gs, struct ClientToServer *msg, uns
} }
} }
static bool merge_filter(Entity *potential_merge)
{
return potential_merge->is_box && potential_merge->box_type == BoxMerge;
}
static void cloaking_shield_callback_func(cpShape *shape, cpContactPointSet *points, void *data) static void cloaking_shield_callback_func(cpShape *shape, cpContactPointSet *points, void *data)
{ {
Entity *from_cloaking_box = (Entity *)data; Entity *from_cloaking_box = (Entity *)data;
@ -1658,12 +1687,14 @@ static void do_explosion(GameState *gs, Entity *explosion, float dt)
cpBodyFree(tmpbody); cpBodyFree(tmpbody);
} }
V2 box_facing_vector(Entity *box) V2 box_facing_vector(Entity *box)
{ {
assert(box->is_box); assert(box->is_box);
V2 to_return = (V2){.x = 1.0f, .y = 0.0f}; V2 to_return = (V2){.x = 1.0f, .y = 0.0f};
to_return = V2rotate(to_return, rotangle(box->compass_rotation)); to_return = box_compass_vector(box);
to_return = V2rotate(to_return, box_rotation(box)); to_return = V2rotate(to_return, box_rotation(box));
return to_return; return to_return;
@ -1975,6 +2006,15 @@ void process(GameState *gs, float dt)
{ {
player->box_unlocks |= potential_seat->blueprints_learned; player->box_unlocks |= potential_seat->blueprints_learned;
} }
if (potential_seat->box_type == BoxMerge) // disconnect!
{
potential_seat->wants_disconnect = true;
grid_correct_for_holes(gs, box_grid(potential_seat));
assert(potential_seat->exists);
assert(potential_seat->is_box);
assert(potential_seat->box_type == BoxMerge);
potential_seat->wants_disconnect = false;
}
if (potential_seat->box_type == BoxCockpit || potential_seat->box_type == BoxMedbay) // @Robust check by feature flag instead of box type if (potential_seat->box_type == BoxCockpit || potential_seat->box_type == BoxMedbay) // @Robust check by feature flag instead of box type
{ {
// don't let players get inside of cockpits that somebody else is already inside of // don't let players get inside of cockpits that somebody else is already inside of
@ -2241,6 +2281,34 @@ void process(GameState *gs, float dt)
if (!e->is_platonic) if (!e->is_platonic)
grid_remove_box(gs, get_entity(gs, e->shape_parent_entity), e); grid_remove_box(gs, get_entity(gs, e->shape_parent_entity), e);
} }
if (e->box_type == BoxMerge)
{
Entity *from_merge = e;
Entity *other_merge = closest_box_to_point_in_radius(gs, entity_pos(from_merge), MERGE_MAX_DIST, merge_filter);
if (box_grid(from_merge) != box_grid(other_merge))
{
bool from_facing_other = V2dot(box_facing_vector(from_merge), V2normalize(V2sub(entity_pos(other_merge), entity_pos(from_merge)))) > 0.8f;
bool other_facing_from = V2dot(box_facing_vector(other_merge), V2normalize(V2sub(entity_pos(from_merge), entity_pos(other_merge)))) > 0.8f;
if (from_facing_other && other_facing_from)
{
// do the merge
Entity *new_grid = box_grid(from_merge);
Entity *old_grid = box_grid(other_merge);
Entity *cur = get_entity(gs, old_grid->boxes);
old_grid->boxes = (EntityID){0};
while (cur != NULL)
{
Entity *next = get_entity(gs, cur->next_box);
V2 world = entity_pos(cur);
box_create(gs, cur, new_grid, grid_world_to_local(new_grid, grid_snapped_box_pos(new_grid, world))); // destroys next/prev fields on cur
assert(box_grid(cur) == box_grid(from_merge));
cur = next;
}
entity_destroy(gs, old_grid);
}
}
}
if (e->damage >= 1.0f) if (e->damage >= 1.0f)
{ {
grid_remove_box(gs, get_entity(gs, e->shape_parent_entity), e); grid_remove_box(gs, get_entity(gs, e->shape_parent_entity), e);

Binary file not shown.

After

Width:  |  Height:  |  Size: 778 B

@ -197,6 +197,10 @@ static struct BoxInfo
.type = BoxMissileLauncher, .type = BoxMissileLauncher,
.image_path = "loaded/missile_launcher.png", .image_path = "loaded/missile_launcher.png",
}, },
{
.type = BoxMerge,
.image_path = "loaded/merge.png",
},
}; };
#define ENTITIES_ITER(cur) \ #define ENTITIES_ITER(cur) \
for (Entity *cur = gs.entities; cur < gs.entities + gs.cur_next_entity; \ for (Entity *cur = gs.entities; cur < gs.entities + gs.cur_next_entity; \

@ -6,6 +6,7 @@
#define MAX_PLAYERS 16 #define MAX_PLAYERS 16
#define MAX_ENTITIES 1024 * 25 #define MAX_ENTITIES 1024 * 25
#define BOX_SIZE 0.25f #define BOX_SIZE 0.25f
#define MERGE_MAX_DIST 0.35f
#define PLAYER_SIZE ((V2){.x = BOX_SIZE, .y = BOX_SIZE}) #define PLAYER_SIZE ((V2){.x = BOX_SIZE, .y = BOX_SIZE})
#define PLAYER_MASS 0.5f #define PLAYER_MASS 0.5f
#define PLAYER_JETPACK_FORCE 1.5f #define PLAYER_JETPACK_FORCE 1.5f
@ -167,6 +168,7 @@ enum BoxType
BoxGyroscope, BoxGyroscope,
BoxCloaking, BoxCloaking,
BoxMissileLauncher, BoxMissileLauncher,
BoxMerge,
BoxLast, BoxLast,
}; };
@ -279,6 +281,9 @@ typedef struct Entity
enum CompassRotation compass_rotation; enum CompassRotation compass_rotation;
bool indestructible; bool indestructible;
// merger
bool wants_disconnect; // don't serialized, termporary value not used across frames
// missile launcher // missile launcher
float missile_construction_charge; float missile_construction_charge;

Loading…
Cancel
Save