Add solar panel

main
Cameron Murphy Reikes 2 years ago
parent 16f3dfa443
commit ca2e4196d9

@ -235,7 +235,7 @@ void entity_set_rotation(Entity* e, float rot)
{ {
assert(e->body != NULL); assert(e->body != NULL);
cpBodySetAngle(e->body, rot); cpBodySetAngle(e->body, rot);
} }
void entity_set_pos(Entity* e, V2 pos) 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); cpSpaceAddShape(gs->space, e->shape);
} }
#define PLAYER_SHAPE_FILTER cpShapeFilterNew(CP_NO_GROUP, PLAYERS, CP_ALL_CATEGORIES)
void create_player(GameState* gs, Entity* e) void create_player(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, PLAYER_SHAPE_FILTER);
} }
// 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
@ -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); printf("%s:%d | Expected variable %s but got %sn\n", file, line, var_name, read_name);
*(char*)NULL = 0; *(char*)NULL = 0;
} }
} }
#endif #endif
for (int b = 0; b < var_size; b++) 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_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) #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) void ser_V2(SerState* ser, V2* var)
{ {
SER_VAR(&var->x); SER_VAR(&var->x);
@ -739,9 +742,10 @@ void ser_entity(SerState* ser, GameState* gs, Entity* e)
if (has_shape) if (has_shape)
{ {
SER_VAR(&e->shape_size); ser_V2(ser, &e->shape_size);
ser_entityid(ser, &e->shape_parent_entity); ser_entityid(ser, &e->shape_parent_entity);
Entity* parent = get_entity(gs, e->shape_parent_entity);
assert(parent != NULL);
V2 shape_pos; V2 shape_pos;
if (ser->serializing) if (ser->serializing)
@ -753,14 +757,18 @@ void ser_entity(SerState* ser, GameState* gs, Entity* e)
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); cpShapeFilter filter;
if (parent == NULL) 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) 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);
cpShapeSetFilter(e->shape, filter);
} }
} }
@ -789,6 +797,7 @@ void ser_entity(SerState* ser, GameState* gs, Entity* e)
SER_VAR(&e->thrust); SER_VAR(&e->thrust);
SER_VAR(&e->wanted_thrust); SER_VAR(&e->wanted_thrust);
SER_VAR(&e->energy_used); SER_VAR(&e->energy_used);
SER_VAR(&e->sun_amount);
ser_entityid(ser, &e->piloted_by); ser_entityid(ser, &e->piloted_by);
} }
} }
@ -828,19 +837,13 @@ void ser_server_to_client(SerState* ser, ServerToClient* s)
Entity* e = &gs->entities[i]; Entity* e = &gs->entities[i];
if (e->exists) if (e->exists)
{ {
if (e->is_player) SER_VAR(&entities_done);
{ SER_VAR(&i);
SER_VAR(&entities_done); ser_entity(ser, gs, e);
SER_VAR(&i); if (e->is_grid)
ser_entity(ser, gs, e);
}
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.
SER_VAR(&entities_done);
SER_VAR(&i);
ser_entity(ser, gs, e);
BOXES_ITER(gs, cur, e) BOXES_ITER(gs, cur, e)
{ {
EntityID cur_id = get_id(gs, cur); 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) void process(GameState* gs, float dt)
{ {
assert(gs->space != NULL); assert(gs->space != NULL);
@ -1007,13 +1024,13 @@ void process(GameState* gs, float dt)
player->entity = get_id(gs, p); player->entity = get_id(gs, p);
cpVect pos = v2_to_cp(V2sub(entity_pos(p), SUN_POS)); cpVect pos = v2_to_cp(V2sub(entity_pos(p), SUN_POS));
cpFloat r = cpvlength(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)); cpBodySetVelocity(p->body, cpvmult(cpvperp(pos), v));
} }
assert(p->is_player); assert(p->is_player);
#ifdef INFINITE_RESOURCES #ifdef INFINITE_RESOURCES
p->spice_taken_away = 0.0f; p->spice_taken_away = 0.0f;
#endif #endif
// update gold win condition // update gold win condition
if (V2length(V2sub(cp_to_v2(cpBodyGetPosition(p->body)), gs->goldpos)) < GOLD_COLLECT_RADIUS) 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) 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)); 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;
} }
@ -1117,8 +1134,8 @@ void process(GameState* gs, float dt)
{ {
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));
p->spice_taken_away -= SPICE_PER_BLOCK*((BATTERY_CAPACITY - cur_box->energy_used)/BATTERY_CAPACITY);
grid_remove_box(gs, cur_grid, cur_box); grid_remove_box(gs, cur_grid, cur_box);
p->spice_taken_away -= 0.1f;
} }
else if (target_grid == NULL) 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! grid_correct_for_holes(gs, target_grid); // no holey ship for you!
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;
p->spice_taken_away += 0.1f; p->spice_taken_away += SPICE_PER_BLOCK;
} }
} }
#endif #endif
@ -1161,7 +1178,7 @@ void process(GameState* gs, float dt)
if (e->body != NULL) 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); cpFloat sqdist = cpvlengthsq(p);
if (sqdist < (SUN_RADIUS * SUN_RADIUS)) if (sqdist < (SUN_RADIUS * SUN_RADIUS))
{ {
@ -1182,20 +1199,52 @@ void process(GameState* gs, float dt)
} }
if (e->is_grid) 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) BOXES_ITER(gs, cur, e)
{ {
if (cur->box_type == BoxThruster) if (cur->box_type == BoxThruster)
{ {
float energy_to_consume = cur->wanted_thrust * THRUSTER_ENERGY_USED_PER_SECOND * dt; float energy_to_consume = cur->wanted_thrust * THRUSTER_ENERGY_USED_PER_SECOND * dt;
cur->thrust = 0.0f; 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; potential_pilot->spice_taken_away -= energy_to_recharge;
cur->thrust = cur->wanted_thrust;
cpBodyApplyForceAtWorldPoint(e->body, v2_to_cp(thruster_force(cur)), v2_to_cp(box_pos(cur)));
break;
} }
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

@ -74,6 +74,10 @@ static struct BoxInfo {
.type = BoxBattery, .type = BoxBattery,
.image_path = "loaded/battery.png", .image_path = "loaded/battery.png",
}, },
{
.type = BoxSolarPanel,
.image_path = "loaded/solarpanel.png",
},
{ {
.type = BoxCockpit, .type = BoxCockpit,
.image_path = "loaded/cockpit.png", .image_path = "loaded/cockpit.png",
@ -705,7 +709,7 @@ frame(void)
float cur_alpha = sgp_get_color().a; float cur_alpha = sgp_get_color().a;
Color from = WHITE; Color from = WHITE;
Color to = colhex(255, 0, 0); Color to = colhex(255, 0, 0);
Color result = Collerp(from, to, b->energy_used); Color result = Collerp(from, to, b->energy_used/BATTERY_CAPACITY);
sgp_set_color(result.r, result.g, result.b, cur_alpha); sgp_set_color(result.r, result.g, result.b, cur_alpha);
} }
transform_scope transform_scope
@ -741,6 +745,14 @@ frame(void)
draw_texture_centered(box_pos(b), BOX_SIZE); draw_texture_centered(box_pos(b), BOX_SIZE);
sgp_reset_image(0); 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); sgp_set_color(0.5f, 0.1f, 0.1f, b->damage);
draw_color_rect_centered(box_pos(b), BOX_SIZE); draw_color_rect_centered(box_pos(b), BOX_SIZE);
} }

@ -14,10 +14,14 @@
#define THRUSTER_FORCE 4.0f #define THRUSTER_FORCE 4.0f
#define THRUSTER_ENERGY_USED_PER_SECOND 0.05f #define THRUSTER_ENERGY_USED_PER_SECOND 0.05f
#define VISION_RADIUS 16.0f #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_RADIUS 10.0f
#define SUN_POS ((V2){50.0f,0.0f}) #define SUN_POS ((V2){50.0f,0.0f})
#define SUN_GRAVITY_STRENGTH (5.0e3f) #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 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) #define TIME_BETWEEN_INPUT_PACKETS (1.0f / 20.0f)
@ -77,6 +81,7 @@ enum BoxType
BoxThruster, BoxThruster,
BoxBattery, BoxBattery,
BoxCockpit, BoxCockpit,
BoxSolarPanel,
BoxLast, BoxLast,
}; };
@ -156,6 +161,7 @@ typedef struct Entity
float wanted_thrust; // the thrust command applied to the thruster 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 thrust; // the actual thrust it can provide based on energy sources in the grid
float energy_used; // battery float energy_used; // battery
float sun_amount; // solar panel, between 0 and 1
EntityID piloted_by; EntityID piloted_by;
} Entity; } Entity;

Loading…
Cancel
Save