@ -17,7 +17,7 @@ enum
BOXES = 1 < < 1 ,
BOXES = 1 < < 1 ,
} ;
} ;
void __assert ( bool cond , const char * file , int line , const char * cond_string )
void __assert ( bool cond , const char * file , int line , const char * cond_string )
{
{
if ( ! cond )
if ( ! cond )
{
{
@ -29,7 +29,7 @@ void __assert(bool cond, const char *file, int line, const char *cond_string)
static V2 cp_to_v2 ( cpVect v )
static V2 cp_to_v2 ( cpVect v )
{
{
return ( V2 ) { . x = v . x , . y = v . y } ;
return ( V2 ) { . x = ( float ) v . x , . y = ( float ) v . y } ;
}
}
static cpVect v2_to_cp ( V2 v )
static cpVect v2_to_cp ( V2 v )
@ -37,15 +37,15 @@ static cpVect v2_to_cp(V2 v)
return cpv ( v . x , v . y ) ;
return cpv ( v . x , v . y ) ;
}
}
bool was_entity_deleted ( struct GameState * gs , EntityID id )
bool was_entity_deleted ( struct GameState * gs , EntityID id )
{
{
if ( id . generation = = 0 ) return false ; // generation 0 means null entity ID, not a deleted entity
if ( id . generation = = 0 ) return false ; // generation 0 means null entity ID, not a deleted entity
Entity * the_entity = & gs - > entities [ id . index ] ;
Entity * the_entity = & gs - > entities [ id . index ] ;
return ( ! the_entity - > exists | | the_entity - > generation ! = id . generation ) ;
return ( ! the_entity - > exists | | the_entity - > generation ! = id . generation ) ;
}
}
// may return null if it doesn't exist anymore
// may return null if it doesn't exist anymore
Entity * get_entity ( struct GameState * gs , EntityID id )
Entity * get_entity ( struct GameState * gs , EntityID id )
{
{
if ( id . generation = = 0 )
if ( id . generation = = 0 )
{
{
@ -53,43 +53,43 @@ Entity *get_entity(struct GameState *gs, EntityID id)
}
}
assert ( id . index < gs - > cur_next_entity ) ;
assert ( id . index < gs - > cur_next_entity ) ;
assert ( id . index < gs - > max_entities ) ;
assert ( id . index < gs - > max_entities ) ;
Entity * to_return = & gs - > entities [ id . index ] ;
Entity * to_return = & gs - > entities [ id . index ] ;
if ( was_entity_deleted ( gs , id ) )
if ( was_entity_deleted ( gs , id ) )
return NULL ;
return NULL ;
return to_return ;
return to_return ;
}
}
EntityID get_id ( struct GameState * gs , Entity * e )
EntityID get_id ( struct GameState * gs , Entity * e )
{
{
if ( e = = NULL )
if ( e = = NULL )
return ( EntityID ) { 0 } ;
return ( EntityID ) { 0 } ;
in t index = e - gs - > entities ;
size_ t index = e - gs - > entities ;
assert ( index > = 0 ) ;
assert ( index > = 0 ) ;
assert ( index < gs - > cur_next_entity ) ;
assert ( index < gs - > cur_next_entity ) ;
return ( EntityID ) {
return ( EntityID ) {
. generation = e - > generation ,
. generation = e - > generation ,
. index = index ,
. index = index ,
} ;
} ;
}
}
static Entity * cp_shape_entity ( cpShape * shape )
static Entity * cp_shape_entity ( cpShape * shape )
{
{
return ( Entity * ) cpShapeGetUserData ( shape ) ;
return ( Entity * ) cpShapeGetUserData ( shape ) ;
}
}
static Entity * cp_body_entity ( cpBody * body )
static Entity * cp_body_entity ( cpBody * body )
{
{
return ( Entity * ) cpBodyGetUserData ( body ) ;
return ( Entity * ) cpBodyGetUserData ( body ) ;
}
}
static struct GameState * cp_space_gs ( cpSpace * space )
static struct GameState * cp_space_gs ( cpSpace * space )
{
{
return ( struct GameState * ) cpSpaceGetUserData ( space ) ;
return ( struct GameState * ) cpSpaceGetUserData ( space ) ;
}
}
int grid_num_boxes ( struct GameState * gs , Entity * e )
int grid_num_boxes ( struct GameState * gs , Entity * e )
{
{
assert ( e - > is_grid ) ;
assert ( e - > is_grid ) ;
int to_return = 0 ;
int to_return = 0 ;
@ -100,11 +100,11 @@ int grid_num_boxes(struct GameState *gs, Entity *e)
return to_return ;
return to_return ;
}
}
void box_remove_from_boxes ( GameState * gs , Entity * box )
void box_remove_from_boxes ( GameState * gs , Entity * box )
{
{
assert ( box - > is_box ) ;
assert ( box - > is_box ) ;
Entity * prev_box = get_entity ( gs , box - > prev_box ) ;
Entity * prev_box = get_entity ( gs , box - > prev_box ) ;
Entity * next_box = get_entity ( gs , box - > next_box ) ;
Entity * next_box = get_entity ( gs , box - > next_box ) ;
if ( prev_box ! = NULL )
if ( prev_box ! = NULL )
{
{
if ( prev_box - > is_box )
if ( prev_box - > is_box )
@ -117,12 +117,12 @@ void box_remove_from_boxes(GameState *gs, Entity *box)
assert ( next_box - > is_box ) ;
assert ( next_box - > is_box ) ;
next_box - > prev_box = get_id ( gs , prev_box ) ;
next_box - > prev_box = get_id ( gs , prev_box ) ;
}
}
box - > next_box = ( EntityID ) { 0 } ;
box - > next_box = ( EntityID ) { 0 } ;
box - > prev_box = ( EntityID ) { 0 } ;
box - > prev_box = ( EntityID ) { 0 } ;
}
}
void on_entity_child_shape ( cpBody * body , cpShape * shape , void * data ) ;
void on_entity_child_shape ( cpBody * body , cpShape * shape , void * data ) ;
void entity_destroy ( GameState * gs , Entity * e )
void entity_destroy ( GameState * gs , Entity * e )
{
{
assert ( e - > exists ) ;
assert ( e - > exists ) ;
@ -152,11 +152,11 @@ void entity_destroy(GameState *gs, Entity *e)
e - > body = NULL ;
e - > body = NULL ;
e - > shape = NULL ;
e - > shape = NULL ;
Entity * front_of_free_list = get_entity ( gs , gs - > free_list ) ;
Entity * front_of_free_list = get_entity ( gs , gs - > free_list ) ;
if ( front_of_free_list ! = NULL )
if ( front_of_free_list ! = NULL )
assert ( ! front_of_free_list - > exists ) ;
assert ( ! front_of_free_list - > exists ) ;
int gen = e - > generation ;
int gen = e - > generation ;
* e = ( Entity ) { 0 } ;
* e = ( Entity ) { 0 } ;
e - > generation = gen ;
e - > generation = gen ;
e - > next_free_entity = gs - > free_list ;
e - > next_free_entity = gs - > free_list ;
gs - > free_list = get_id ( gs , e ) ;
gs - > free_list = get_id ( gs , e ) ;
@ -167,9 +167,9 @@ void on_entity_child_shape(cpBody* body, cpShape* shape, void* data)
entity_destroy ( ( GameState * ) data , cp_shape_entity ( shape ) ) ;
entity_destroy ( ( GameState * ) data , cp_shape_entity ( shape ) ) ;
}
}
Entity * new_entity ( struct GameState * gs )
Entity * new_entity ( struct GameState * gs )
{
{
Entity * to_return = NULL ;
Entity * to_return = NULL ;
if ( get_entity ( gs , gs - > free_list ) ! = NULL )
if ( get_entity ( gs , gs - > free_list ) ! = NULL )
{
{
to_return = get_entity ( gs , gs - > free_list ) ;
to_return = get_entity ( gs , gs - > free_list ) ;
@ -188,7 +188,7 @@ Entity *new_entity(struct GameState *gs)
return to_return ;
return to_return ;
}
}
void create_body ( struct GameState * gs , Entity * e )
void create_body ( struct GameState * gs , Entity * e )
{
{
assert ( gs - > space ! = NULL ) ;
assert ( gs - > space ! = NULL ) ;
@ -199,18 +199,18 @@ void create_body(struct GameState *gs, Entity *e)
e - > body = NULL ;
e - > body = NULL ;
}
}
cpBody * body = cpSpaceAddBody ( gs - > space , cpBodyNew ( 0.0 , 0.0 ) ) ; // zeros for mass/moment of inertia means automatically calculated from its collision shapes
cpBody * body = cpSpaceAddBody ( gs - > space , cpBodyNew ( 0.0 , 0.0 ) ) ; // zeros for mass/moment of inertia means automatically calculated from its collision shapes
e - > body = body ;
e - > body = body ;
cpBodySetUserData ( e - > body , ( void * ) e ) ;
cpBodySetUserData ( e - > body , ( void * ) e ) ;
}
}
void grid_create ( struct GameState * gs , Entity * e )
void grid_create ( struct GameState * gs , Entity * e )
{
{
e - > is_grid = true ;
e - > is_grid = true ;
create_body ( gs , e ) ;
create_body ( gs , e ) ;
}
}
void entity_set_pos ( Entity * e , V2 pos )
void entity_set_pos ( Entity * e , V2 pos )
{
{
assert ( e - > is_grid ) ;
assert ( e - > is_grid ) ;
assert ( e - > body ! = NULL ) ;
assert ( e - > body ! = NULL ) ;
@ -218,7 +218,7 @@ void entity_set_pos(Entity *e, V2 pos)
}
}
// size is (1/2 the width, 1/2 the height)
// size is (1/2 the width, 1/2 the height)
void create_rectangle_shape ( GameState * gs , Entity * e , Entity * parent , V2 pos , V2 size , float mass )
void create_rectangle_shape ( GameState * gs , Entity * e , Entity * parent , V2 pos , V2 size , float mass )
{
{
if ( e - > shape ! = NULL )
if ( e - > shape ! = NULL )
{
{
@ -237,23 +237,23 @@ void create_rectangle_shape(GameState *gs, Entity *e, Entity *parent, V2 pos, V2
e - > shape_size = size ;
e - > shape_size = size ;
e - > shape_parent_entity = get_id ( gs , parent ) ;
e - > shape_parent_entity = get_id ( gs , parent ) ;
e - > shape = ( cpShape * ) cpPolyShapeInitRaw ( cpPolyShapeAlloc ( ) , parent - > body , 4 , verts , 0.0f ) ; // this cast is done in chipmunk, not sure why it works
e - > shape = ( cpShape * ) cpPolyShapeInitRaw ( cpPolyShapeAlloc ( ) , parent - > body , 4 , verts , 0.0f ) ; // this cast is done in chipmunk, not sure why it works
cpShapeSetUserData ( e - > shape , ( void * ) e ) ;
cpShapeSetUserData ( e - > shape , ( void * ) e ) ;
cpShapeSetMass ( e - > shape , mass ) ;
cpShapeSetMass ( e - > shape , mass ) ;
cpSpaceAddShape ( gs - > space , e - > shape ) ;
cpSpaceAddShape ( gs - > space , e - > shape ) ;
}
}
void create_player ( struct GameState * gs , Entity * e )
void create_player ( struct GameState * gs , Entity * e )
{
{
e - > is_player = true ;
e - > is_player = true ;
create_body ( gs , e ) ;
create_body ( gs , e ) ;
create_rectangle_shape ( gs , e , e , ( V2 ) { 0 } , V2scale ( PLAYER_SIZE , 0.5f ) , PLAYER_MASS ) ;
create_rectangle_shape ( gs , e , e , ( V2 ) { 0 } , V2scale ( PLAYER_SIZE , 0.5f ) , PLAYER_MASS ) ;
cpShapeSetFilter ( e - > shape , cpShapeFilterNew ( CP_NO_GROUP , PLAYERS , CP_ALL_CATEGORIES ) ) ;
cpShapeSetFilter ( e - > shape , cpShapeFilterNew ( CP_NO_GROUP , PLAYERS , CP_ALL_CATEGORIES ) ) ;
}
}
// box must be passed as a parameter as the box added to chipmunk uses this pointer in its
// box must be passed as a parameter as the box added to chipmunk uses this pointer in its
// user data. pos is in local coordinates. Adds the box to the grid's chain of boxes
// user data. pos is in local coordinates. Adds the box to the grid's chain of boxes
void box_create ( struct GameState * gs , Entity * new_box , Entity * grid , V2 pos )
void box_create ( struct GameState * gs , Entity * new_box , Entity * grid , V2 pos )
{
{
new_box - > is_box = true ;
new_box - > is_box = true ;
assert ( gs - > space ! = NULL ) ;
assert ( gs - > space ! = NULL ) ;
@ -261,7 +261,7 @@ void box_create(struct GameState *gs, Entity *new_box, Entity *grid, V2 pos)
float halfbox = BOX_SIZE / 2.0f ;
float halfbox = BOX_SIZE / 2.0f ;
create_rectangle_shape ( gs , new_box , grid , pos , ( V2 ) { halfbox , halfbox } , 1.0f ) ;
create_rectangle_shape ( gs , new_box , grid , pos , ( V2 ) { halfbox , halfbox } , 1.0f ) ;
cpShapeSetFilter ( new_box - > shape , cpShapeFilterNew ( CP_NO_GROUP , BOXES , CP_ALL_CATEGORIES ) ) ;
cpShapeSetFilter ( new_box - > shape , cpShapeFilterNew ( CP_NO_GROUP , BOXES , CP_ALL_CATEGORIES ) ) ;
@ -276,7 +276,7 @@ void box_create(struct GameState *gs, Entity *new_box, Entity *grid, V2 pos)
// 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_remove_box ( struct GameState * gs , struct Entity * grid , struct Entity * box )
static void grid_remove_box ( struct GameState * gs , struct Entity * grid , struct Entity * box )
{
{
assert ( grid - > is_grid ) ;
assert ( grid - > is_grid ) ;
assert ( box - > is_box ) ;
assert ( box - > is_box ) ;
@ -300,7 +300,7 @@ static void grid_remove_box(struct GameState *gs, struct Entity *grid, struct En
// The other "real grids" are allocated as new grids
// The other "real grids" are allocated as new grids
# define MAX_SEPARATE_GRIDS 8
# define MAX_SEPARATE_GRIDS 8
EntityID separate_grids [ MAX_SEPARATE_GRIDS ] = { 0 } ;
EntityID separate_grids [ MAX_SEPARATE_GRIDS ] = { 0 } ;
int cur_separate_grid_index = 0 ;
int cur_separate_grid_index = 0 ;
int cur_separate_grid_size = 0 ;
int cur_separate_grid_size = 0 ;
int processed_boxes = 0 ;
int processed_boxes = 0 ;
@ -312,7 +312,7 @@ static void grid_remove_box(struct GameState *gs, struct Entity *grid, struct En
while ( processed_boxes < num_boxes )
while ( processed_boxes < num_boxes )
{
{
// grab an unprocessed box, one not in separate_grids, to start the flood fill
// grab an unprocessed box, one not in separate_grids, to start the flood fill
Entity * unprocessed = get_entity ( gs , grid - > boxes ) ;
Entity * unprocessed = get_entity ( gs , grid - > boxes ) ;
assert ( unprocessed ! = NULL ) ;
assert ( unprocessed ! = NULL ) ;
assert ( unprocessed - > is_box ) ;
assert ( unprocessed - > is_box ) ;
box_remove_from_boxes ( gs , unprocessed ) ; // no longer in the boxes list of the grid
box_remove_from_boxes ( gs , unprocessed ) ; // no longer in the boxes list of the grid
@ -323,7 +323,7 @@ static void grid_remove_box(struct GameState *gs, struct Entity *grid, struct En
{
{
// queue stuff @Robust use factored datastructure
// queue stuff @Robust use factored datastructure
EntityID Q = get_id ( gs , unprocessed ) ;
EntityID Q = get_id ( gs , unprocessed ) ;
Entity * N = NULL ;
Entity * N = NULL ;
while ( true )
while ( true )
{
{
assert ( ! was_entity_deleted ( gs , Q ) ) ;
assert ( ! was_entity_deleted ( gs , Q ) ) ;
@ -340,10 +340,18 @@ static void grid_remove_box(struct GameState *gs, struct Entity *grid, struct En
V2 cur_local_pos = entity_shape_pos ( N ) ;
V2 cur_local_pos = entity_shape_pos ( N ) ;
const V2 dirs [ ] = {
const V2 dirs [ ] = {
( V2 ) { . x = - 1.0f , . y = 0.0f } ,
( V2 ) {
( V2 ) { . x = 1.0f , . y = 0.0f } ,
. x = - 1.0f , . y = 0.0f
( V2 ) { . x = 0.0f , . y = 1.0f } ,
} ,
( V2 ) { . x = 0.0f , . y = - 1.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 ) ;
int num_dirs = sizeof ( dirs ) / sizeof ( * dirs ) ;
@ -353,7 +361,7 @@ static void grid_remove_box(struct GameState *gs, struct Entity *grid, struct En
// @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 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 } ;
EntityID box_in_direction = ( EntityID ) { 0 } ;
BOXES_ITER ( gs , cur , grid )
BOXES_ITER ( gs , cur , grid )
{
{
if ( V2cmp ( entity_shape_pos ( cur ) , wanted_local_pos , 0.01f ) )
if ( V2cmp ( entity_shape_pos ( cur ) , wanted_local_pos , 0.01f ) )
@ -363,7 +371,7 @@ static void grid_remove_box(struct GameState *gs, struct Entity *grid, struct En
}
}
}
}
Entity * newbox = get_entity ( gs , box_in_direction ) ;
Entity * newbox = get_entity ( gs , box_in_direction ) ;
if ( newbox ! = NULL )
if ( newbox ! = NULL )
{
{
box_remove_from_boxes ( gs , newbox ) ;
box_remove_from_boxes ( gs , newbox ) ;
@ -394,7 +402,7 @@ static void grid_remove_box(struct GameState *gs, struct Entity *grid, struct En
if ( get_entity ( gs , cur_separate_grid ) = = NULL )
if ( get_entity ( gs , cur_separate_grid ) = = NULL )
continue ; // this separate grid is empty
continue ; // this separate grid is empty
Entity * new_grid ;
Entity * new_grid ;
if ( sepgrid_i = = biggest_separate_grid_index )
if ( sepgrid_i = = biggest_separate_grid_index )
{
{
new_grid = grid ;
new_grid = grid ;
@ -407,23 +415,23 @@ static void grid_remove_box(struct GameState *gs, struct Entity *grid, struct En
cpBodySetAngle ( new_grid - > body , cpBodyGetAngle ( grid - > body ) ) ;
cpBodySetAngle ( new_grid - > body , cpBodyGetAngle ( grid - > body ) ) ;
}
}
Entity * cur = get_entity ( gs , cur_separate_grid ) ;
Entity * cur = get_entity ( gs , cur_separate_grid ) ;
while ( cur ! = NULL )
while ( cur ! = NULL )
{
{
Entity * next = get_entity ( gs , cur - > next_box ) ;
Entity * next = get_entity ( gs , cur - > next_box ) ;
box_create ( gs , cur , new_grid , entity_shape_pos ( cur ) ) ; // destroys next/prev fields on cur
box_create ( gs , cur , new_grid , entity_shape_pos ( cur ) ) ; // destroys next/prev fields on cur
cur = next ;
cur = next ;
}
}
cpBodySetVelocity ( new_grid - > body , cpBodyGetVelocityAtWorldPoint ( grid - > body , v2_to_cp ( grid_com ( new_grid ) ) ) ) ;
cpBodySetVelocity ( new_grid - > body , cpBodyGetVelocityAtWorldPoint ( grid - > body , v2_to_cp ( grid_com ( new_grid ) ) ) ) ;
cpBodySetAngularVelocity ( new_grid - > body , grid _angular_velocity( grid ) ) ;
cpBodySetAngularVelocity ( new_grid - > body , entity _angular_velocity( grid ) ) ;
}
}
}
}
static void postStepRemove ( cpSpace * space , void * key , void * data )
static void postStepRemove ( cpSpace * space , void * key , void * data )
{
{
cpShape * b = ( cpShape * ) key ;
cpShape * b = ( cpShape * ) key ;
Entity * e = cp_shape_entity ( b ) ;
Entity * e = cp_shape_entity ( b ) ;
// @Robust why not just do these deletions in the update loop? save on a lot of complexity
// @Robust why not just do these deletions in the update loop? save on a lot of complexity
if ( e - > damage > 1.0f )
if ( e - > damage > 1.0f )
{
{
@ -432,12 +440,12 @@ static void postStepRemove(cpSpace *space, void *key, void *data)
}
}
}
}
static cpBool on_damage ( cpArbiter * arb , cpSpace * space , cpDataPointer userData )
static cpBool on_damage ( cpArbiter * arb , cpSpace * space , cpDataPointer userData )
{
{
cpShape * a , * b ;
cpShape * a , * b ;
cpArbiterGetShapes ( arb , & a , & b ) ;
cpArbiterGetShapes ( arb , & a , & b ) ;
Entity * entity_a , * entity_b ;
Entity * entity_a , * entity_b ;
entity_a = cp_shape_entity ( a ) ;
entity_a = cp_shape_entity ( a ) ;
entity_b = cp_shape_entity ( b ) ;
entity_b = cp_shape_entity ( b ) ;
@ -456,18 +464,18 @@ static cpBool on_damage(cpArbiter *arb, cpSpace *space, cpDataPointer userData)
return true ; // keep colliding
return true ; // keep colliding
}
}
void initialize ( struct GameState * gs , void * entity_arena , int entity_arena_size )
void initialize ( struct GameState * gs , void * entity_arena , int entity_arena_size )
{
{
* gs = ( struct GameState ) { 0 } ;
* gs = ( struct GameState ) { 0 } ;
memset ( entity_arena , 0 , entity_arena_size ) ; // SUPER critical. Random vals in the entity data causes big problem
memset ( entity_arena , 0 , entity_arena_size ) ; // SUPER critical. Random vals in the entity data causes big problem
gs - > entities = ( Entity * ) entity_arena ;
gs - > entities = ( Entity * ) entity_arena ;
gs - > max_entities = entity_arena_size / sizeof ( Entity ) ;
gs - > max_entities = entity_arena_size / sizeof ( Entity ) ;
gs - > space = cpSpaceNew ( ) ;
gs - > space = cpSpaceNew ( ) ;
cpSpaceSetUserData ( gs - > space , ( cpDataPointer ) gs ) ; // needed in the handler
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
cpCollisionHandler * handler = cpSpaceAddCollisionHandler ( gs - > space , 0 , 0 ) ; // @Robust limit collision type to just blocks that can be damaged
handler - > postSolveFunc = on_damage ;
handler - > postSolveFunc = on_damage ;
}
}
void destroy ( struct GameState * gs )
void destroy ( struct GameState * gs )
{
{
// can't zero out gs data because the entity memory arena is reused
// can't zero out gs data because the entity memory arena is reused
// on deserialization
// on deserialization
@ -481,29 +489,29 @@ void destroy(struct GameState *gs)
gs - > cur_next_entity = 0 ;
gs - > cur_next_entity = 0 ;
}
}
// center of mass, not the literal position
// center of mass, not the literal position
V2 grid_com ( Entity * grid )
V2 grid_com ( Entity * grid )
{
{
return cp_to_v2 ( cpBodyLocalToWorld ( grid - > body , cpBodyGetCenterOfGravity ( grid - > body ) ) ) ;
return cp_to_v2 ( cpBodyLocalToWorld ( grid - > body , cpBodyGetCenterOfGravity ( grid - > body ) ) ) ;
}
}
V2 entity_pos ( Entity * grid )
V2 entity_pos ( Entity * grid )
{
{
return cp_to_v2 ( cpBodyGetPosition ( grid - > body ) ) ;
return cp_to_v2 ( cpBodyGetPosition ( grid - > body ) ) ;
}
}
V2 grid_vel ( Entity * grid )
V2 grid_vel ( Entity * grid )
{
{
return cp_to_v2 ( cpBodyGetVelocity ( grid - > body ) ) ;
return cp_to_v2 ( cpBodyGetVelocity ( grid - > body ) ) ;
}
}
V2 grid_world_to_local ( Entity * grid , V2 world )
V2 grid_world_to_local ( Entity * grid , V2 world )
{
{
return cp_to_v2 ( cpBodyWorldToLocal ( grid - > body , v2_to_cp ( world ) ) ) ;
return cp_to_v2 ( cpBodyWorldToLocal ( grid - > body , v2_to_cp ( world ) ) ) ;
}
}
V2 grid_local_to_world ( Entity * grid , V2 local )
V2 grid_local_to_world ( Entity * grid , V2 local )
{
{
return cp_to_v2 ( cpBodyLocalToWorld ( grid - > body , v2_to_cp ( local ) ) ) ;
return cp_to_v2 ( cpBodyLocalToWorld ( grid - > body , v2_to_cp ( local ) ) ) ;
}
}
// returned snapped position is in world coordinates
// returned snapped position is in world coordinates
V2 grid_snapped_box_pos ( Entity * grid , V2 world )
V2 grid_snapped_box_pos ( Entity * grid , V2 world )
{
{
V2 local = grid_world_to_local ( grid , world ) ;
V2 local = grid_world_to_local ( grid , world ) ;
local . x / = BOX_SIZE ;
local . x / = BOX_SIZE ;
@ -515,36 +523,36 @@ V2 grid_snapped_box_pos(Entity *grid, V2 world)
return cp_to_v2 ( cpBodyLocalToWorld ( grid - > body , v2_to_cp ( local ) ) ) ;
return cp_to_v2 ( cpBodyLocalToWorld ( grid - > body , v2_to_cp ( local ) ) ) ;
}
}
float entity_rotation ( Entity * grid )
float entity_rotation ( Entity * grid )
{
{
return cpBodyGetAngle ( grid - > body ) ;
return ( float ) cpBodyGetAngle ( grid - > body ) ;
}
}
float grid_angular_velocity( Entity * grid )
float entity_angular_velocity( Entity * grid )
{
{
return cpBodyGetAngularVelocity ( grid - > body ) ;
return ( float ) cpBodyGetAngularVelocity ( grid - > body ) ;
}
}
Entity * box_grid ( Entity * box )
Entity * box_grid ( Entity * box )
{
{
return ( Entity * ) cpBodyGetUserData ( cpShapeGetBody ( box - > shape ) ) ;
return ( Entity * ) cpBodyGetUserData ( cpShapeGetBody ( box - > shape ) ) ;
}
}
// in local space
// in local space
V2 entity_shape_pos ( Entity * box )
V2 entity_shape_pos ( Entity * box )
{
{
return cp_to_v2 ( cpShapeGetCenterOfGravity ( box - > shape ) ) ;
return cp_to_v2 ( cpShapeGetCenterOfGravity ( box - > shape ) ) ;
}
}
float entity_shape_mass ( Entity * box )
float entity_shape_mass ( Entity * box )
{
{
assert ( box - > shape ! = NULL ) ;
assert ( box - > shape ! = NULL ) ;
return cpShapeGetMass ( box - > shape ) ;
return ( float ) cpShapeGetMass ( box - > shape ) ;
}
}
V2 box_pos ( Entity * box )
V2 box_pos ( Entity * box )
{
{
assert ( box - > is_box ) ;
assert ( box - > is_box ) ;
return V2add ( entity_pos ( box_grid ( box ) ) , V2rotate ( entity_shape_pos ( box ) , entity_rotation ( box_grid ( box ) ) ) ) ;
return V2add ( entity_pos ( box_grid ( box ) ) , V2rotate ( entity_shape_pos ( box ) , entity_rotation ( box_grid ( box ) ) ) ) ;
}
}
float box_rotation ( Entity * box )
float box_rotation ( Entity * box )
{
{
return cpBodyGetAngle ( cpShapeGetBody ( box - > shape ) ) ;
return ( float ) cpBodyGetAngle ( cpShapeGetBody ( box - > shape ) ) ;
}
}
struct BodyData
struct BodyData
@ -555,7 +563,7 @@ struct BodyData
float angular_velocity ;
float angular_velocity ;
} ;
} ;
void populate ( cpBody * body , struct BodyData * data )
void populate ( cpBody * body , struct BodyData * data )
{
{
data - > pos = cp_to_v2 ( cpBodyGetPosition ( body ) ) ;
data - > pos = cp_to_v2 ( cpBodyGetPosition ( body ) ) ;
data - > vel = cp_to_v2 ( cpBodyGetVelocity ( body ) ) ;
data - > vel = cp_to_v2 ( cpBodyGetVelocity ( body ) ) ;
@ -563,7 +571,7 @@ void populate(cpBody *body, struct BodyData *data)
data - > angular_velocity = ( float ) cpBodyGetAngularVelocity ( body ) ;
data - > angular_velocity = ( float ) cpBodyGetAngularVelocity ( body ) ;
}
}
void update_from ( cpBody * body , struct BodyData * data )
void update_from ( cpBody * body , struct BodyData * data )
{
{
cpBodySetPosition ( body , v2_to_cp ( data - > pos ) ) ;
cpBodySetPosition ( body , v2_to_cp ( data - > pos ) ) ;
cpBodySetVelocity ( body , v2_to_cp ( data - > vel ) ) ;
cpBodySetVelocity ( body , v2_to_cp ( data - > vel ) ) ;
@ -571,71 +579,73 @@ void update_from(cpBody *body, struct BodyData *data)
cpBodySetAngularVelocity ( body , data - > angular_velocity ) ;
cpBodySetAngularVelocity ( body , data - > angular_velocity ) ;
}
}
# define WRITE_VARNAMES true // debugging feature horrible for network
# define WRITE_VARNAMES // debugging feature horrible for network
typedef struct SerState
typedef struct SerState
{
{
char * bytes ;
char * bytes ;
bool serializing ;
bool serializing ;
in t cursor ; // points to next available byte, is the size of current message after serializing something
size_ t cursor ; // points to next available byte, is the size of current message after serializing something
in t max_size ;
size_ t max_size ;
} SerState ;
} SerState ;
# define SER_VAR_NAME(var_pointer, name) \
void ser_var ( SerState * ser , char * var_pointer , size_t var_size , const char * name )
{ \
{
const char * var_name = name ; \
const char * var_name = name ;
size_t var_name_len = 0 ; \
# ifdef WRITE_VARNAMES
if ( WRITE_VARNAMES ) \
size_t var_name_len = strlen ( var_name ) ;
{ \
# endif
var_name_len = strlen ( var_name ) ; \
if ( ser - > serializing )
} \
{
if ( ser - > serializing ) \
{ \
# ifdef WRITE_VARNAMES
if ( WRITE_VARNAMES ) \
memcpy ( ser - > bytes + ser - > cursor , var_name , var_name_len ) ;
{ \
ser - > cursor + = var_name_len ;
memcpy ( ser - > bytes + ser - > cursor , var_name , var_name_len ) ; \
# endif
ser - > cursor + = var_name_len ; \
for ( int b = 0 ; b < var_size ; b + + )
} \
{
for ( int b = 0 ; b < sizeof ( * var_pointer ) ; b + + ) \
ser - > bytes [ ser - > cursor ] = var_pointer [ b ] ;
{ \
ser - > cursor + = 1 ;
ser - > bytes [ ser - > cursor ] = ( ( char * ) var_pointer ) [ b ] ; \
assert ( ser - > cursor < ser - > max_size ) ;
ser - > cursor + = 1 ; \
}
assert ( ser - > cursor < ser - > max_size ) ; \
}
} \
else
} \
{
else \
# ifdef WRITE_VARNAMES
{ \
{
if ( WRITE_VARNAMES ) \
char read_name [ 1024 ] = { 0 } ;
{ \
char * read_name = malloc ( sizeof * read_name * ( var_name_len + 1 ) ) ; \
for ( int i = 0 ; i < var_name_len ; i + + )
for ( int i = 0 ; i < var_name_len ; i + + ) \
{
{ \
read_name [ i ] = ser - > bytes [ ser - > cursor ] ;
read_name [ i ] = ser - > bytes [ ser - > cursor ] ; \
ser - > cursor + = 1 ;
ser - > cursor + = 1 ; \
assert ( ser - > cursor < ser - > max_size ) ;
assert ( ser - > cursor < ser - > max_size ) ; \
}
} \
read_name [ var_name_len ] = ' \0 ' ;
read_name [ var_name_len ] = ' \0 ' ; \
if ( strcmp ( read_name , var_name ) ! = 0 )
if ( strcmp ( read_name , var_name ) ! = 0 ) \
{
{ \
printf ( " %s:%d | Expected variable %s but got %sn \n " , __FILE__ , __LINE__ , var_name , read_name ) ;
printf ( " %s:%d | Expected variable %s but got %s \n " , __FILE__ , __LINE__ , var_name , read_name ) ; \
* ( char * ) NULL = 0 ;
} \
}
free ( read_name ) ; \
}
} \
# endif
for ( int b = 0 ; b < sizeof ( * var_pointer ) ; b + + ) \
for ( int b = 0 ; b < var_size ; b + + )
{ \
{
( ( char * ) var_pointer ) [ b ] = ser - > bytes [ ser - > cursor ] ; \
var_pointer [ b ] = ser - > bytes [ ser - > cursor ] ;
ser - > cursor + = 1 ; \
ser - > cursor + = 1 ;
assert ( ser - > cursor < ser - > max_size ) ; \
assert ( ser - > cursor < ser - > max_size ) ;
} \
}
} \
}
}
}
# define SER_VAR_NAME(var_pointer, name) ser_var(ser, (char*)var_pointer, sizeof(var_pointer), name)
# define SER_VAR(var_pointer) SER_VAR_NAME(var_pointer, #var_pointer)
# define SER_VAR(var_pointer) SER_VAR_NAME(var_pointer, #var_pointer)
void ser_V2 ( SerState * ser , V2 * var )
void ser_V2 ( SerState * ser , V2 * var )
{
{
SER_VAR ( & var - > x ) ;
SER_VAR ( & var - > x ) ;
SER_VAR ( & var - > y ) ;
SER_VAR ( & var - > y ) ;
}
}
void ser_bodydata ( SerState * ser , struct BodyData * data )
void ser_bodydata ( SerState * ser , struct BodyData * data )
{
{
ser_V2 ( ser , & data - > pos ) ;
ser_V2 ( ser , & data - > pos ) ;
ser_V2 ( ser , & data - > vel ) ;
ser_V2 ( ser , & data - > vel ) ;
@ -643,13 +653,13 @@ void ser_bodydata(SerState *ser, struct BodyData *data)
SER_VAR ( & data - > angular_velocity ) ;
SER_VAR ( & data - > angular_velocity ) ;
}
}
void ser_entityid ( SerState * ser , EntityID * id )
void ser_entityid ( SerState * ser , EntityID * id )
{
{
SER_VAR ( & id - > generation ) ;
SER_VAR ( & id - > generation ) ;
SER_VAR ( & id - > index ) ;
SER_VAR ( & id - > index ) ;
}
}
void ser_inputframe ( SerState * ser , struct InputFrame * i )
void ser_inputframe ( SerState * ser , struct InputFrame * i )
{
{
SER_VAR ( & i - > movement ) ;
SER_VAR ( & i - > movement ) ;
SER_VAR ( & i - > inhabit ) ;
SER_VAR ( & i - > inhabit ) ;
@ -660,7 +670,7 @@ void ser_inputframe(SerState *ser, struct InputFrame *i)
ser_entityid ( ser , & i - > grid_to_build_on ) ;
ser_entityid ( ser , & i - > grid_to_build_on ) ;
}
}
void ser_player ( SerState * ser , struct Player * p )
void ser_player ( SerState * ser , struct Player * p )
{
{
SER_VAR ( & p - > connected ) ;
SER_VAR ( & p - > connected ) ;
if ( p - > connected )
if ( p - > connected )
@ -670,7 +680,7 @@ void ser_player(SerState *ser, struct Player *p)
}
}
}
}
void ser_entity ( SerState * ser , struct GameState * gs , Entity * e )
void ser_entity ( SerState * ser , struct GameState * gs , Entity * e )
{
{
SER_VAR ( & e - > generation ) ;
SER_VAR ( & e - > generation ) ;
SER_VAR ( & e - > damage ) ;
SER_VAR ( & e - > damage ) ;
@ -708,16 +718,16 @@ void ser_entity(SerState *ser, struct GameState *gs, Entity *e)
float shape_mass ;
float shape_mass ;
if ( ser - > serializing )
if ( ser - > serializing )
shape_mass = entity_shape_mass ( e ) ;
shape_mass = entity_shape_mass ( e ) ;
SER_VAR ( & shape_mass )
SER_VAR ( & shape_mass ) ;
Entity * parent = get_entity ( gs , e - > shape_parent_entity ) ;
Entity * parent = get_entity ( gs , e - > shape_parent_entity ) ;
if ( parent = = NULL )
if ( parent = = NULL )
{
{
printf ( " Null shape parent \n " ) ;
printf ( " Null shape parent \n " ) ;
}
}
if ( ! ser - > serializing )
if ( ! ser - > serializing )
{
{
create_rectangle_shape ( gs , e , parent , shape_pos , e - > shape_size , shape_mass ) ;
create_rectangle_shape ( gs , e , parent , shape_pos , e - > shape_size , shape_mass ) ;
}
}
}
}
@ -748,9 +758,9 @@ void ser_entity(SerState *ser, struct GameState *gs, Entity *e)
}
}
}
}
void ser_server_to_client ( SerState * ser , ServerToClient * s )
void ser_server_to_client ( SerState * ser , ServerToClient * s )
{
{
struct GameState * gs = s - > cur_gs ;
struct GameState * gs = s - > cur_gs ;
int cur_next_entity = 0 ;
int cur_next_entity = 0 ;
if ( ser - > serializing )
if ( ser - > serializing )
@ -760,7 +770,7 @@ void ser_server_to_client(SerState *ser, ServerToClient *s)
if ( ! ser - > serializing )
if ( ! ser - > serializing )
{
{
destroy ( gs ) ;
destroy ( gs ) ;
memset ( ( void * ) gs - > entities , 0 , sizeof ( * gs - > entities ) * gs - > max_entities ) ;
memset ( ( void * ) gs - > entities , 0 , sizeof ( * gs - > entities ) * gs - > max_entities ) ;
initialize ( gs , gs - > entities , gs - > max_entities * sizeof ( * gs - > entities ) ) ;
initialize ( gs , gs - > entities , gs - > max_entities * sizeof ( * gs - > entities ) ) ;
gs - > cur_next_entity = cur_next_entity ;
gs - > cur_next_entity = cur_next_entity ;
}
}
@ -779,15 +789,15 @@ void ser_server_to_client(SerState *ser, ServerToClient *s)
{
{
for ( int i = 0 ; i < gs - > cur_next_entity ; i + + )
for ( int i = 0 ; i < gs - > cur_next_entity ; i + + )
{
{
Entity * e = & gs - > entities [ i ] ;
Entity * e = & gs - > entities [ i ] ;
if ( e - > exists )
if ( e - > exists )
{
{
if ( e - > is_player )
if ( e - > is_player )
{
{
SER_VAR ( & i ) ;
SER_VAR ( & i ) ;
ser_entity ( ser , gs , e ) ;
ser_entity ( ser , gs , e ) ;
}
}
else if ( e - > is_grid )
else if ( e - > is_grid )
{
{
// serialize boxes always after bodies, so that by the time the boxes
// serialize boxes always after bodies, so that by the time the boxes
// are loaded in the parent body is loaded in and can be referenced.
// are loaded in the parent body is loaded in and can be referenced.
@ -814,14 +824,14 @@ void ser_server_to_client(SerState *ser, ServerToClient *s)
if ( next_index = = - 1 )
if ( next_index = = - 1 )
break ;
break ;
assert ( next_index < gs - > max_entities ) ;
assert ( next_index < gs - > max_entities ) ;
Entity * e = & gs - > entities [ next_index ] ;
Entity * e = & gs - > entities [ next_index ] ;
e - > exists = true ;
e - > exists = true ;
ser_entity ( ser , gs , e ) ;
ser_entity ( ser , gs , e ) ;
gs - > cur_next_entity = max ( gs - > cur_next_entity , next_index + 1 ) ;
gs - > cur_next_entity = max ( gs - > cur_next_entity , next_index + 1 ) ;
}
}
for ( int i = 0 ; i < gs - > cur_next_entity ; i + + )
for ( int i = 0 ; i < gs - > cur_next_entity ; i + + )
{
{
Entity * e = & gs - > entities [ i ] ;
Entity * e = & gs - > entities [ i ] ;
if ( ! e - > exists )
if ( ! e - > exists )
{
{
e - > next_free_entity = gs - > free_list ;
e - > next_free_entity = gs - > free_list ;
@ -831,7 +841,7 @@ void ser_server_to_client(SerState *ser, ServerToClient *s)
}
}
}
}
void into_bytes ( struct ServerToClient * msg , char * bytes , int * out_len , in t max_len )
void into_bytes ( struct ServerToClient * msg , char * bytes , size_t * out_len , size_ t max_len )
{
{
assert ( msg - > cur_gs ! = NULL ) ;
assert ( msg - > cur_gs ! = NULL ) ;
assert ( msg ! = NULL ) ;
assert ( msg ! = NULL ) ;
@ -847,7 +857,7 @@ void into_bytes(struct ServerToClient *msg, char *bytes, int *out_len, int max_l
* out_len = ser . cursor + 1 ; // @Robust not sure why I need to add one to cursor, ser.cursor should be the length..
* out_len = ser . cursor + 1 ; // @Robust not sure why I need to add one to cursor, ser.cursor should be the length..
}
}
void from_bytes ( struct ServerToClient * msg , char * bytes , in t max_len )
void from_bytes ( struct ServerToClient * msg , char * bytes , size_ t max_len )
{
{
assert ( msg - > cur_gs ! = NULL ) ;
assert ( msg - > cur_gs ! = NULL ) ;
assert ( msg ! = NULL ) ;
assert ( msg ! = NULL ) ;
@ -863,9 +873,9 @@ void from_bytes(struct ServerToClient *msg, char *bytes, int max_len)
}
}
// has to be global var because can only get this information
// has to be global var because can only get this information
static cpShape * closest_to_point_in_radius_result = NULL ;
static cpShape * closest_to_point_in_radius_result = NULL ;
static float closest_to_point_in_radius_result_largest_dist = 0.0f ;
static float closest_to_point_in_radius_result_largest_dist = 0.0f ;
static void closest_point_callback_func ( cpShape * shape , cpContactPointSet * points , void * data )
static void closest_point_callback_func ( cpShape * shape , cpContactPointSet * points , void * data )
{
{
assert ( points - > count = = 1 ) ;
assert ( points - > count = = 1 ) ;
if ( ! cp_shape_entity ( shape ) - > is_box )
if ( ! cp_shape_entity ( shape ) - > is_box )
@ -879,13 +889,13 @@ static void closest_point_callback_func(cpShape *shape, cpContactPointSet *point
}
}
}
}
Entity * closest_to_point_in_radius ( struct GameState * gs , V2 point , float radius )
Entity * closest_to_point_in_radius ( struct GameState * gs , V2 point , float radius )
{
{
closest_to_point_in_radius_result = NULL ;
closest_to_point_in_radius_result = NULL ;
closest_to_point_in_radius_result_largest_dist = 0.0f ;
closest_to_point_in_radius_result_largest_dist = 0.0f ;
cpBody * tmpbody = cpBodyNew ( 0.0f , 0.0f ) ;
cpBody * tmpbody = cpBodyNew ( 0.0f , 0.0f ) ;
cpShape * circle = cpCircleShapeNew ( tmpbody , radius , v2_to_cp ( point ) ) ;
cpShape * circle = cpCircleShapeNew ( tmpbody , radius , v2_to_cp ( point ) ) ;
cpSpaceShapeQuery ( gs - > space , circle , closest_point_callback_func , NULL ) ;
cpSpaceShapeQuery ( gs - > space , circle , closest_point_callback_func , NULL ) ;
cpShapeFree ( circle ) ;
cpShapeFree ( circle ) ;
@ -900,10 +910,10 @@ Entity *closest_to_point_in_radius(struct GameState *gs, V2 point, float radius)
return NULL ;
return NULL ;
}
}
V2 thruster_direction ( Entity * box )
V2 thruster_direction ( Entity * box )
{
{
assert ( box - > is_box & & box - > box_type = = BoxThruster ) ;
assert ( box - > is_box & & box - > box_type = = BoxThruster ) ;
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 = V2rotate ( to_return , rotangle ( box - > compass_rotation ) ) ;
to_return = V2rotate ( to_return , box_rotation ( box ) ) ;
to_return = V2rotate ( to_return , box_rotation ( box ) ) ;
@ -911,17 +921,17 @@ V2 thruster_direction(Entity *box)
return to_return ;
return to_return ;
}
}
V2 thruster_force ( Entity * box )
V2 thruster_force ( Entity * box )
{
{
return V2scale ( thruster_direction ( box ) , - box - > thrust * THRUSTER_FORCE ) ;
return V2scale ( thruster_direction ( box ) , - box - > thrust * THRUSTER_FORCE ) ;
}
}
uint64_t tick ( struct GameState * gs )
uint64_t tick ( struct GameState * gs )
{
{
return ( uint64_t ) floor ( gs - > time / ( ( double ) TIMESTEP ) ) ;
return ( uint64_t ) floor ( gs - > time / ( ( double ) TIMESTEP ) ) ;
}
}
void process ( struct GameState * gs , float dt )
void process ( struct GameState * gs , float dt )
{
{
assert ( gs - > space ! = NULL ) ;
assert ( gs - > space ! = NULL ) ;
@ -931,10 +941,10 @@ void process(struct GameState *gs, float dt)
// process input
// process input
for ( int i = 0 ; i < MAX_PLAYERS ; i + + )
for ( int i = 0 ; i < MAX_PLAYERS ; i + + )
{
{
struct Player * player = & gs - > players [ i ] ;
struct Player * player = & gs - > players [ i ] ;
if ( ! player - > connected )
if ( ! player - > connected )
continue ;
continue ;
Entity * p = get_entity ( gs , player - > entity ) ;
Entity * p = get_entity ( gs , player - > entity ) ;
if ( p = = NULL )
if ( p = = NULL )
{
{
p = new_entity ( gs ) ;
p = new_entity ( gs ) ;
@ -948,15 +958,15 @@ void process(struct GameState *gs, float dt)
{
{
p - > goldness + = 0.1 ;
p - > goldness + = 0.1 ;
p - > spice_taken_away = 0.0f ;
p - > spice_taken_away = 0.0f ;
gs - > goldpos = ( V2 ) { . x = hash11 ( gs - > time ) * 20.0f , . y = hash11 ( gs - > time - 13.6f ) * 20.0f } ;
gs - > goldpos = ( V2 ) { . x = hash11 ( gs - > time ) * 20.0f , . y = hash11 ( gs - > time - 13.6f ) * 20.0f } ;
}
}
if ( get_entity ( gs , p - > currently_piloting_seat ) = = NULL )
if ( get_entity ( gs , p - > currently_piloting_seat ) = = NULL )
{
{
p - > currently_piloting_seat = ( EntityID ) { 0 } ;
p - > currently_piloting_seat = ( EntityID ) { 0 } ;
}
}
// @Todo do getting inside pilot seat
// @Todo do getting inside pilot seat
#if 0
#if 0
if ( p - > input . inhabit )
if ( p - > input . inhabit )
{
{
@ -965,12 +975,12 @@ void process(struct GameState *gs, float dt)
{
{
// @Robust mask to only ship boxes of things the player can inhabit
// @Robust mask to only ship boxes of things the player can inhabit
cpPointQueryInfo query_info = { 0 } ;
cpPointQueryInfo query_info = { 0 } ;
cpShape * result = cpSpacePointQueryNearest ( gs - > space , v2_to_cp ( p - > pos ) , 0.1f , cpShapeFilterNew ( CP_NO_GROUP , CP_ALL_CATEGORIES , CP_ALL_CATEGORIES ) , & query_info ) ;
cpShape * result = cpSpacePointQueryNearest ( gs - > space , v2_to_cp ( p - > pos ) , 0.1f , cpShapeFilterNew ( CP_NO_GROUP , CP_ALL_CATEGORIES , CP_ALL_CATEGORIES ) , & query_info ) ;
if ( result ! = NULL )
if ( result ! = NULL )
{
{
// result is assumed to be a box shape
// result is assumed to be a box shape
struct Grid * g = ( struct Grid * ) cpBodyGetUserData ( cpShapeGetBody ( result ) ) ;
struct Grid * g = ( struct Grid * ) cpBodyGetUserData ( cpShapeGetBody ( result ) ) ;
int ship_to_inhabit = - 1 ;
int ship_to_inhabit = - 1 ;
for ( int ii = 0 ; ii < MAX_GRIDS ; ii + + )
for ( int ii = 0 ; ii < MAX_GRIDS ; ii + + )
{
{
@ -1024,10 +1034,10 @@ void process(struct GameState *gs, float dt)
}
}
cpBodyApplyForceAtWorldPoint ( p - > body , v2_to_cp ( V2scale ( player - > input . movement , PLAYER_JETPACK_FORCE ) ) , cpBodyGetPosition ( p - > body ) ) ;
cpBodyApplyForceAtWorldPoint ( p - > body , v2_to_cp ( V2scale ( player - > input . movement , PLAYER_JETPACK_FORCE ) ) , cpBodyGetPosition ( p - > body ) ) ;
p - > spice_taken_away + = movement_strength * dt * PLAYER_JETPACK_SPICE_PER_SECOND ;
p - > spice_taken_away + = movement_strength * dt * PLAYER_JETPACK_SPICE_PER_SECOND ;
// @Todo do pilot seat
// @Todo do pilot seat
#if 0
#if 0
{
{
struct Grid * g = & gs - > grids [ p - > currently_inhabiting_index ] ;
struct Grid * g = & gs - > grids [ p - > currently_inhabiting_index ] ;
V2 target_new_pos = V2lerp ( p - > pos , grid_com ( g ) , dt * 20.0f ) ;
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 ) ; // set vel correctly so newly built grids have the correct velocity copied from it
p - > vel = V2scale ( V2sub ( target_new_pos , p - > pos ) , 1.0f / dt ) ; // set vel correctly so newly built grids have the correct velocity copied from it
@ -1035,7 +1045,7 @@ void process(struct GameState *gs, float dt)
{
{
float energy_available = g - > total_energy_capacity ;
float energy_available = g - > total_energy_capacity ;
V2 target_direction = { 0 } ;
V2 target_direction = { 0 } ;
if ( V2length ( p - > input . movement ) > 0.0f )
if ( V2length ( p - > input . movement ) > 0.0f )
{
{
target_direction = V2normalize ( p - > input . movement ) ;
target_direction = V2normalize ( p - > input . movement ) ;
@ -1069,39 +1079,39 @@ void process(struct GameState *gs, float dt)
{
{
player - > 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...
player - > 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 } ;
cpPointQueryInfo info = { 0 } ;
V2 world_build = player - > input . build ;
V2 world_build = player - > input . build ;
// @Robust sanitize this input so player can't build on any grid in the world
// @Robust sanitize this input so player can't build on any grid in the world
Entity * target_grid = get_entity ( gs , player - > input . grid_to_build_on ) ;
Entity * target_grid = get_entity ( gs , player - > input . grid_to_build_on ) ;
if ( target_grid ! = NULL )
if ( target_grid ! = NULL )
{
{
world_build = grid_local_to_world ( target_grid , player - > input . build ) ;
world_build = grid_local_to_world ( target_grid , player - > input . build ) ;
}
}
cpShape * nearest = cpSpacePointQueryNearest ( gs - > space , v2_to_cp ( world_build ) , 0.01f , cpShapeFilterNew ( CP_NO_GROUP , CP_ALL_CATEGORIES , BOXES ) , & info ) ;
cpShape * nearest = cpSpacePointQueryNearest ( gs - > space , v2_to_cp ( world_build ) , 0.01f , cpShapeFilterNew ( CP_NO_GROUP , CP_ALL_CATEGORIES , BOXES ) , & info ) ;
if ( nearest ! = NULL )
if ( nearest ! = NULL )
{
{
Entity * cur_box = cp_shape_entity ( nearest ) ;
Entity * cur_box = cp_shape_entity ( nearest ) ;
Entity * cur_grid = cp_body_entity ( cpShapeGetBody ( nearest ) ) ;
Entity * cur_grid = cp_body_entity ( cpShapeGetBody ( nearest ) ) ;
grid_remove_box ( gs , cur_grid , cur_box ) ;
grid_remove_box ( gs , cur_grid , cur_box ) ;
p - > spice_taken_away - = 0.1f ;
p - > spice_taken_away - = 0.1f ;
}
}
else if ( target_grid = = NULL )
else if ( target_grid = = NULL )
{
{
Entity * new_grid = new_entity ( gs ) ;
Entity * new_grid = new_entity ( gs ) ;
grid_create ( gs , new_grid ) ;
grid_create ( gs , new_grid ) ;
p - > spice_taken_away + = 0.1f ;
p - > spice_taken_away + = 0.1f ;
entity_set_pos ( new_grid , world_build ) ;
entity_set_pos ( new_grid , world_build ) ;
Entity * new_box = new_entity ( gs ) ;
Entity * new_box = new_entity ( gs ) ;
box_create ( gs , new_box , new_grid , ( V2 ) { 0 } ) ;
box_create ( gs , new_box , new_grid , ( V2 ) { 0 } ) ;
new_box - > box_type = player - > input . build_type ;
new_box - > box_type = player - > input . build_type ;
new_box - > compass_rotation = player - > input . build_rotation ;
new_box - > compass_rotation = player - > input . build_rotation ;
cpBodySetVelocity ( new_grid - > body , cpBodyGetVelocity ( p - > body ) ) ;
cpBodySetVelocity ( new_grid - > body , cpBodyGetVelocity ( p - > body ) ) ;
}
}
else
else
{
{
Entity * new_box = new_entity ( gs ) ;
Entity * new_box = new_entity ( gs ) ;
box_create ( gs , new_box , target_grid , grid_world_to_local ( target_grid , world_build ) ) ;
box_create ( gs , new_box , target_grid , grid_world_to_local ( target_grid , world_build ) ) ;
new_box - > box_type = player - > input . build_type ;
new_box - > box_type = player - > input . build_type ;
new_box - > compass_rotation = player - > input . build_rotation ;
new_box - > compass_rotation = player - > input . build_rotation ;
@ -1112,19 +1122,19 @@ void process(struct GameState *gs, float dt)
if ( p - > spice_taken_away > = 1.0f )
if ( p - > spice_taken_away > = 1.0f )
{
{
entity_destroy ( gs , p ) ;
entity_destroy ( gs , p ) ;
player - > entity = ( EntityID ) { 0 } ;
player - > entity = ( EntityID ) { 0 } ;
}
}
p - > spice_taken_away = clamp01 ( p - > spice_taken_away ) ;
p - > spice_taken_away = clamp01 ( p - > spice_taken_away ) ;
}
}
// @Todo add thrust from thruster blocks
// @Todo add thrust from thruster blocks
#if 0
#if 0
for ( int i = 0 ; i < MAX_GRIDS ; i + + )
for ( int i = 0 ; i < MAX_GRIDS ; i + + )
{
{
SKIPNULL ( gs - > grids [ i ] . body ) ;
SKIPNULL ( gs - > grids [ i ] . body ) ;
struct Box * batteries [ MAX_BOXES_PER_GRID ] = { 0 } ;
struct Box * batteries [ MAX_BOXES_PER_GRID ] = { 0 } ;
int cur_battery = 0 ;
int cur_battery = 0 ;
for ( int ii = 0 ; ii < MAX_BOXES_PER_GRID ; ii + + )
for ( int ii = 0 ; ii < MAX_BOXES_PER_GRID ; ii + + )
{
{
@ -1145,7 +1155,7 @@ void process(struct GameState *gs, float dt)
if ( gs - > grids [ i ] . boxes [ ii ] . type = = BoxThruster )
if ( gs - > grids [ i ] . boxes [ ii ] . type = = BoxThruster )
{
{
float energy_to_consume = gs - > grids [ i ] . boxes [ ii ] . thrust * THRUSTER_ENERGY_USED_PER_SECOND * dt ;
float energy_to_consume = gs - > grids [ i ] . boxes [ ii ] . thrust * THRUSTER_ENERGY_USED_PER_SECOND * dt ;
struct Box * max_capacity_battery = NULL ;
struct Box * max_capacity_battery = NULL ;
float max_capacity_battery_energy_used = 1.0f ;
float max_capacity_battery_energy_used = 1.0f ;
for ( int iii = 0 ; iii < batteries_len ; iii + + )
for ( int iii = 0 ; iii < batteries_len ; iii + + )
{
{