Push to queue instead of callback, art changes

- Needs more thorough testing
main
Cameron Murphy Reikes 2 years ago
parent ab48cb8e84
commit a4997f771b

@ -15,12 +15,13 @@
// #define SERVER_ADDRESS "207.246.80.160" // #define SERVER_ADDRESS "207.246.80.160"
// #define PROFILING // #define PROFILING
#define DEBUG_RENDERING // #define DEBUG_RENDERING
// #define DEBUG_WORLD // #define DEBUG_WORLD
#define UNLOCK_ALL #define UNLOCK_ALL
#define TIME_BETWEEN_WORLD_SAVE 1.0f #define TIME_BETWEEN_WORLD_SAVE 1000000.0f
// #define INFINITE_RESOURCES #define INFINITE_RESOURCES
#define DEBUG_TOOLS #define DEBUG_TOOLS
#define CHIPMUNK_INTEGRITY_CHECK
// #define FAT_THRUSTERS // #define FAT_THRUSTERS
// #define NO_GRAVITY // #define NO_GRAVITY
// #define NO_SUNS // #define NO_SUNS

Binary file not shown.

@ -288,14 +288,70 @@ cpVect entity_vel(GameState *gs, Entity *e)
return (cpVect){0}; return (cpVect){0};
} }
static THREADLOCAL double to_face = 0.0; typedef struct QueryResult
static THREADLOCAL double nearest_dist = INFINITY; {
static THREADLOCAL bool target_found = false; cpShape *shape;
static void on_missile_shape(cpShape *shape, cpContactPointSet *points, void *data) cpVect pointA;
{ cpVect pointB;
Entity *launcher = (Entity *)data; } QueryResult;
Entity *other = cp_shape_entity(shape); static THREADLOCAL char query_result_data[128 * sizeof(QueryResult)] = {0};
GameState *gs = entitys_gamestate(launcher); // the data starts off NULL, on the first call sets it to result data
static THREADLOCAL Queue query_result = {.data_length = 128 * sizeof(QueryResult), .element_size = sizeof(cpShape *)};
static void shape_query_callback(cpShape *shape, cpContactPointSet *points, void *data)
{
flight_assert(points->count >= 1); // bad, not exactly sure what the points look like. Just taking the first one for now. @Robust good debug drawing for this and figure it out. Make debug rects fade away instead of only drawn for one frame, makes one off things visible
QueryResult *new = queue_push_element(&query_result);
if (new == NULL)
{
(void)queue_pop_element(&query_result);
new = queue_push_element(&query_result);
}
new->shape = shape;
new->pointA = points->points[0].pointA;
new->pointB = points->points[0].pointB;
}
// shapes are pushed to query result
static void shape_query(cpSpace *space, cpShape *shape)
{
query_result.data = query_result_data;
queue_clear(&query_result);
cpSpaceShapeQuery(space, shape, shape_query_callback, NULL);
}
// shapes are pushed to query result
static void circle_query(cpSpace *space, cpVect pos, double radius)
{
cpBody *tmp_body = cpBodyNew(0, 0);
cpBodySetPosition(tmp_body, pos);
cpShape *tmp_shape = cpCircleShapeNew(tmp_body, radius, cpv(0, 0));
shape_query(space, tmp_shape);
cpBodyFree(tmp_body);
cpShapeFree(tmp_shape);
}
static void rect_query(cpSpace *space, BoxCentered box)
{
cpBody *tmp_body = cpBodyNew(0, 0);
cpBodySetPosition(tmp_body, box.pos);
cpBodySetAngle(tmp_body, box.rotation);
cpShape *tmp_shape = cpBoxShapeNew(tmp_body, box.size.x * 2.0, box.size.y * 2.0, 0.0);
shape_query(space, tmp_shape);
cpBodyFree(tmp_body);
cpShapeFree(tmp_shape);
}
LauncherTarget missile_launcher_target(GameState *gs, Entity *launcher)
{
double to_face = 0.0;
double nearest_dist = INFINITY;
bool target_found = false;
circle_query(gs->space, entity_pos(launcher), MISSILE_RANGE);
QUEUE_ITER(&query_result, QueryResult, res)
{
cpShape *cur_shape = res->shape;
Entity *other = cp_shape_entity(cur_shape);
flight_assert(other->is_box || other->is_player || other->is_missile); flight_assert(other->is_box || other->is_player || other->is_missile);
cpVect to = cpvsub(entity_pos(other), entity_pos(launcher)); cpVect to = cpvsub(entity_pos(other), entity_pos(launcher));
@ -323,25 +379,10 @@ static void on_missile_shape(cpShape *shape, cpContactPointSet *points, void *da
to_face = cpvangle(adjusted_to); to_face = cpvangle(adjusted_to);
} }
} }
LauncherTarget missile_launcher_target(GameState *gs, Entity *launcher)
{
to_face = 0.0;
cpBody *tmp = cpBodyNew(0.0, 0.0);
cpBodySetPosition(tmp, (entity_pos(launcher)));
cpShape *circle = cpCircleShapeNew(tmp, MISSILE_RANGE, cpv(0, 0));
nearest_dist = INFINITY;
to_face = 0.0;
target_found = false;
cpSpaceShapeQuery(gs->space, circle, on_missile_shape, (void *)launcher);
cpBodyFree(tmp);
cpShapeFree(circle);
return (LauncherTarget){.target_found = target_found, .facing_angle = to_face}; return (LauncherTarget){.target_found = target_found, .facing_angle = to_face};
} }
void on_entity_child_shape(cpBody *body, cpShape *shape, void *data); void on_entity_child_shape(cpBody *body, cpShape *shape, void *data); // declared here bc entity_destroy circular dependency
// gs is for iterating over all child shapes and destroying those, too // gs is for iterating over all child shapes and destroying those, too
static void destroy_body(GameState *gs, cpBody **body) static void destroy_body(GameState *gs, cpBody **body)
@ -437,6 +478,7 @@ EntityID create_sun(GameState *gs, Entity *new_sun, cpVect pos, cpVect vel, doub
new_sun->sun_vel = vel; new_sun->sun_vel = vel;
new_sun->sun_mass = mass; new_sun->sun_mass = mass;
new_sun->sun_radius = radius; new_sun->sun_radius = radius;
new_sun->always_visible = true;
return get_id(gs, new_sun); return get_id(gs, new_sun);
} }
@ -1530,9 +1572,20 @@ SerMaybeFailure ser_server_to_client(SerState *ser, ServerToClient *s)
if (e->exists && !(ser->save_or_load_from_disk && e->no_save_to_disk) && !DONT_SEND_BECAUSE_CLOAKED(e)) if (e->exists && !(ser->save_or_load_from_disk && e->no_save_to_disk) && !DONT_SEND_BECAUSE_CLOAKED(e))
{ {
if (!e->is_box && !e->is_grid) if (!e->is_box && !e->is_grid)
{
Entity *cur_entity = e;
bool this_entity_in_range = ser->save_or_load_from_disk;
this_entity_in_range |= ser->for_player == NULL;
this_entity_in_range |= (ser->for_player != NULL && cpvdistsq(entity_pos(ser->for_player), entity_pos(cur_entity)) < VISION_RADIUS * VISION_RADIUS); // only in vision radius
// don't have to check if the entity is cloaked because this is checked above
if (cur_entity->always_visible)
this_entity_in_range = true;
if (this_entity_in_range)
{ {
SER_ENTITY(); SER_ENTITY();
} }
}
if (e->is_grid) if (e->is_grid)
{ {
bool serialized_grid_yet = false; bool serialized_grid_yet = false;
@ -1806,30 +1859,25 @@ static bool merge_filter(Entity *potential_merge)
return potential_merge->is_box && potential_merge->box_type == BoxMerge && box_grid(potential_merge) != grid_to_exclude; return potential_merge->is_box && potential_merge->box_type == BoxMerge && box_grid(potential_merge) != grid_to_exclude;
} }
static void cloaking_shield_callback_func(cpShape *shape, cpContactPointSet *points, void *data) // filter func null means everything is ok, if it's not null and returns false, that means
// exclude it from the selection. This returns the closest box entity!
Entity *closest_box_to_point_in_radius(struct GameState *gs, cpVect point, double radius, bool (*filter_func)(Entity *))
{ {
Entity *from_cloaking_box = (Entity *)data; cpShape *closest_to_point_in_radius_result = NULL;
GameState *gs = entitys_gamestate(from_cloaking_box); double closest_to_point_in_radius_result_largest_dist = 0.0;
Entity *to_cloak = cp_shape_entity(shape);
to_cloak->time_was_last_cloaked = elapsed_time(gs); circle_query(gs->space, point, radius);
to_cloak->last_cloaked_by_squad = from_cloaking_box->owning_squad; QUEUE_ITER(&query_result, QueryResult, res)
}
// has to be global var because can only get this information
static THREADLOCAL cpShape *closest_to_point_in_radius_result = NULL;
static THREADLOCAL double closest_to_point_in_radius_result_largest_dist = 0.0;
static THREADLOCAL bool (*closest_to_point_in_radius_filter_func)(Entity *);
static void closest_point_callback_func(cpShape *shape, cpContactPointSet *points, void *data)
{ {
flight_assert(points->count == 1); cpShape *shape = res->shape;
Entity *e = cp_shape_entity(shape); Entity *e = cp_shape_entity(shape);
if (!e->is_box) if (!e->is_box)
return; continue;
if (closest_to_point_in_radius_filter_func != NULL && !closest_to_point_in_radius_filter_func(e)) if (filter_func != NULL && !filter_func(e))
return; continue;
double dist = cpvlength((cpvsub(points->points[0].pointA, points->points[0].pointB))); double dist = cpvlength((cpvsub(res->pointA, res->pointB)));
// double dist = -points->points[0].distance; // double dist = -points->points[0].distance;
if (dist > closest_to_point_in_radius_result_largest_dist) if (dist > closest_to_point_in_radius_result_largest_dist)
{ {
@ -1838,20 +1886,6 @@ static void closest_point_callback_func(cpShape *shape, cpContactPointSet *point
} }
} }
// filter func null means everything is ok, if it's not null and returns false, that means
// exclude it from the selection. This returns the closest box entity!
Entity *closest_box_to_point_in_radius(struct GameState *gs, cpVect point, double radius, bool (*filter_func)(Entity *))
{
closest_to_point_in_radius_result = NULL;
closest_to_point_in_radius_result_largest_dist = 0.0;
closest_to_point_in_radius_filter_func = filter_func;
cpBody *tmpbody = cpBodyNew(0.0, 0.0);
cpShape *circle = cpCircleShapeNew(tmpbody, radius, (point));
cpSpaceShapeQuery(gs->space, circle, closest_point_callback_func, NULL);
cpShapeFree(circle);
cpBodyFree(tmpbody);
if (closest_to_point_in_radius_result != NULL) if (closest_to_point_in_radius_result != NULL)
{ {
return cp_shape_entity(closest_to_point_in_radius_result); return cp_shape_entity(closest_to_point_in_radius_result);
@ -1870,12 +1904,16 @@ static bool scanner_filter(Entity *e)
return true; return true;
} }
static double cur_explosion_damage = 0.0; static void do_explosion(GameState *gs, Entity *explosion, double dt)
static cpVect explosion_origin = {0};
static double explosion_push_strength = 0.0;
static void explosion_callback_func(cpShape *shape, cpContactPointSet *points, void *data)
{ {
GameState *gs = (GameState *)data;
double cur_explosion_damage = dt * EXPLOSION_DAMAGE_PER_SEC;
cpVect explosion_origin = explosion->explosion_pos;
double explosion_push_strength = explosion->explosion_push_strength;
circle_query(gs->space, explosion_origin, explosion->explosion_radius);
QUEUE_ITER(&query_result, QueryResult, res)
{
cpShape *shape = res->shape;
cp_shape_entity(shape)->damage += cur_explosion_damage; cp_shape_entity(shape)->damage += cur_explosion_damage;
Entity *parent = get_entity(gs, cp_shape_entity(shape)->shape_parent_entity); Entity *parent = get_entity(gs, cp_shape_entity(shape)->shape_parent_entity);
cpVect from_pos = entity_pos(cp_shape_entity(shape)); cpVect from_pos = entity_pos(cp_shape_entity(shape));
@ -1883,20 +1921,6 @@ static void explosion_callback_func(cpShape *shape, cpContactPointSet *points, v
flight_assert(parent->body != NULL); flight_assert(parent->body != NULL);
cpBodyApplyImpulseAtWorldPoint(parent->body, (impulse), (from_pos)); cpBodyApplyImpulseAtWorldPoint(parent->body, (impulse), (from_pos));
} }
static void do_explosion(GameState *gs, Entity *explosion, double dt)
{
cpBody *tmpbody = cpBodyNew(0.0, 0.0);
cpShape *circle = cpCircleShapeNew(tmpbody, explosion->explosion_radius, (explosion_origin));
cur_explosion_damage = dt * EXPLOSION_DAMAGE_PER_SEC;
explosion_origin = explosion->explosion_pos;
explosion_push_strength = explosion->explosion_push_strength;
cpSpaceShapeQuery(gs->space, circle, explosion_callback_func, (void *)gs);
cpShapeFree(circle);
cpBodyFree(tmpbody);
} }
cpVect box_facing_vector(Entity *box) cpVect box_facing_vector(Entity *box)
@ -2195,11 +2219,12 @@ void create_hard_shell_station(GameState *gs, cpVect pos, enum BoxType platonic_
} }
void create_initial_world(GameState *gs) void create_initial_world(GameState *gs)
{ {
const double mass_multiplier = 10.0;
EntityID suns[] = { EntityID suns[] = {
create_sun(gs, new_entity(gs), ((cpVect){800.0, 0.0}), ((cpVect){0.0, 0.0}), 1000000.0, 30.0), create_sun(gs, new_entity(gs), ((cpVect){800.0, 0.0}), ((cpVect){0.0, 0.0}), 1000000.0 * mass_multiplier, 30.0),
create_sun(gs, new_entity(gs), ((cpVect){800.0, 50.0}), ((cpVect){50.0, 0.0}), 10000.0, 20.0), create_sun(gs, new_entity(gs), ((cpVect){800.0, 100.0}), ((cpVect){60.0, 0.0}), 10000.0 * mass_multiplier, 20.0),
create_sun(gs, new_entity(gs), ((cpVect){800.0, -50.0}), ((cpVect){-50.0, 0.0}), 10000.0, 20.0), create_sun(gs, new_entity(gs), ((cpVect){800.0, -100.0}), ((cpVect){-60.0, 0.0}), 10000.0 * mass_multiplier, 20.0),
create_sun(gs, new_entity(gs), ((cpVect){-2500.0, -50.0}), ((cpVect){0.0, 0.0}), 100000.0, 20.0), create_sun(gs, new_entity(gs), ((cpVect){-7000.0, -50.0}), ((cpVect){0.0, 0.0}), 100000.0 * mass_multiplier, 20.0),
}; };
for (int i = 0; i < ARRLEN(suns); i++) for (int i = 0; i < ARRLEN(suns); i++)
@ -2212,7 +2237,7 @@ void create_initial_world(GameState *gs)
// create_hard_shell_station(gs, (cpVect){800.0, 400.0}, BoxGyroscope); // create_hard_shell_station(gs, (cpVect){800.0, 400.0}, BoxGyroscope);
create_bomb_station(gs, (cpVect){800.0, -800.0}, BoxCloaking); create_bomb_station(gs, (cpVect){800.0, -800.0}, BoxCloaking);
create_bomb_station(gs, (cpVect){1600.0, 800.0}, BoxMissileLauncher); create_bomb_station(gs, (cpVect){1600.0, 800.0}, BoxMissileLauncher);
create_hard_shell_station(gs, (cpVect){-2500.0, 200.0}, BoxMerge); create_hard_shell_station(gs, (cpVect){-7000.0, 200.0}, BoxMerge);
#else #else
Log("Creating debug world\n"); Log("Creating debug world\n");
// pos, mass, radius // pos, mass, radius
@ -2264,12 +2289,34 @@ void exit_seat(GameState *gs, Entity *seat_in, Entity *p)
cpBodySetVelocity(p->body, cpBodyGetVelocity(box_grid(seat_in)->body)); cpBodySetVelocity(p->body, cpBodyGetVelocity(box_grid(seat_in)->body));
} }
void shape_integrity_check(cpShape *shape, void *data)
{
flight_assert(cpShapeGetUserData(shape) != NULL);
flight_assert(cp_shape_entity(shape)->exists);
flight_assert(cp_shape_entity(shape)->shape == shape);
}
void body_integrity_check(cpBody *body, void *data)
{
flight_assert(cpBodyGetUserData(body) != NULL);
flight_assert(cp_body_entity(body)->exists);
flight_assert(cp_body_entity(body)->body == body);
}
void process(struct GameState *gs, double dt) void process(struct GameState *gs, double dt)
{ {
PROFILE_SCOPE("Gameplay processing") PROFILE_SCOPE("Gameplay processing")
{ {
flight_assert(gs->space != NULL); flight_assert(gs->space != NULL);
#ifdef CHIPMUNK_INTEGRITY_CHECK
PROFILE_SCOPE("Chipmunk Integrity Checks")
{
cpSpaceEachShape(gs->space, shape_integrity_check, NULL);
cpSpaceEachBody(gs->space, body_integrity_check, NULL);
}
#endif
gs->tick++; gs->tick++;
PROFILE_SCOPE("sun gravity") PROFILE_SCOPE("sun gravity")
@ -2881,15 +2928,23 @@ void process(struct GameState *gs, double dt)
else else
{ {
cur_box->cloaking_power = lerp(cur_box->cloaking_power, 1.0, dt * 3.0); cur_box->cloaking_power = lerp(cur_box->cloaking_power, 1.0, dt * 3.0);
cpBody *tmp = cpBodyNew(0.0, 0.0); rect_query(gs->space, (BoxCentered){
cpBodySetPosition(tmp, (entity_pos(cur_box))); .pos = entity_pos(cur_box),
cpBodySetAngle(tmp, entity_rotation(cur_box)); .rotation = entity_rotation(cur_box),
// subtract a little from the panel size so that boxes just at the boundary of the panel // subtract a little from the panel size so that boxes just at the boundary of the panel
// aren't (sometimes cloaked)/(sometimes not) from floating point imprecision // aren't (sometimes cloaked)/(sometimes not) from floating point imprecision
cpShape *box_shape = cpBoxShapeNew(tmp, CLOAKING_PANEL_SIZE - 0.03, CLOAKING_PANEL_SIZE - 0.03, 0.0); .size = cpv(CLOAKING_PANEL_SIZE - 0.03, CLOAKING_PANEL_SIZE - 0.03),
cpSpaceShapeQuery(gs->space, box_shape, cloaking_shield_callback_func, (void *)cur_box); });
cpShapeFree(box_shape); QUEUE_ITER(&query_result, QueryResult, res)
cpBodyFree(tmp); {
cpShape *shape = res->shape;
Entity *from_cloaking_box = cur_box;
GameState *gs = entitys_gamestate(from_cloaking_box);
Entity *to_cloak = cp_shape_entity(shape);
to_cloak->time_was_last_cloaked = elapsed_time(gs);
to_cloak->last_cloaked_by_squad = from_cloaking_box->owning_squad;
}
} }
} }
if (cur_box->box_type == BoxMissileLauncher) if (cur_box->box_type == BoxMissileLauncher)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 427 B

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 4.5 MiB

@ -1990,7 +1990,7 @@ static void frame(void)
} }
} }
double player_scaling_target = zoom < 6.5 ? 100.0 : 1.0; double player_scaling_target = zoom < 6.5 ? PLAYER_BIG_SCALING/zoom : 1.0;
if (zoom > 50.0) if (zoom > 50.0)
player_scaling = player_scaling_target; // For press tab zoom shortcut. Bad hack to make zooming in not jarring with the bigger player. Comment this out and press tab to see! player_scaling = player_scaling_target; // For press tab zoom shortcut. Bad hack to make zooming in not jarring with the bigger player. Comment this out and press tab to see!
player_scaling = lerp(player_scaling, player_scaling_target, dt * 15.0); player_scaling = lerp(player_scaling, player_scaling_target, dt * 15.0);
@ -2265,9 +2265,15 @@ static void frame(void)
translate(entity_pos(i.sun).x, entity_pos(i.sun).y); translate(entity_pos(i.sun).x, entity_pos(i.sun).y);
set_color(WHITE); set_color(WHITE);
sgp_set_image(0, image_sun); sgp_set_image(0, image_sun);
draw_texture_centered((cpVect){0}, i.sun->sun_radius * 2.0); draw_texture_centered((cpVect){0}, i.sun->sun_radius * 8.0);
sgp_reset_image(0); sgp_reset_image(0);
#ifdef DEBUG_RENDERING
// so you can make sure the sprite is the right size to accurately show when it will burn you
set_color(RED);
draw_circle(cpv(0, 0), i.sun->sun_radius);
#endif
// can draw at 0,0 because everything relative to sun now! // can draw at 0,0 because everything relative to sun now!
// sun DEATH RADIUS // sun DEATH RADIUS

@ -3,7 +3,7 @@
#include "buildsettings.h" #include "buildsettings.h"
#define MAX_BOX_TYPES 64 #define MAX_BOX_TYPES 64
#define ZOOM_MIN 0.10 // smaller means you can zoom out more #define ZOOM_MIN 0.04 // smaller means you can zoom out more
#define ZOOM_MAX 1500.0 // bigger means you can zoom in more #define ZOOM_MAX 1500.0 // bigger means you can zoom in more
#define MAX_PLAYERS 16 #define MAX_PLAYERS 16
#define MAX_SUNS 8 #define MAX_SUNS 8
@ -32,6 +32,7 @@
#define MISSILE_SPAWN_DIST (sqrt((BOX_SIZE / 2.0) * (BOX_SIZE / 2.0) * 2.0) + MISSILE_COLLIDER_SIZE.x / 2.0 + 0.1) #define MISSILE_SPAWN_DIST (sqrt((BOX_SIZE / 2.0) * (BOX_SIZE / 2.0) * 2.0) + MISSILE_COLLIDER_SIZE.x / 2.0 + 0.1)
#define PLAYER_JETPACK_ROTATION_ENERGY_PER_SECOND 0.2f #define PLAYER_JETPACK_ROTATION_ENERGY_PER_SECOND 0.2f
#define PLAYER_JETPACK_SPICE_PER_SECOND 0.08f #define PLAYER_JETPACK_SPICE_PER_SECOND 0.08f
#define PLAYER_BIG_SCALING 300.0
#define SCANNER_ENERGY_USE 0.05f #define SCANNER_ENERGY_USE 0.05f
#define MAX_HAND_REACH 1.0f #define MAX_HAND_REACH 1.0f
#define SCANNER_SCAN_RATE 0.5f #define SCANNER_SCAN_RATE 0.5f
@ -50,9 +51,9 @@
#define VISION_RADIUS 12.0f #define VISION_RADIUS 12.0f
#define MAX_SERVER_TO_CLIENT 1024 * 512 // maximum size of serialized gamestate buffer #define MAX_SERVER_TO_CLIENT 1024 * 512 // maximum size of serialized gamestate buffer
#define MAX_CLIENT_TO_SERVER 1024 * 10 // maximum size of serialized inputs and mic data #define MAX_CLIENT_TO_SERVER 1024 * 10 // maximum size of serialized inputs and mic data
#define GRAVITY_CONSTANT 0.1f #define GRAVITY_CONSTANT 0.05f
#define GRAVITY_SMALLEST 0.01f // used to determine when gravity is clamped to 0.0f #define GRAVITY_SMALLEST 0.01f // used to determine when gravity is clamped to 0.0f
#define INSTANT_DEATH_DISTANCE_FROM_CENTER 4000.0f #define INSTANT_DEATH_DISTANCE_FROM_CENTER 10000.0f
#define SOLAR_ENERGY_PER_SECOND 0.09f #define SOLAR_ENERGY_PER_SECOND 0.09f
#define DAMAGE_TO_PLAYER_PER_BLOCK 0.1f #define DAMAGE_TO_PLAYER_PER_BLOCK 0.1f
#define BATTERY_CAPACITY 1.5f #define BATTERY_CAPACITY 1.5f
@ -558,7 +559,7 @@ typedef struct BoxCentered
{ {
cpVect pos; cpVect pos;
double rotation; double rotation;
cpVect size; cpVect size; // half width and half height, centered on position
} BoxCentered; } BoxCentered;
static inline bool box_has_point(BoxCentered box, cpVect point) static inline bool box_has_point(BoxCentered box, cpVect point)

Loading…
Cancel
Save