Compare commits

...

5 Commits

@ -35,6 +35,23 @@ static struct Box *getbox(cpShape *shape)
return (struct Box *)cpShapeGetUserData(shape);
}
static struct Grid *find_empty_grid(struct GameState *gs)
{
// @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;
}
}
// @Robust cleanly fail when not enough grids
assert(empty_grid != NULL);
return empty_grid;
}
static int grid_num_boxes(struct Grid *g)
{
int to_return = 0;
@ -69,13 +86,204 @@ void grid_destroy(cpSpace *space, struct Grid *grid)
grid->body = NULL;
}
// removes boxe from grid, then ensures that the rule that grids must not have
// holes in them is applied.
// uses these forward declared serialization functions to duplicate a box
typedef struct SerState
{
char *bytes;
bool serializing;
int cursor; // points to next available byte, is the size of current message after serializing something
int max_size;
} SerState;
void ser_box(SerState *ser, struct Box *var, struct GameState *gs, struct Grid *g);
static void grid_remove_box(cpSpace *space, struct Grid *grid, struct Box *box)
{
box_destroy(space, box);
if (grid_num_boxes(grid) == 0)
struct GameState *gs = (struct GameState *)cpSpaceGetUserData(space);
int num_boxes = grid_num_boxes(grid);
if (num_boxes == 0)
{
grid_destroy(space, grid);
return;
}
if (num_boxes == 1)
return;
// could be a gap between boxes in the grid, separate into multiple grids
// goal: create list of "real grids" from this grid that have boxes which are
// ONLY connected horizontally and vertically. whichever one of these "real grids"
// has the most blocks stays the current grid, so
// if a player is inhabiting this ship it stays that ship.
// The other "real grids" are allocated as new grids
#define MAX_SEPARATE_GRIDS 8
struct Box *separate_grids[MAX_SEPARATE_GRIDS][MAX_BOXES_PER_GRID] = {0};
int cur_separate_grid_index = 0;
int processed_boxes = 0;
struct Box **biggest_separate_grid = separate_grids[0];
int biggest_separate_grid_length = 0;
// process all boxes into separate, but correctly connected, grids
while (processed_boxes < num_boxes)
{
// grab an unprocessed box, one not in separate_grids, to start the flood fill
struct Box *unprocessed = NULL;
for (int i = 0; i < MAX_BOXES_PER_GRID; i++)
{
SKIPNULL(grid->boxes[i].shape);
struct Box *cur = &grid->boxes[i];
bool cur_has_been_processed = false;
for (int sep_i = 0; sep_i < MAX_SEPARATE_GRIDS; sep_i++)
{
for (int sep_box_i = 0; sep_box_i < MAX_BOXES_PER_GRID; sep_box_i++)
{
if (cur == separate_grids[sep_i][sep_box_i])
{
cur_has_been_processed = true;
break;
}
}
if (cur_has_been_processed)
break;
}
if (!cur_has_been_processed)
{
unprocessed = cur;
break;
}
}
assert(unprocessed != NULL);
// flood fill from this unprocessed box, adding each result to a new separate grid
// https://en.wikipedia.org/wiki/Flood_fill
struct Box **cur_separate_grid = separate_grids[cur_separate_grid_index];
cur_separate_grid_index++;
int separate_grid_i = 0;
{
// queue stuff @Robust use factored datastructure
struct Box *Q[MAX_BOXES_PER_GRID] = {0};
int Q_i = 0;
Q[Q_i] = unprocessed;
Q_i++;
struct Box *N = NULL;
while (Q_i > 0)
{
N = Q[Q_i - 1];
Q_i--;
if (true) // if node "inside", this is always true
{
cur_separate_grid[separate_grid_i] = N;
separate_grid_i++;
processed_boxes++;
V2 cur_local_pos = box_local_pos(N);
const V2 dirs[] = {
(V2){.x = -1.0f, .y = 0.0f},
(V2){.x = 1.0f, .y = 0.0f},
(V2){.x = 0.0f, .y = 1.0f},
(V2){.x = 0.0f, .y = -1.0f},
};
int num_dirs = sizeof(dirs) / sizeof(*dirs);
for (int ii = 0; ii < num_dirs; ii++)
{
V2 dir = dirs[ii];
// @Robust faster method, not O(N^2), of getting the box
// in the direction currently needed
V2 wanted_local_pos = V2add(cur_local_pos, V2scale(dir, BOX_SIZE));
struct Box *box_in_direction = NULL;
for (int iii = 0; iii < MAX_BOXES_PER_GRID; iii++)
{
SKIPNULL(grid->boxes[iii].shape);
if (V2cmp(box_local_pos(&grid->boxes[iii]), wanted_local_pos, 0.01f))
{
box_in_direction = &grid->boxes[iii];
break;
}
}
if (box_in_direction != NULL)
{
// make sure not already added to the separate grid
bool already_in_separate_grid = false;
for (int sepgrid_i = 0; sepgrid_i < MAX_BOXES_PER_GRID; sepgrid_i++)
{
if (cur_separate_grid[sepgrid_i] == NULL)
break; // assumed to be end of the current separate grid list
if (cur_separate_grid[sepgrid_i] == box_in_direction)
{
already_in_separate_grid = true;
break;
}
}
if (!already_in_separate_grid)
{
Q[Q_i] = box_in_direction;
Q_i++;
}
}
}
}
}
}
if (separate_grid_i > biggest_separate_grid_length)
{
biggest_separate_grid_length = separate_grid_i;
biggest_separate_grid = cur_separate_grid;
}
}
// create new grids for all lists of boxes except for the biggest one.
// delete the boxes out of the current grid as I pull boxes into separate ones
// which are no longer connected
for (int sepgrid_i = 0; sepgrid_i < MAX_SEPARATE_GRIDS; sepgrid_i++)
{
if (separate_grids[sepgrid_i] == biggest_separate_grid)
continue; // leave the boxes of the biggest separate untouched
struct Box **cur_separate_grid = separate_grids[sepgrid_i];
int cur_sepgrid_i = 0;
if (cur_separate_grid[cur_sepgrid_i] == NULL)
continue; // this separate grid is empty
struct Grid *new_grid = find_empty_grid(gs);
grid_new(new_grid, gs, grid_pos(grid)); // all grids have same pos but different center of mass (com)
cpBodySetAngle(new_grid->body, grid_rotation(grid));
int new_grid_box_i = 0;
while (cur_separate_grid[cur_sepgrid_i] != NULL)
{
char box_bytes[128];
char *cur = box_bytes;
// duplicate the box by serializing it then deserializing it
SerState ser = (SerState){
.bytes = cur,
.cursor = 0,
.max_size = 128,
.serializing = true,
};
ser_box(&ser, cur_separate_grid[cur_sepgrid_i], gs, grid);
ser.cursor = 0;
ser.serializing = false;
ser_box(&ser, &new_grid->boxes[new_grid_box_i], gs, new_grid);
cur_sepgrid_i++;
new_grid_box_i++;
}
cpBodySetVelocity(new_grid->body, cpBodyGetVelocityAtWorldPoint(grid->body, v2_to_cp(grid_com(new_grid))));
cpBodySetAngularVelocity(new_grid->body, grid_angular_velocity(grid));
cur_sepgrid_i = 0;
while (cur_separate_grid[cur_sepgrid_i] != NULL)
{
box_destroy(space, cur_separate_grid[cur_sepgrid_i]);
cur_sepgrid_i++;
}
}
}
@ -111,6 +319,7 @@ static cpBool on_damage(cpArbiter *arb, cpSpace *space, cpDataPointer userData)
void initialize(struct GameState *gs)
{
gs->space = cpSpaceNew();
cpSpaceSetUserData(gs->space, (cpDataPointer)gs); // needed in the handler
cpCollisionHandler *handler = cpSpaceAddCollisionHandler(gs->space, 0, 0); // @Robust limit collision type to just blocks that can be damaged
// handler->beginFunc = begin;
handler->postSolveFunc = on_damage;
@ -214,301 +423,238 @@ float grid_angular_velocity(struct Grid *grid)
{
return cpBodyGetAngularVelocity(grid->body);
}
V2 box_pos(struct Box *box)
{
struct Grid *g = (struct Grid *)cpBodyGetUserData(cpShapeGetBody(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)
{
return cpBodyGetAngle(cpShapeGetBody(box->shape));
}
#define memwrite(out, variable) \
for (char b = 0; b < sizeof(variable); b++) \
{ \
**out = ((char *)&variable)[b]; \
*out += 1; \
}
#define memread(in, variable_pointer) \
for (char b = 0; b < sizeof(*variable_pointer); b++) \
{ \
((char *)variable_pointer)[b] = **in; \
*in += 1; \
}
void ser_float(char **out, float f)
struct Grid *box_grid(struct Box *box)
{
memwrite(out, f);
return (struct Grid *)cpBodyGetUserData(cpShapeGetBody(box->shape));
}
void des_float(char **in, float *f)
V2 box_local_pos(struct Box *box)
{
memread(in, f);
return cp_to_v2(cpShapeGetCenterOfGravity(box->shape));
}
void ser_double(char **out, double d)
{
memwrite(out, d);
}
void des_double(char **in, double *d)
{
memread(in, d);
}
void ser_int(char **out, int i)
{
memwrite(out, i);
}
void des_int(char **in, int *i)
{
memread(in, i);
}
void ser_uint64(char **out, uint64_t i)
V2 box_pos(struct Box *box)
{
memwrite(out, i);
return V2add(grid_pos(box_grid(box)), V2rotate(box_local_pos(box), grid_rotation(box_grid(box))));
}
void des_uint64(char **in, uint64_t *i)
float box_rotation(struct Box *box)
{
memread(in, i);
return cpBodyGetAngle(cpShapeGetBody(box->shape));
}
void ser_bool(char **out, bool b)
{
**out = (char)b;
*out += 1;
}
#define WRITE_VARNAMES false // good for debugging
#include <string.h>
// assumes SerState *var defined
#define SER_VAR(var_pointer) \
{ \
const char *var_name = #var_pointer; \
size_t var_name_len = 0; \
if (WRITE_VARNAMES) \
{ \
var_name_len = strlen(var_name); \
} \
if (ser->serializing) \
{ \
if (WRITE_VARNAMES) \
{ \
memcpy(ser->bytes + ser->cursor, var_name, var_name_len); \
ser->cursor += var_name_len; \
} \
for (int b = 0; b < sizeof(*var_pointer); b++) \
{ \
ser->bytes[ser->cursor] = ((char *)var_pointer)[b]; \
ser->cursor += 1; \
assert(ser->cursor < ser->max_size); \
} \
} \
else \
{ \
if (WRITE_VARNAMES) \
{ \
char *read_name = malloc(sizeof *read_name * (var_name_len + 1)); \
for (int i = 0; i < var_name_len; i++) \
{ \
read_name[i] = ser->bytes[ser->cursor]; \
ser->cursor += 1; \
assert(ser->cursor < ser->max_size); \
} \
read_name[var_name_len] = '\0'; \
if (strcmp(read_name, var_name) != 0) \
{ \
printf("%s:%d | Expected variable %s but got %s\n", __FILE__, __LINE__, var_name, read_name); \
} \
free(read_name); \
} \
for (int b = 0; b < sizeof(*var_pointer); b++) \
{ \
((char *)var_pointer)[b] = ser->bytes[ser->cursor]; \
ser->cursor += 1; \
assert(ser->cursor < ser->max_size); \
} \
} \
}
void des_bool(char **in, bool *b)
void ser_V2(SerState *ser, V2 *var)
{
*b = (bool)**in;
*in += 1;
SER_VAR(&var->x);
SER_VAR(&var->y);
}
void ser_V2(char **out, V2 v)
void ser_box(SerState *ser, struct Box *var, struct GameState *gs, struct Grid *g)
{
ser_float(out, v.x);
ser_float(out, v.y);
}
{
V2 pos;
if (ser->serializing)
{
pos = cp_to_v2(cpShapeGetCenterOfGravity(var->shape));
}
ser_V2(ser, &pos);
if (!ser->serializing)
{
box_new(var, gs, g, pos);
}
}
void des_V2(char **in, V2 *v)
{
des_float(in, &v->x);
des_float(in, &v->y);
SER_VAR(&var->type); // @Rovarust separate enum serialization that checks for out of varounds enum
SER_VAR(&var->compass_rotation);
SER_VAR(&var->thrust);
SER_VAR(&var->energy_used);
SER_VAR(&var->damage);
}
void ser_grid(char **out, struct Grid *g)
void ser_grid(SerState *ser, struct GameState *gs, struct Grid *g)
{
// grid must not be null, dummy!
assert(g->body != NULL);
if (ser->serializing)
assert(g->body != NULL);
else
assert(g->body == NULL);
ser_V2(out, grid_pos(g));
ser_V2(out, grid_vel(g));
ser_float(out, grid_rotation(g));
ser_float(out, grid_angular_velocity(g));
ser_float(out, g->total_energy_capacity);
for (int i = 0; i < MAX_BOXES_PER_GRID; i++)
{
bool exists = g->boxes[i].shape != NULL;
ser_bool(out, exists);
if (exists)
V2 pos = {0};
V2 vel = {0};
float rot = 0.0f;
float angular_vel = 0.0f;
if (ser->serializing)
{
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].energy_used);
ser_float(out, g->boxes[i].damage);
pos = grid_pos(g);
vel = grid_vel(g);
rot = grid_rotation(g);
angular_vel = grid_angular_velocity(g);
}
SER_VAR(&pos);
SER_VAR(&vel);
SER_VAR(&rot);
SER_VAR(&angular_vel);
if (!ser->serializing)
{
grid_new(g, gs, pos);
cpBodySetVelocity(g->body, v2_to_cp(vel));
cpBodySetAngle(g->body, rot);
cpBodySetAngularVelocity(g->body, angular_vel);
}
}
}
// takes gamestate as argument to place box in the gamestates space
void des_grid(char **in, struct Grid *g, struct GameState *gs)
{
assert(g->body == NULL); // destroy the grid before deserializing into it
V2 pos = {0};
V2 vel = {0};
float rot = 0.0f;
float angular_vel = 0.0f;
des_V2(in, &pos);
des_V2(in, &vel);
des_float(in, &rot);
des_float(in, &angular_vel);
grid_new(g, gs, pos);
cpBodySetVelocity(g->body, v2_to_cp(vel));
cpBodySetAngle(g->body, rot);
cpBodySetAngularVelocity(g->body, angular_vel);
des_float(in, &g->total_energy_capacity);
SER_VAR(&g->total_energy_capacity);
for (int i = 0; i < MAX_BOXES_PER_GRID; i++)
{
bool exists = false;
des_bool(in, &exists);
bool exists;
if (ser->serializing)
exists = g->boxes[i].shape != NULL;
SER_VAR(&exists);
if (exists)
{
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].energy_used);
des_float(in, &g->boxes[i].damage);
ser_box(ser, &g->boxes[i], gs, g);
}
}
}
void ser_inputframe(char **out, struct InputFrame *i)
void ser_inputframe(SerState *ser, 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);
SER_VAR(&i->movement);
SER_VAR(&i->inhabit);
SER_VAR(&i->build);
SER_VAR(&i->dobuild);
SER_VAR(&i->build_type);
SER_VAR(&i->build_rotation);
SER_VAR(&i->grid_index);
}
void des_inputframe(char **in, struct InputFrame *i)
void ser_player(SerState *ser, struct Player *p)
{
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);
SER_VAR(&p->connected);
if (p->connected)
{
ser_int(out, p->currently_inhabiting_index);
ser_V2(out, p->pos);
ser_V2(out, p->vel);
ser_float(out, p->spice_taken_away);
ser_float(out, p->goldness);
ser_inputframe(out, &p->input);
SER_VAR(&p->currently_inhabiting_index);
ser_V2(ser, &p->pos);
ser_V2(ser, &p->vel);
SER_VAR(&p->spice_taken_away);
SER_VAR(&p->goldness);
ser_inputframe(ser, &p->input);
}
}
void des_player(char **in, struct Player *p, struct GameState *gs)
void ser_server_to_client(SerState *ser, ServerToClient *s)
{
des_bool(in, &p->connected);
if (p->connected)
{
des_int(in, &p->currently_inhabiting_index);
des_V2(in, &p->pos);
des_V2(in, &p->vel);
des_float(in, &p->spice_taken_away);
des_float(in, &p->goldness);
struct GameState *gs = s->cur_gs;
des_inputframe(in, &p->input);
if (!ser->serializing)
{
destroy(gs);
initialize(gs);
}
}
// @Robust really think about if <= makes more sense than < here...
#define LEN_CHECK() assert(bytes - original_bytes <= max_len)
SER_VAR(&s->your_player);
SER_VAR(&gs->tick);
SER_VAR(&gs->time);
void into_bytes(struct ServerToClient *msg, char *bytes, int *out_len, int max_len)
{
assert(msg->cur_gs != NULL);
assert(msg != NULL);
struct GameState *gs = msg->cur_gs;
char *original_bytes = bytes;
ser_int(&bytes, msg->your_player);
LEN_CHECK();
ser_uint64(&bytes, gs->tick);
ser_double(&bytes, gs->time);
LEN_CHECK();
ser_V2(&bytes, gs->goldpos);
LEN_CHECK();
ser_V2(ser, &gs->goldpos);
for (int i = 0; i < MAX_PLAYERS; i++)
{
ser_player(&bytes, &gs->players[i]);
LEN_CHECK();
ser_player(ser, &gs->players[i]);
}
// @Robust invalid message on num boxes bigger than max boxes
for (int i = 0; i < MAX_GRIDS; i++)
{
bool exists = gs->grids[i].body != NULL;
ser_bool(&bytes, exists);
LEN_CHECK();
bool exists;
if (ser->serializing)
exists = gs->grids[i].body != NULL;
SER_VAR(&exists);
if (exists)
{
ser_grid(&bytes, &gs->grids[i]);
LEN_CHECK();
ser_grid(ser, gs, &gs->grids[i]);
}
}
*out_len = bytes - original_bytes;
}
void from_bytes(struct ServerToClient *msg, char *bytes, int max_len)
void into_bytes(struct ServerToClient *msg, char *bytes, int *out_len, int max_len)
{
struct GameState *gs = msg->cur_gs;
char *original_bytes = bytes;
destroy(gs);
initialize(gs);
des_int(&bytes, &msg->your_player);
LEN_CHECK();
assert(msg->cur_gs != NULL);
assert(msg != NULL);
des_uint64(&bytes, &gs->tick);
LEN_CHECK();
SerState ser = (SerState){
.bytes = bytes,
.serializing = true,
.cursor = 0,
.max_size = max_len,
};
des_double(&bytes, &gs->time);
LEN_CHECK();
ser_server_to_client(&ser, msg);
*out_len = ser.cursor + 1; // @Robust not sure why I need to add one to cursor, ser.cursor should be the length..
}
des_V2(&bytes, &gs->goldpos);
LEN_CHECK();
void from_bytes(struct ServerToClient *msg, char *bytes, int max_len)
{
assert(msg->cur_gs != NULL);
assert(msg != NULL);
for (int i = 0; i < MAX_PLAYERS; i++)
{
des_player(&bytes, &gs->players[i], gs);
LEN_CHECK();
}
SerState ser = (SerState){
.bytes = bytes,
.serializing = false,
.cursor = 0,
.max_size = max_len,
};
for (int i = 0; i < MAX_GRIDS; i++)
{
bool exists = false;
des_bool(&bytes, &exists);
LEN_CHECK();
if (exists)
{
des_grid(&bytes, &gs->grids[i], gs);
LEN_CHECK();
}
}
ser_server_to_client(&ser, msg);
}
// has to be global var because can only get this information
@ -552,7 +698,7 @@ 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, rotangle(box->compass_rotation));
to_return = V2rotate(to_return, box_rotation(box));
return to_return;
@ -572,6 +718,7 @@ void process(struct GameState *gs, float dt)
{
assert(gs->space != NULL);
assert(dt == TIMESTEP); // @TODO fix tick being incremented every time
gs->tick += 1;
gs->time += dt;
@ -690,7 +837,7 @@ void process(struct GameState *gs, float dt)
float needed_energy = wanted_thrust * THRUSTER_ENERGY_USED_PER_SECOND * dt;
energy_available -= needed_energy;
if(energy_available > 0.0f)
if (energy_available > 0.0f)
g->boxes[ii].thrust = wanted_thrust;
else
g->boxes[ii].thrust = 0.0f;
@ -723,23 +870,12 @@ void process(struct GameState *gs, float dt)
}
else if (p->input.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;
}
}
// @Robust cleanly fail when not enough grids
assert(empty_grid != NULL);
struct Grid *empty_grid = find_empty_grid(gs);
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;
empty_grid->boxes[0].compass_rotation = p->input.build_rotation;
cpBodySetVelocity(empty_grid->body, v2_to_cp(p->vel));
}
else
@ -760,7 +896,7 @@ void process(struct GameState *gs, float dt)
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;
empty_box->compass_rotation = p->input.build_rotation;
}
}
@ -819,9 +955,9 @@ void process(struct GameState *gs, float dt)
}
gs->grids[i].total_energy_capacity = 0.0f;
for(int ii = 0; ii < batteries_len; ii++)
for (int ii = 0; ii < batteries_len; ii++)
{
gs->grids[i].total_energy_capacity += 1.0f - batteries[ii]->energy_used;
gs->grids[i].total_energy_capacity += 1.0f - batteries[ii]->energy_used;
}
}

@ -595,7 +595,7 @@ static void frame(void)
}
sgp_push_transform();
sgp_rotate_at(grid_rotation(g) + rotangle(b->rotation), box_pos(b).x, box_pos(b).y);
sgp_rotate_at(grid_rotation(g) + rotangle(b->compass_rotation), box_pos(b).x, box_pos(b).y);
if (b->type == BoxThruster)
{

@ -25,11 +25,11 @@ void server(void *data)
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;
gs.grids[0].boxes[3].compass_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;
gs.grids[0].boxes[4].compass_rotation = Up;
grid_new(&gs.grids[1], &gs, (V2){.x = -BOX_SIZE*1.5, .y = 0.0});

@ -71,7 +71,7 @@ enum BoxType
BoxLast,
};
enum Rotation
enum CompassRotation
{
Right,
Down,
@ -90,7 +90,7 @@ struct InputFrame
V2 build;
bool dobuild;
enum BoxType build_type;
enum Rotation build_rotation;
enum CompassRotation build_rotation;
int grid_index;
};
@ -131,11 +131,11 @@ struct GameState
struct Box
{
enum BoxType type;
enum Rotation rotation;
enum CompassRotation compass_rotation; // @Robust rename to compass_rotation
// thruster
float thrust; // must be between 0 and 1
// battery
float energy_used; // must be between 0 and 1
@ -148,7 +148,7 @@ struct GameState
#define PI 3.14159f
// returns in radians
static float rotangle(enum Rotation rot)
static float rotangle(enum CompassRotation rot)
{
switch (rot)
{
@ -171,11 +171,11 @@ static float rotangle(enum Rotation rot)
}
}
struct ServerToClient
typedef struct ServerToClient
{
struct GameState *cur_gs;
int your_player;
};
} ServerToClient;
struct ClientToServer
{
@ -208,6 +208,7 @@ V2 grid_snapped_box_pos(struct Grid *grid, V2 world); // returns the snapped pos
float grid_rotation(struct Grid *grid);
float grid_angular_velocity(struct Grid *grid);
void box_new(struct Box *to_modify, struct GameState *gs, struct Grid *grid, V2 pos);
V2 box_local_pos(struct Box *box);
V2 box_pos(struct Box *box);
float box_rotation(struct Box *box);

Loading…
Cancel
Save