From 2feb571c1d2af86d0d7a1bc8d8b48db6414e06f2 Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Fri, 16 Dec 2022 17:36:33 -0800 Subject: [PATCH] Add radar --- buildsettings.h | 4 +- flight.rdbg | Bin 1841 -> 1955 bytes gamestate.c | 91 ++++++++++++++++++++++++++++++++++++-------- loaded/radardot.png | Bin 0 -> 240 bytes main.c | 58 ++++++++++++++++++++++------ types.h | 65 ++++++++++++++++++++----------- 6 files changed, 167 insertions(+), 51 deletions(-) create mode 100644 loaded/radardot.png diff --git a/buildsettings.h b/buildsettings.h index 836fcaf..4900a52 100644 --- a/buildsettings.h +++ b/buildsettings.h @@ -26,8 +26,8 @@ #define DEBUG_TOOLS #define CHIPMUNK_INTEGRITY_CHECK // #define FAT_THRUSTERS -// #define NO_GRAVITY -// #define NO_SUNS +#define NO_GRAVITY +#define NO_SUNS #else diff --git a/flight.rdbg b/flight.rdbg index 4b30e4fc5b466f7b90135dd27dac70df78d19237..3d1162f1ea5c1b0da2be65443d68103760e13b0a 100644 GIT binary patch delta 339 zcmXv|OG?8~6wOWYUZRCWsUXf$K`KImj*3_;iVBJfr8saD@_9CaHs2StyJ)#fZ~-E2 zz;!rs1tKUo)YlXT_nvz`9PYF6Xijsmu?1T=B@MX6J^5hv*2EvxfD1v6@KqtCU$J6> zhI$F7b4?#aUdEiDCL*B039hQgGz}+C&=qC7*j7x~scS!E9nSxo)B$H1I`S24&rLe^ z;=~Eif)4%y5xWH)HFKi+qejU5Y8V#YeI4n}zHI0(9_;CP#VY1R6nmtN*F?uVvVWsV zk_2LMMXaP6uL}sO!u8V!`>+hWBw>Y{rE$VbQ&@f)#;kNh##z8wNQ6|IsyGTZvSfig keR(1q02+d}i7Q$Y-wDM}x`f}vT5!6yOhxi+6b~c*2L~BltN;K2 delta 243 zcmZ3?zmac3A*1Hxhm5L|^;y{&1A#2-$sbtkC$D8;XS4wF3?>V(u(PC9=w(bSRGaL; z!p&$773G46zFAWfQ(_!P0Y;GOLhmc9Vh28b254YS#B)BC8-6I*E1PRE@X0G zbOA}SIOV5QPQJ(JJ^2BnGkZp2L8@M|8(3FABL|}wNEd5hX=+jB#0Bva3k@0BCfl>B zPxfQwn4HFHDZs?Qz`zK^h0H)AuQYe_7gk9|MyAPv?CM+~aYhax0pe=%fw*iy?3R<6 Ho>2k-RE9#o diff --git a/gamestate.c b/gamestate.c index 4b4676b..b42ab0b 100644 --- a/gamestate.c +++ b/gamestate.c @@ -348,6 +348,14 @@ static void raycast_query_callback(cpShape *shape, cpVect point, cpVect normal, } } +static THREADLOCAL cpVect from_point = {0}; +static int sort_bodies_callback(const void *a, const void *b) +{ + double a_dist = cpvdist(cpBodyGetPosition((cpBody *)a), from_point); + double b_dist = cpvdist(cpBodyGetPosition((cpBody *)b), from_point); + return (int)(a_dist - b_dist); +} + LauncherTarget missile_launcher_target(GameState *gs, Entity *launcher) { double to_face = 0.0; @@ -1517,8 +1525,10 @@ SerMaybeFailure ser_entity(SerState *ser, GameState *gs, Entity *e) SER_MAYBE_RETURN(ser_f(ser, &e->currently_scanning_progress)); SER_VAR(&e->blueprints_learned); SER_MAYBE_RETURN(ser_f(ser, &e->scanner_head_rotate)); - SER_MAYBE_RETURN(ser_fV2(ser, &e->platonic_nearest_direction)); - SER_MAYBE_RETURN(ser_f(ser, &e->platonic_detection_strength)); + for (int i = 0; i < SCANNER_MAX_POINTS; i++) + { + SER_VAR(&e->scanner_points[i]); + } break; case BoxCloaking: SER_MAYBE_RETURN(ser_f(ser, &e->cloaking_power)); @@ -3123,13 +3133,11 @@ void process(struct GameState *gs, double dt) // only the server knows all the positions of all the solids if (gs->server_side_computing) { - if (cur_box->energy_effectiveness < 1.0) - { - cur_box->platonic_detection_strength = 0.0; - cur_box->platonic_nearest_direction = (cpVect){0}; - } - else + for (int i = 0; i < SCANNER_MAX_POINTS; i++) + cur_box->scanner_points[i] = (struct ScannerPoint){0}; + if (cur_box->energy_effectiveness >= 1.0) { + /* cpVect from_pos = entity_pos(cur_box); cpVect nearest = {0}; double nearest_dist = INFINITY; @@ -3146,15 +3154,67 @@ void process(struct GameState *gs, double dt) } } } - if (nearest_dist < INFINITY) + */ + + circle_query(gs->space, entity_pos(cur_box), SCANNER_MAX_RANGE); + cpBody *body_results[128] = {0}; + size_t cur_results_len = 0; + + QUEUE_ITER(&query_result, QueryResult, res) { - cur_box->platonic_nearest_direction = cpvnormalize(cpvsub(nearest, from_pos)); - cur_box->platonic_detection_strength = fmax(0.1, 1.0 - fmin(1.0, nearest_dist / 100.0)); + cpBody *cur_body = cpShapeGetBody(res->shape); + bool unique_body = true; + for (int i = 0; i < cur_results_len; i++) + { + if (body_results[i] == cur_body) + { + unique_body = false; + break; + } + } + if (unique_body && cur_results_len < ARRLEN(body_results)) + { + body_results[cur_results_len] = cur_body; + cur_results_len++; + } } - else + from_point = entity_pos(cur_box); + qsort(body_results, cur_results_len, sizeof(cpBody *), sort_bodies_callback); + size_t bodies_detected = cur_results_len < SCANNER_MAX_POINTS ? cur_results_len : SCANNER_MAX_POINTS; + for (int i = 0; i < bodies_detected; i++) { - cur_box->platonic_nearest_direction = (cpVect){0}; - cur_box->platonic_detection_strength = 0.0; + cpVect rel_vect = cpvsub(cpBodyGetPosition(body_results[i]), from_point); + double vect_length = cpvlength(rel_vect); + if (vect_length > SCANNER_MIN_RANGE) + { + if (vect_length > SCANNER_MAX_RANGE) + { + rel_vect = cpvmult(cpvnormalize(rel_vect), SCANNER_MAX_RANGE); + } + + enum ScannerPointKind kind = Platonic; + Entity *body_entity =cp_body_entity(body_results[i]) ; + if(body_entity->is_grid) { + kind = Neutral; + BOXES_ITER(gs, cur_potential_platonic, body_entity) + { + if(cur_potential_platonic->is_platonic) + { + kind = Platonic; + break; + } + } + } else if(body_entity->is_player) { + kind = Neutral; + } else { + kind = Enemy; + } + cur_box->scanner_points[i] = (struct ScannerPoint){ + .kind = (char)kind, + .x = (char)((rel_vect.x / SCANNER_MAX_RANGE) * 128.0), + .y = (char)((rel_vect.y / SCANNER_MAX_RANGE) * 128.0), + }; + } } } } @@ -3173,7 +3233,8 @@ void process(struct GameState *gs, double dt) cur_box->currently_scanning = new_id; } - double target_head_rotate_speed = cur_box->platonic_detection_strength > 0.0 ? 3.0 : 0.0; + // double target_head_rotate_speed = cur_box->platonic_detection_strength > 0.0 ? 3.0 : 0.0; + double target_head_rotate_speed = 3.0 * cur_box->energy_effectiveness; if (to_learn != NULL) { cur_box->currently_scanning_progress += dt * SCANNER_SCAN_RATE; diff --git a/loaded/radardot.png b/loaded/radardot.png new file mode 100644 index 0000000000000000000000000000000000000000..b7929f1cc54a2d1c811279709b769011519118c7 GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D$|R(ZNOhIn+o zopPJ=umO*2zxVNiZyoF}&zzI{DEF$LN3D0sh3oFKnZ=!UTq{&CoAbx!rH7}B(S%0N z__Yq+np>x{9DcA#ogqtQ7u#WO1M4Op9i<@MPR$EPjSHmN%GG@Damepr*{yGVc>5wI zk=SCN1=g=S3wBRSkP>=WrhD-A2A02P m6S2EpKSor3{~N!54c5mWdaV(-lB@@GHG`+CpUXO@geCx|eO>qf literal 0 HcmV?d00001 diff --git a/main.c b/main.c index e3460c0..7aeb30b 100644 --- a/main.c +++ b/main.c @@ -127,6 +127,7 @@ static sg_image image_gyrospin; static sg_image image_noenergy; static sg_image image_orb; static sg_image image_orb_frozen; +static sg_image image_radardot; static enum BoxType toolbar[TOOLBAR_SLOTS] = { BoxHullpiece, @@ -657,6 +658,7 @@ static void init(void) image_noenergy = load_image("loaded/no_energy.png"); image_orb = load_image("loaded/orb.png"); image_orb_frozen = load_image("loaded/orb_frozen.png"); + image_radardot = load_image("loaded/radardot.png"); } // socket initialization @@ -2171,13 +2173,6 @@ static void frame(void) sgp_reset_image(0); } - // scanner range, visualizes what scanner can scan - if (b->box_type == BoxScanner) - { - set_color(BLUE); - draw_circle(entity_pos(b), SCANNER_RADIUS); - set_color(WHITE); - } set_color_values(0.5, 0.1, 0.1, b->damage); draw_color_rect_centered(entity_pos(b), BOX_SIZE); @@ -2215,13 +2210,52 @@ static void frame(void) if (b->box_type == BoxScanner) { - if (b->platonic_detection_strength > 0.0) + if (b->energy_effectiveness >= 1.0) { + // maximum scanner range + set_color(BLUE); + draw_circle(entity_pos(b), SCANNER_RADIUS); + set_color_values(0.0, 0.0, 1.0, 0.3); + draw_circle(entity_pos(b), SCANNER_RADIUS * 0.25); + draw_circle(entity_pos(b), SCANNER_RADIUS * 0.5); + draw_circle(entity_pos(b), SCANNER_RADIUS * 0.75); + set_color(WHITE); + set_color(colhexcode(0xf2d75c)); - cpVect to = cpvadd(entity_pos(b), cpvmult(b->platonic_nearest_direction, b->platonic_detection_strength)); - dbg_rect(to); - dbg_rect(entity_pos(b)); - draw_line(entity_pos(b).x, entity_pos(b).y, to.x, to.y); + sgp_set_image(0, image_radardot); + for (int i = 0; i < SCANNER_MAX_POINTS; i++) + { + if(b->scanner_points[i].x != 0 && b->scanner_points[i].y != 0) + { + struct ScannerPoint point = b->scanner_points[i]; + switch(point.kind) + { + case Platonic: + set_color(GOLD); + break; + case Neutral: + set_color(WHITE); + break; + case Enemy: + set_color(RED); + break; + default: + set_color(WHITE); // @Robust assert false in serialization if unexpected kind + break; + } + cpVect rel = cpv( + ((double)point.x / 128.0) * SCANNER_RADIUS, + ((double)point.y / 128.0) * SCANNER_RADIUS + ); + cpVect to = cpvadd(entity_pos(b), rel); + dbg_rect(to); + dbg_rect(entity_pos(b)); + pipeline_scope(goodpixel_pipeline) + draw_texture_centered(to, BOX_SIZE / 2.0); + } + } + sgp_reset_image(0); + // draw_line(entity_pos(b).x, entity_pos(b).y, to.x, to.y); } } if (b->box_type == BoxMissileLauncher) diff --git a/types.h b/types.h index ef84666..0d1c71b 100644 --- a/types.h +++ b/types.h @@ -10,14 +10,7 @@ #define MAX_ENTITIES 1024 * 25 #define BOX_SIZE 0.25f #define MERGE_MAX_DIST (BOX_SIZE / 2.0f + 0.01f) -#define PLAYER_SIZE ((cpVect){.x = BOX_SIZE, .y = BOX_SIZE}) -#define PLAYER_MASS 0.5f -#ifdef FAT_THRUSTERS -#define PLAYER_JETPACK_FORCE 200.0f -#else -#define PLAYER_JETPACK_FORCE 3.5f -#endif -#define PLAYER_JETPACK_TORQUE 0.05f + #define MISSILE_RANGE 4.0f #define MISSILE_BURN_TIME 1.5f #define MISSILE_ARM_TIME 0.5f @@ -30,6 +23,17 @@ #define MISSILE_SPRITE_SIZE ((cpVect){.x = BOX_SIZE, .y = BOX_SIZE}) #define MISSILE_COLLIDER_SIZE ((cpVect){.x = BOX_SIZE * 0.5f, .y = BOX_SIZE * 0.5f}) #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_EXPLOSION_PUSH 2.5f +#define MISSILE_EXPLOSION_RADIUS 0.4f + +#define PLAYER_SIZE ((cpVect){.x = BOX_SIZE, .y = BOX_SIZE}) +#define PLAYER_MASS 0.5f +#ifdef FAT_THRUSTERS +#define PLAYER_JETPACK_FORCE 200.0f +#else +#define PLAYER_JETPACK_FORCE 3.5f +#endif +#define PLAYER_JETPACK_TORQUE 0.05f #define PLAYER_JETPACK_ROTATION_ENERGY_PER_SECOND 0.2f #define PLAYER_JETPACK_SPICE_PER_SECOND 0.08f #define PLAYER_BIG_SCALING 300.0 @@ -43,22 +47,30 @@ #define ORB_HEAL_RATE 0.2 #define ORB_MAX_FORCE 200.0 -#define SCANNER_ENERGY_USE 0.05f +#define VISION_RADIUS 12.0f #define MAX_HAND_REACH 1.0f -#define SCANNER_SCAN_RATE 0.5f -#define SCANNER_RADIUS 1.0f #define GOLD_COLLECT_RADIUS 0.3f #define BUILD_BOX_SNAP_DIST_TO_SHIP 0.2f #define BOX_MASS 1.0f #define COLLISION_DAMAGE_SCALING 0.15f + #define THRUSTER_FORCE 24.0f #define THRUSTER_ENERGY_USED_PER_SECOND 0.005f + #define GYROSCOPE_ENERGY_USED_PER_SECOND 0.005f #define GYROSCOPE_TORQUE 1.5f #define GYROSCOPE_PROPORTIONAL_INERTIAL_RESPONSE 0.7 // between 0-1. How strongly responds to rotation, to stop the rotation + #define CLOAKING_ENERGY_USE 0.1f #define CLOAKING_PANEL_SIZE BOX_SIZE * 3.0f -#define VISION_RADIUS 12.0f + +#define SCANNER_ENERGY_USE 0.05f +#define SCANNER_SCAN_RATE 0.5f +#define SCANNER_RADIUS 1.0f +#define SCANNER_MAX_RANGE 1500.0 +#define SCANNER_MIN_RANGE 1.0 +#define SCANNER_MAX_POINTS 10 + #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 GRAVITY_CONSTANT 0.05f @@ -77,8 +89,6 @@ #define TIME_BETWEEN_WORLD_SAVE 30.0f #endif -#define MISSILE_EXPLOSION_PUSH 2.5f -#define MISSILE_EXPLOSION_RADIUS 0.4f #define BOMB_EXPLOSION_PUSH 5.0f #define BOMB_EXPLOSION_RADIUS 1.0f @@ -95,7 +105,7 @@ // multiplayer #define CAUTIOUS_MULTIPLIER 0.8 // how overboard to go with the time ahead predicting, makes it less likely that inputs are lost -#define TICKS_BEHIND_DO_SNAP 6 // when this many ticks behind, instead of dilating time SNAP to the healthy ticks ahead +#define TICKS_BEHIND_DO_SNAP 6 // when this many ticks behind, instead of dilating time SNAP to the healthy ticks ahead #define MAX_MS_SPENT_REPREDICTING 30.0f #define TIME_BETWEEN_SEND_GAMESTATE (1.0f / 20.0f) #define TIME_BETWEEN_INPUT_PACKETS (1.0f / 20.0f) @@ -224,6 +234,13 @@ static inline bool entityids_same(EntityID a, EntityID b) return (a.generation == b.generation) && (a.index == b.index); } +enum ScannerPointKind +{ + Platonic, + Neutral, + Enemy, +}; + // when updated, must update serialization, comparison in main.c, and the server // on input received processing function typedef struct InputFrame @@ -267,8 +284,8 @@ typedef struct Entity // what the shape's parent entity is bool is_circle_shape; EntityID shape_parent_entity; // can't be zero if shape is nonzero - double shape_radius; // only when circle shape - cpVect shape_size; // only when rect shape + double shape_radius; // only when circle shape + cpVect shape_size; // only when rect shape // player bool is_player; @@ -328,12 +345,11 @@ typedef struct Entity // used by medbay and cockpit EntityID player_who_is_inside_of_me; - // only serialized when box_type is thruster or gyroscope, used for both. Thrust // can mean rotation thrust! double wanted_thrust; // the thrust command applied to the thruster double thrust; // the actual thrust it can provide based on energy sources in the grid - + // only gyroscope, velocity not serialized. Cosmetic double gyrospin_angle; double gyrospin_velocity; @@ -353,8 +369,13 @@ typedef struct Entity BOX_UNLOCKS_TYPE blueprints_learned; double scanner_head_rotate_speed; // not serialized, cosmetic double scanner_head_rotate; - cpVect platonic_nearest_direction; // normalized - double platonic_detection_strength; // from zero to one + + struct ScannerPoint + { + char kind; // is of ScannerPointKind + char x; + char y; + } scanner_points[SCANNER_MAX_POINTS]; } Entity; typedef struct Player @@ -583,7 +604,7 @@ typedef struct BoxCentered static inline bool box_has_point(BoxCentered box, cpVect point) { cpVect local_point = cpvspin(cpvsub(point, box.pos), -box.rotation); - return has_point((AABB){.x = -box.size.x/2.0, .y = -box.size.y/2.0, .width = box.size.x, .height = box.size.y}, local_point); + return has_point((AABB){.x = -box.size.x / 2.0, .y = -box.size.y / 2.0, .width = box.size.x, .height = box.size.y}, local_point); } static double sign(double f)