From ca2e4196d9409409bfe36b06a009ad42f1d7c04e Mon Sep 17 00:00:00 2001 From: Cameron Reikes Date: Sun, 6 Nov 2022 00:35:41 -0700 Subject: [PATCH] Add solar panel --- gamestate.c | 109 ++++++++++++++++++++++++++++++------------ loaded/solarpanel.png | Bin 0 -> 5748 bytes main.c | 14 +++++- types.h | 8 +++- 4 files changed, 99 insertions(+), 32 deletions(-) create mode 100644 loaded/solarpanel.png diff --git a/gamestate.c b/gamestate.c index e400f18..7a7b8fe 100644 --- a/gamestate.c +++ b/gamestate.c @@ -235,7 +235,7 @@ void entity_set_rotation(Entity* e, float rot) { assert(e->body != NULL); cpBodySetAngle(e->body, rot); -} +} void entity_set_pos(Entity* e, V2 pos) { @@ -270,12 +270,14 @@ void create_rectangle_shape(GameState* gs, Entity* e, Entity* parent, V2 pos, V2 cpSpaceAddShape(gs->space, e->shape); } +#define PLAYER_SHAPE_FILTER cpShapeFilterNew(CP_NO_GROUP, PLAYERS, CP_ALL_CATEGORIES) + void create_player(GameState* gs, Entity* e) { e->is_player = true; create_body(gs, e); 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, PLAYER_SHAPE_FILTER); } // box must be passed as a parameter as the box added to chipmunk uses this pointer in its @@ -653,7 +655,7 @@ void ser_var(SerState* ser, char* var_pointer, size_t var_size, const char* name { printf("%s:%d | Expected variable %s but got %sn\n", file, line, var_name, read_name); *(char*)NULL = 0; -} + } } #endif for (int b = 0; b < var_size; b++) @@ -668,6 +670,7 @@ void ser_var(SerState* ser, char* var_pointer, size_t var_size, const char* name #define SER_VAR_NAME(var_pointer, name) ser_var(ser, (char*)var_pointer, sizeof(*var_pointer), name, __FILE__, __LINE__) #define SER_VAR(var_pointer) SER_VAR_NAME(var_pointer, #var_pointer) +// @Robust probably get rid of this as separate function, just use SER_VAR void ser_V2(SerState* ser, V2* var) { SER_VAR(&var->x); @@ -739,9 +742,10 @@ void ser_entity(SerState* ser, GameState* gs, Entity* e) if (has_shape) { - SER_VAR(&e->shape_size); + ser_V2(ser, &e->shape_size); ser_entityid(ser, &e->shape_parent_entity); - + Entity* parent = get_entity(gs, e->shape_parent_entity); + assert(parent != NULL); V2 shape_pos; if (ser->serializing) @@ -753,14 +757,18 @@ void ser_entity(SerState* ser, GameState* gs, Entity* e) shape_mass = entity_shape_mass(e); SER_VAR(&shape_mass); - Entity* parent = get_entity(gs, e->shape_parent_entity); - if (parent == NULL) + cpShapeFilter filter; + if (ser->serializing) { - printf("Null shape parent\n"); + filter = cpShapeGetFilter(e->shape); } + SER_VAR(&filter.categories); + SER_VAR(&filter.group); + SER_VAR(&filter.mask); if (!ser->serializing) { create_rectangle_shape(gs, e, parent, shape_pos, e->shape_size, shape_mass); + cpShapeSetFilter(e->shape, filter); } } @@ -789,6 +797,7 @@ void ser_entity(SerState* ser, GameState* gs, Entity* e) SER_VAR(&e->thrust); SER_VAR(&e->wanted_thrust); SER_VAR(&e->energy_used); + SER_VAR(&e->sun_amount); ser_entityid(ser, &e->piloted_by); } } @@ -828,19 +837,13 @@ void ser_server_to_client(SerState* ser, ServerToClient* s) Entity* e = &gs->entities[i]; if (e->exists) { - if (e->is_player) - { - SER_VAR(&entities_done); - SER_VAR(&i); - ser_entity(ser, gs, e); - } - else if (e->is_grid) + SER_VAR(&entities_done); + SER_VAR(&i); + ser_entity(ser, gs, e); + if (e->is_grid) { // 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. - SER_VAR(&entities_done); - SER_VAR(&i); - ser_entity(ser, gs, e); BOXES_ITER(gs, cur, e) { EntityID cur_id = get_id(gs, cur); @@ -986,6 +989,20 @@ V2 get_world_hand_pos(GameState* gs, InputFrame* input, Entity* player) } } +// return true if used the energy +bool possibly_use_energy(GameState* gs, Entity* grid, float wanted_energy) +{ + BOXES_ITER(gs, possible_battery, grid) + { + if (possible_battery->box_type == BoxBattery && (BATTERY_CAPACITY - possible_battery->energy_used) > wanted_energy) + { + possible_battery->energy_used += wanted_energy; + return true; + } + } + return false; +} + void process(GameState* gs, float dt) { assert(gs->space != NULL); @@ -1007,13 +1024,13 @@ void process(GameState* gs, float dt) player->entity = get_id(gs, p); cpVect pos = v2_to_cp(V2sub(entity_pos(p), SUN_POS)); cpFloat r = cpvlength(pos); - cpFloat v = cpfsqrt(SUN_GRAVITY_STRENGTH/ r) / r; + cpFloat v = cpfsqrt(SUN_GRAVITY_STRENGTH / r) / r; cpBodySetVelocity(p->body, cpvmult(cpvperp(pos), v)); } assert(p->is_player); #ifdef INFINITE_RESOURCES - p->spice_taken_away = 0.0f; + p->spice_taken_away = 0.0f; #endif // update gold win condition if (V2length(V2sub(cp_to_v2(cpBodyGetPosition(p->body)), gs->goldpos)) < GOLD_COLLECT_RADIUS) @@ -1072,7 +1089,7 @@ void process(GameState* gs, float dt) if (piloting_seat == NULL) { - cpShapeSetFilter(p->shape, CP_SHAPE_FILTER_ALL); + cpShapeSetFilter(p->shape, PLAYER_SHAPE_FILTER); 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; } @@ -1117,8 +1134,8 @@ void process(GameState* gs, float dt) { Entity* cur_box = cp_shape_entity(nearest); Entity* cur_grid = cp_body_entity(cpShapeGetBody(nearest)); + p->spice_taken_away -= SPICE_PER_BLOCK*((BATTERY_CAPACITY - cur_box->energy_used)/BATTERY_CAPACITY); grid_remove_box(gs, cur_grid, cur_box); - p->spice_taken_away -= 0.1f; } else if (target_grid == NULL) { @@ -1140,7 +1157,7 @@ void process(GameState* gs, float dt) grid_correct_for_holes(gs, target_grid); // no holey ship for you! new_box->box_type = player->input.build_type; new_box->compass_rotation = player->input.build_rotation; - p->spice_taken_away += 0.1f; + p->spice_taken_away += SPICE_PER_BLOCK; } } #endif @@ -1161,7 +1178,7 @@ void process(GameState* gs, float dt) if (e->body != NULL) { - cpVect p = cpvsub(cpBodyGetPosition(e->body),v2_to_cp(SUN_POS)); + cpVect p = cpvsub(cpBodyGetPosition(e->body), v2_to_cp(SUN_POS)); cpFloat sqdist = cpvlengthsq(p); if (sqdist < (SUN_RADIUS * SUN_RADIUS)) { @@ -1182,20 +1199,52 @@ void process(GameState* gs, float dt) } if (e->is_grid) { + // calculate how much energy solar panels provide + float energy_to_add = 0.0f; + BOXES_ITER(gs, cur, e) + { + if (cur->box_type == BoxSolarPanel) { + cur->sun_amount = clamp01(V2dot(box_facing_vector(cur), V2normalize(V2sub(SUN_POS, box_pos(cur))))); + energy_to_add += cur->sun_amount * SOLAR_ENERGY_PER_SECOND * dt; + } + } + + // apply all of the energy to all connected batteries + BOXES_ITER(gs, cur, e) + { + if (energy_to_add <= 0.0f) + break; + if (cur->box_type == BoxBattery) + { + float energy_sucked_up_by_battery = cur->energy_used < energy_to_add ? cur->energy_used : energy_to_add; + cur->energy_used -= energy_sucked_up_by_battery; + energy_to_add -= energy_sucked_up_by_battery; + } + assert(energy_to_add >= 0.0f); + } + + // use the energy, stored in the batteries, in various boxes BOXES_ITER(gs, cur, e) { if (cur->box_type == BoxThruster) { float energy_to_consume = cur->wanted_thrust * THRUSTER_ENERGY_USED_PER_SECOND * dt; cur->thrust = 0.0f; - BOXES_ITER(gs, possible_battery, e) + if (possibly_use_energy(gs, e, energy_to_consume)) + { + cur->thrust = cur->wanted_thrust; + cpBodyApplyForceAtWorldPoint(e->body, v2_to_cp(thruster_force(cur)), v2_to_cp(box_pos(cur))); + } + } + if (cur->box_type == BoxCockpit) + { + Entity* potential_pilot = get_entity(gs, cur->piloted_by); + if (potential_pilot != NULL && potential_pilot->spice_taken_away) { - if (possible_battery->box_type == BoxBattery && (1.0f - possible_battery->energy_used) > energy_to_consume) + float energy_to_recharge = min(potential_pilot->spice_taken_away, PLAYER_ENERGY_RECHARGE_PER_SECOND * dt); + if (possibly_use_energy(gs, e, energy_to_recharge)) { - possible_battery->energy_used += energy_to_consume; - cur->thrust = cur->wanted_thrust; - cpBodyApplyForceAtWorldPoint(e->body, v2_to_cp(thruster_force(cur)), v2_to_cp(box_pos(cur))); - break; + potential_pilot->spice_taken_away -= energy_to_recharge; } } } diff --git a/loaded/solarpanel.png b/loaded/solarpanel.png new file mode 100644 index 0000000000000000000000000000000000000000..a740d70de5ee74d7e5b6b14cfe0911a949a8c60b GIT binary patch literal 5748 zcmeHKdpuP879U}h*C@AAk!jLH%zGF!8LAnfj69<_vS((`G>v(f2a`hSNb1PrsB^+8 zQgmH$s9aK^De4#;(%Y+$<4B0=bfWGadgyb{=W{=OKKK0B{>$mp) zC3<1j6;<;jMi9q-rXGtsi=DECgqpxtW zk3##-&bG8WWnydWp60;Lj<9%Lo_3`BqUBRcc|+#L>K~=$l`qZ!11Cl~;-f3sJ(h<2 z_BiQ$tNSls+%zf9%v{_M{&0VbeUEb1_C+@YLH1Tj$w4cl+aFe#eiO?LVGN0?99X!#Klw`1a*L#6+_>4<`4Dw^%Ts0%kJx~}@ z61PoFyeDC!$i-gTC{l#i#O$uo-A>DkjA#D2p!XPR)?RcyV`R*GR-4xOeJAUpdy&`6 zjF61L2dV{}{U%;Z`>a!v)TuM~`oYp4QCB~jp>t!GNRoEF0v49u*P>k3lJm=Pybzbn zf?GL0x0#XIL#UoJ(zWRyx(TI`A(vj&xE4FTHV;neqR+&uPyU#Dh;=e~N$nZ@^+HdV z%kZRv4AKfuW0za`DXf-spTDP21HY0_bwE+{;_7qs#*g( zb*(ZZdyD7zHN!n6vu8XGUk6(^dQH75ahM@uaZQ)nII7&8@dDCp?YNf2iEPu=Dud?4 zw%Dr;jEYCKu?Mq`{W>wHBA~4!=MHyKfga1ofai6V{?cg2F+17Ktpn!Uj|;_}4Wrji zbW{=jvXp6w^Z$Hcp0i_41nD%LV>M9v6N3AAH@~&{u=n*P0?VzLwKSVLqiEW^T^_HG zYK6^sbFC{;s4mqB?ZjW^<~oOr6{v25^H1mY*;z;i35UZy;Poyh-NSP)FWu`Q2)dlT z!cv@D{IqhQ>mFd@zxd)t)5f5%!J_+|`%lkZzgt3DbTKxsSJv|9Zyhki;hnzPN`FD{ zV))M!X=rcH)oqqF7@N(_`SQjsGW~>8m#yL>#oIPVDRwodpGk;tJh1R;S%BN1igcmu zlK$?8p)x_dn{|H8W#L^mac_)yf9)d^?!b<=oUG2Agtl?Zy~k@v+w`JFA4FNyy>Y+L z-&nr&#S(-XzvdKzzxfomGyTr;rddQs?2?&Sa$3QbXWw?klpZTW{0_Plb_<%H96A3o z`JP&V&f_C_9)TNb6xeObw`aSb_)e4|%_X^k9mj%yRY}hbS>{h(rztsx-owI@vBz;YDH;VD{sg-?1A4?m-Nz&hF8`N_9JFWyt`=r zYMTJ*v(>z`0l?KnA>wR_E9mtPbvhC}qv{YQTKVF)G2?%i1X#paEg5ReZ5iWXGK+UV zi}ub|i`y?8RBX~o%It*4vBW=zG{CE7ZM&2zyypG;l^e6>>YCbjKN?O_h^dV~7}W(^ zA0=0Etp9%ExmMmQ%L*I(wkjJd zg!*k^O7OBipRu5l4GS?(k0zybFtgIE4-DNHxw2x>%K#k0=Xmq_W$>o5)qh0G;_-t~ z`{>1GLBo~rZ0P~>bRNV9t-5k(GqXwhFS_Nq0BS~%Q_THz=j!N4a;Nq9SPZcT?v&j3 zj`CKwIa{&$hA#Sh7)&dkPp5mi)9D}jH`KMWqEl&Zsx@Z&JM)en+-zQme4LU)-C{B~ zJbl%?nst1e^S_5m`z=X)H=kg0-Mex7oDccy&F6h%5v;p*Snpc%P4{M(4dWQ=^9M!_ zcQ5XE)A2*)5G=x@Jeh(A=2jej%Z_&IF_=r01w5(%=@wv29CMQgj7s=N?b}g#MRE1-xw!`Y5Q{5X( z6B4hp^y)3t8}@H-WSV>XB|VQXtk>^DH|{uHyY*EM*0A@&5z<|L67ujetCVkNF0f1Y z-W$JiaG~{bANk_ZVZ`dURuvrSk(wJNdsg|m9kv`t#Jsv=>%qL}o?~XBEE!DpMwT0p z2FfO)!yY!6R=+b0<_lvlXsKh;Ld1g9rP;BI%F9K9=Zhs3+J?0Lv?Y|Z6Gy#P!iIQb zOiF0iyx+FS-rS+q^=qf(grGZNdI{Bmsik*m9qsM+{~asXI`KveKO{}cF?qNKdeKJk zp%-c((}T(u3o!sk%mOh=p#*y2!eEZhN(sOgfN~@Y;(n(6A@)gSNQ=p&GQ@0!W_s=n8cO4z$`P~q9O~39k>$Vw9mr^VkWEID@E`@v z0ssygPqd>r*aHNP9R-{QOc6WI1-3I$C8xCAtb3xH?`7MY7? z;aGSU9tTiZB+fL5O;SEol|b0^S!tj+5EMY+kSQz&0-8c3+M`J#`5DZ6IxIlKn^efIS7H`2m~q~PsQ2!;q9pe=;wgO zk*T<8`eF{ByYqi(YnBhvaVqIQ0_=cH(AP5FZ1Q%_TmVf@L(ghWm*3o5{#3PA=$ zfK%y$u%?FC+W`>|g!;$(g8d-p|3xv7K^%t!Kq&)A6c$tr92S~IA={%lAO|25$y^G^ znyROd=rS=^9tlXnwLFMNh%2Z-C%Hnde4i@oN!C8m!T>g0>~{YuwYy1s~k zFH-(mU0>EI4bUD+6W?vx5QXggsS| zWR}Ejiwp)cFx8w|u#7A-NT?@wXS(P;G0>gA(0n9rPc*cd#<(-q`Z?6IIY^ilX!Nf8 zdma!P8tTTq`!3d_>A+fl&;5I$$?F zCCqsacecc8WA8dUT;BfLxZK>AQ0cVak}RSfyjs^g15$k)yvH~c6L@~Np0=sI?%R$# zhCf#?dM;g=JA0nPJ(liz)upZ>Vbbsn$TvKsC^k^rKul_!*qPcqFqe^AkY%_J sI_aB5%T%LveG8h|xenergy_used); + Color result = Collerp(from, to, b->energy_used/BATTERY_CAPACITY); sgp_set_color(result.r, result.g, result.b, cur_alpha); } transform_scope @@ -741,6 +745,14 @@ frame(void) draw_texture_centered(box_pos(b), BOX_SIZE); sgp_reset_image(0); + if (b->box_type == BoxSolarPanel) + { + Color to_set = colhexcode(0xeb9834); + to_set.a = b->sun_amount*0.5f; + set_color(to_set); + draw_color_rect_centered(box_pos(b), BOX_SIZE); + } + sgp_set_color(0.5f, 0.1f, 0.1f, b->damage); draw_color_rect_centered(box_pos(b), BOX_SIZE); } diff --git a/types.h b/types.h index cead86c..0092223 100644 --- a/types.h +++ b/types.h @@ -14,10 +14,14 @@ #define THRUSTER_FORCE 4.0f #define THRUSTER_ENERGY_USED_PER_SECOND 0.05f #define VISION_RADIUS 16.0f -#define MAX_BYTES_SIZE 2048 * 2 // maximum size of gamestate buffer +#define MAX_BYTES_SIZE 1024 * 8 // maximum size of gamestate buffer #define SUN_RADIUS 10.0f #define SUN_POS ((V2){50.0f,0.0f}) #define SUN_GRAVITY_STRENGTH (5.0e3f) +#define SOLAR_ENERGY_PER_SECOND 0.02f +#define SPICE_PER_BLOCK 0.1f +#define BATTERY_CAPACITY SPICE_PER_BLOCK +#define PLAYER_ENERGY_RECHARGE_PER_SECOND 0.1f #define TIMESTEP (1.0f / 60.0f) // not required to simulate at this, but this defines what tick the game is on #define TIME_BETWEEN_INPUT_PACKETS (1.0f / 20.0f) @@ -77,6 +81,7 @@ enum BoxType BoxThruster, BoxBattery, BoxCockpit, + BoxSolarPanel, BoxLast, }; @@ -156,6 +161,7 @@ typedef struct Entity float wanted_thrust; // the thrust command applied to the thruster float thrust; // the actual thrust it can provide based on energy sources in the grid float energy_used; // battery + float sun_amount; // solar panel, between 0 and 1 EntityID piloted_by; } Entity;