Add unlockable explosive block

main
Cameron Murphy Reikes 2 years ago
parent a92656699d
commit 238c81ecde

@ -471,11 +471,18 @@ static cpBool on_damage(cpArbiter* arb, cpSpace* space, cpDataPointer userData)
entity_b = cp_shape_entity(b); entity_b = cp_shape_entity(b);
float damage = V2length(cp_to_v2(cpArbiterTotalImpulse(arb))) * COLLISION_DAMAGE_SCALING; float damage = V2length(cp_to_v2(cpArbiterTotalImpulse(arb))) * COLLISION_DAMAGE_SCALING;
if (entity_a->is_box && entity_a->box_type == BoxExplosive)
entity_a->damage += 2.0f*EXPLOSION_DAMAGE_THRESHOLD;
if (entity_b->is_box && entity_b->box_type == BoxExplosive)
entity_b->damage += 2.0f*EXPLOSION_DAMAGE_THRESHOLD;
if (damage > 0.05f) if (damage > 0.05f)
{ {
// Log("Collision with damage %f\n", damage); // Log("Collision with damage %f\n", damage);
entity_a->damage += damage; entity_a->damage += damage;
entity_b->damage += damage; entity_b->damage += damage;
} }
// b must be the key passed into the post step removed, the key is cast into its shape // b must be the key passed into the post step removed, the key is cast into its shape
@ -515,12 +522,6 @@ 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* e)
{
assert(!e->is_box);
// @Robust merge entity_pos with box_pos
return cp_to_v2(cpBodyGetPosition(e->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));
@ -568,15 +569,20 @@ float entity_shape_mass(Entity* box)
assert(box->shape != NULL); assert(box->shape != NULL);
return (float)cpShapeGetMass(box->shape); return (float)cpShapeGetMass(box->shape);
} }
V2 box_pos(Entity* box)
{
assert(box->is_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 (float)cpBodyGetAngle(cpShapeGetBody(box->shape)); return (float)cpBodyGetAngle(cpShapeGetBody(box->shape));
} }
V2 entity_pos(Entity* e)
{
if (e->is_box) {
return V2add(entity_pos(box_grid(e)), V2rotate(entity_shape_pos(e), entity_rotation(box_grid(e))));
}
else {
assert(e->body != NULL);
return cp_to_v2(cpBodyGetPosition(e->body));
}
}
struct BodyData struct BodyData
{ {
@ -711,6 +717,7 @@ void ser_player(SerState* ser, Player* p)
SER_VAR(&p->connected); SER_VAR(&p->connected);
if (p->connected) if (p->connected)
{ {
SER_VAR(&p->unlocked_bombs);
ser_entityid(ser, &p->entity); ser_entityid(ser, &p->entity);
ser_inputframe(ser, &p->input); ser_inputframe(ser, &p->input);
} }
@ -779,6 +786,14 @@ void ser_entity(SerState* ser, GameState* gs, Entity* e)
SER_VAR(&e->goldness); SER_VAR(&e->goldness);
} }
SER_VAR(&e->is_explosion);
if (e->is_explosion)
{
ser_V2(ser, &e->explosion_pos);
ser_V2(ser, &e->explosion_vel);
SER_VAR(&e->explosion_progresss);
}
SER_VAR(&e->is_grid); SER_VAR(&e->is_grid);
if (e->is_grid) if (e->is_grid)
{ {
@ -955,6 +970,34 @@ Entity* closest_to_point_in_radius(GameState* gs, V2 point, float radius)
return NULL; return NULL;
} }
static float cur_explosion_damage = 0.0f;
static V2 explosion_origin = { 0 };
static void explosion_callback_func(cpShape* shape, cpContactPointSet* points, void* data)
{
GameState* gs = (GameState*)data;
cp_shape_entity(shape)->damage += cur_explosion_damage;
Entity* parent = get_entity(gs, cp_shape_entity(shape)->shape_parent_entity);
V2 from_pos = entity_pos(cp_shape_entity(shape));
V2 impulse = V2scale(V2normalize(V2sub(from_pos, explosion_origin)), EXPLOSION_PUSH_STRENGTH);
assert(parent->body != NULL);
cpBodyApplyImpulseAtWorldPoint(parent->body, v2_to_cp(impulse), v2_to_cp(from_pos));
}
static void do_explosion(GameState* gs, Entity* explosion, float dt)
{
cur_explosion_damage = dt * EXPLOSION_DAMAGE_PER_SEC;
explosion_origin = explosion->explosion_pos;
cpBody* tmpbody = cpBodyNew(0.0f, 0.0f);
cpShape* circle = cpCircleShapeNew(tmpbody, EXPLOSION_RADIUS, v2_to_cp(explosion_origin));
cpSpaceShapeQuery(gs->space, circle, explosion_callback_func, (void*)gs);
cpShapeFree(circle);
cpBodyFree(tmpbody);
}
V2 box_facing_vector(Entity* box) V2 box_facing_vector(Entity* box)
{ {
assert(box->is_box); assert(box->is_box);
@ -1029,7 +1072,7 @@ void process(GameState* gs, float dt)
assert(p->is_player); assert(p->is_player);
#ifdef INFINITE_RESOURCES #ifdef INFINITE_RESOURCES
p->spice_taken_away = 0.0f; p->damage = 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)
@ -1066,7 +1109,7 @@ void process(GameState* gs, float dt)
} }
else else
{ {
V2 pilot_seat_exit_spot = V2add(box_pos(the_seat), V2scale(box_facing_vector(the_seat), BOX_SIZE)); V2 pilot_seat_exit_spot = V2add(entity_pos(the_seat), V2scale(box_facing_vector(the_seat), BOX_SIZE));
cpBodySetPosition(p->body, v2_to_cp(pilot_seat_exit_spot)); cpBodySetPosition(p->body, v2_to_cp(pilot_seat_exit_spot));
cpBodySetVelocity(p->body, v2_to_cp(player_vel(gs, p))); cpBodySetVelocity(p->body, v2_to_cp(player_vel(gs, p)));
the_seat->player_who_is_inside_of_me = (EntityID){ 0 }; the_seat->player_who_is_inside_of_me = (EntityID){ 0 };
@ -1095,7 +1138,7 @@ void process(GameState* gs, float dt)
{ {
assert(seat_inside_of->is_box); assert(seat_inside_of->is_box);
cpShapeSetFilter(p->shape, CP_SHAPE_FILTER_NONE); // no collisions while in a seat cpShapeSetFilter(p->shape, CP_SHAPE_FILTER_NONE); // no collisions while in a seat
cpBodySetPosition(p->body, v2_to_cp(box_pos(seat_inside_of))); cpBodySetPosition(p->body, v2_to_cp(entity_pos(seat_inside_of)));
// set thruster thrust from movement // set thruster thrust from movement
if (seat_inside_of->box_type == BoxCockpit) { if (seat_inside_of->box_type == BoxCockpit) {
@ -1194,8 +1237,27 @@ void process(GameState* gs, float dt)
cpBodyUpdateVelocity(e->body, g, 1.0f, dt); cpBodyUpdateVelocity(e->body, g, 1.0f, dt);
} }
if (e->is_explosion)
{
e->explosion_progresss += dt;
e->explosion_pos = V2add(e->explosion_pos, V2scale(e->explosion_vel, dt));
do_explosion(gs, e, dt);
if (e->explosion_progresss >= EXPLOSION_TIME)
{
entity_destroy(gs, e);
}
}
if (e->is_box) if (e->is_box)
{ {
if (e->box_type == BoxExplosive && e->damage >= EXPLOSION_DAMAGE_THRESHOLD)
{
Entity* explosion = new_entity(gs);
explosion->is_explosion = true;
explosion->explosion_pos = entity_pos(e);
explosion->explosion_vel = grid_vel(box_grid(e));
grid_remove_box(gs, get_entity(gs, e->shape_parent_entity), e);
}
if (e->damage >= 1.0f) if (e->damage >= 1.0f)
{ {
grid_remove_box(gs, get_entity(gs, e->shape_parent_entity), e); grid_remove_box(gs, get_entity(gs, e->shape_parent_entity), e);
@ -1208,7 +1270,7 @@ void process(GameState* gs, float dt)
BOXES_ITER(gs, cur, e) BOXES_ITER(gs, cur, e)
{ {
if (cur->box_type == BoxSolarPanel) { if (cur->box_type == BoxSolarPanel) {
cur->sun_amount = clamp01(V2dot(box_facing_vector(cur), V2normalize(V2sub(SUN_POS, box_pos(cur))))); cur->sun_amount = clamp01(V2dot(box_facing_vector(cur), V2normalize(V2sub(SUN_POS, entity_pos(cur)))));
energy_to_add += cur->sun_amount * SOLAR_ENERGY_PER_SECOND * dt; energy_to_add += cur->sun_amount * SOLAR_ENERGY_PER_SECOND * dt;
} }
} }
@ -1237,7 +1299,7 @@ void process(GameState* gs, float dt)
if (possibly_use_energy(gs, e, energy_to_consume)) if (possibly_use_energy(gs, e, energy_to_consume))
{ {
cur->thrust = cur->wanted_thrust; cur->thrust = cur->wanted_thrust;
cpBodyApplyForceAtWorldPoint(e->body, v2_to_cp(thruster_force(cur)), v2_to_cp(box_pos(cur))); cpBodyApplyForceAtWorldPoint(e->body, v2_to_cp(thruster_force(cur)), v2_to_cp(entity_pos(cur)));
} }
} }
if (cur->box_type == BoxMedbay) if (cur->box_type == BoxMedbay)

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

@ -54,6 +54,8 @@ static sg_image image_stars;
static sg_image image_stars2; static sg_image image_stars2;
static sg_image image_sun; static sg_image image_sun;
static sg_image image_medbay_used; static sg_image image_medbay_used;
static sg_image image_mystery;
static sg_image image_explosion;
static int cur_editing_boxtype = -1; static int cur_editing_boxtype = -1;
static int cur_editing_rotation = 0; static int cur_editing_rotation = 0;
@ -61,6 +63,7 @@ static struct BoxInfo {
enum BoxType type; enum BoxType type;
const char* image_path; const char* image_path;
sg_image image; sg_image image;
bool needs_tobe_unlocked;
} boxes[] = { } boxes[] = {
// if added to here will show up in toolbar, is placeable // if added to here will show up in toolbar, is placeable
{ {
@ -75,10 +78,6 @@ 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",
@ -87,6 +86,15 @@ static struct BoxInfo {
.type = BoxMedbay, .type = BoxMedbay,
.image_path = "loaded/medbay.png", .image_path = "loaded/medbay.png",
}, },
{
.type = BoxSolarPanel,
.image_path = "loaded/solarpanel.png",
},
{
.type = BoxExplosive,
.image_path = "loaded/explosive.png",
.needs_tobe_unlocked = true,
},
}; };
const int boxes_len = sizeof(boxes) / sizeof(*boxes); const int boxes_len = sizeof(boxes) / sizeof(*boxes);
@ -171,6 +179,8 @@ init(void)
image_stars2 = load_image("loaded/stars2.png"); image_stars2 = load_image("loaded/stars2.png");
image_sun = load_image("loaded/sun.png"); image_sun = load_image("loaded/sun.png");
image_medbay_used = load_image("loaded/medbay_used.png"); image_medbay_used = load_image("loaded/medbay_used.png");
image_mystery = load_image("loaded/mystery.png");
image_explosion = load_image("loaded/explosion.png");
} }
// socket initialization // socket initialization
@ -273,6 +283,22 @@ myentity()
return to_return; return to_return;
} }
bool can_build(int i)
{
bool allow_building = true;
if (boxinfo((enum BoxType)i).needs_tobe_unlocked)
{
allow_building = gs.players[myplayer].unlocked_bombs;
}
return allow_building;
}
void attempt_to_build(int i)
{
if (can_build(i))
cur_editing_boxtype = i;
}
static void static void
ui(bool draw, float dt, float width, float height) ui(bool draw, float dt, float width, float height)
{ {
@ -326,8 +352,8 @@ ui(bool draw, float dt, float width, float height)
mouse_pos) mouse_pos)
&& mouse_pressed) { && mouse_pressed) {
// "handle" mouse pressed // "handle" mouse pressed
attempt_to_build(i);
mouse_pressed = false; mouse_pressed = false;
cur_editing_boxtype = i;
} }
if (draw) { if (draw) {
@ -339,7 +365,14 @@ ui(bool draw, float dt, float width, float height)
sgp_set_image(0, image_itemframe); sgp_set_image(0, image_itemframe);
} }
sgp_draw_textured_rect(x, y, itemframe_width, itemframe_height); sgp_draw_textured_rect(x, y, itemframe_width, itemframe_height);
sgp_set_image(0, boxinfo((enum BoxType)i).image); struct BoxInfo info = boxinfo((enum BoxType)i);
if (can_build(i))
{
sgp_set_image(0, info.image);
}
else {
sgp_set_image(0, image_mystery);
}
transform_scope transform_scope
{ {
float item_x = x + item_offset_x; float item_x = x + item_offset_x;
@ -706,8 +739,8 @@ frame(void)
{ {
if (b->type == BoxThruster) if (b->type == BoxThruster)
{ {
dbg_rect(box_pos(b)); dbg_rect(entity_pos(b));
dbg_line(box_pos(b), V2add(box_pos(b), V2scale(thruster_force(b), -1.0f))); dbg_line(entity_pos(b), V2add(entity_pos(b), V2scale(thruster_force(b), -1.0f)));
} }
} }
#endif #endif
@ -721,8 +754,8 @@ frame(void)
transform_scope transform_scope
{ {
sgp_rotate_at(entity_rotation(g) + rotangle(b->compass_rotation), sgp_rotate_at(entity_rotation(g) + rotangle(b->compass_rotation),
box_pos(b).x, entity_pos(b).x,
box_pos(b).y); entity_pos(b).y);
if (b->box_type == BoxThruster) { if (b->box_type == BoxThruster) {
transform_scope transform_scope
@ -735,8 +768,8 @@ frame(void)
// float scaling = 1.1; // float scaling = 1.1;
// sgp_translate(-(scaling*BOX_SIZE - BOX_SIZE), 0.0); // sgp_translate(-(scaling*BOX_SIZE - BOX_SIZE), 0.0);
// sgp_scale(scaling, 1.0); // sgp_scale(scaling, 1.0);
sgp_scale_at(scaling, 1.0f, box_pos(b).x, box_pos(b).y); sgp_scale_at(scaling, 1.0f, entity_pos(b).x, entity_pos(b).y);
draw_texture_centered(box_pos(b), BOX_SIZE); draw_texture_centered(entity_pos(b), BOX_SIZE);
sgp_reset_image(0); sgp_reset_image(0);
} }
} }
@ -752,7 +785,7 @@ frame(void)
img = image_medbay_used; img = image_medbay_used;
} }
sgp_set_image(0, img); sgp_set_image(0, img);
draw_texture_centered(box_pos(b), BOX_SIZE); draw_texture_centered(entity_pos(b), BOX_SIZE);
sgp_reset_image(0); sgp_reset_image(0);
if (b->box_type == BoxSolarPanel) if (b->box_type == BoxSolarPanel)
@ -760,11 +793,11 @@ frame(void)
Color to_set = colhexcode(0xeb9834); Color to_set = colhexcode(0xeb9834);
to_set.a = b->sun_amount * 0.5f; to_set.a = b->sun_amount * 0.5f;
set_color(to_set); set_color(to_set);
draw_color_rect_centered(box_pos(b), BOX_SIZE); draw_color_rect_centered(entity_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(entity_pos(b), BOX_SIZE);
} }
} }
@ -784,7 +817,15 @@ frame(void)
sgp_reset_image(0); sgp_reset_image(0);
} }
} }
if (e->is_explosion)
{
sgp_set_image(0, image_explosion);
sgp_set_color(1.0f, 1.0f, 1.0f, 1.0f - (e->explosion_progresss / EXPLOSION_TIME));
draw_texture_centered(e->explosion_pos, EXPLOSION_RADIUS*2.0f);
sgp_reset_image(0);
}
} }
// gold target // gold target
set_color(GOLD); set_color(GOLD);
sgp_draw_filled_rect(gs.goldpos.x, gs.goldpos.y, 0.1f, 0.1f); sgp_draw_filled_rect(gs.goldpos.x, gs.goldpos.y, 0.1f, 0.1f);
@ -843,7 +884,7 @@ void event(const sapp_event* e)
int key_num = e->key_code - SAPP_KEYCODE_0; int key_num = e->key_code - SAPP_KEYCODE_0;
int target_box = key_num - 1; int target_box = key_num - 1;
if (target_box < BoxLast) { if (target_box < BoxLast) {
cur_editing_boxtype = target_box; attempt_to_build(target_box);
} }
if (!mouse_frozen) { if (!mouse_frozen) {

@ -21,6 +21,11 @@ void server(void* data)
initialize(&gs, entity_data, entities_size); initialize(&gs, entity_data, entities_size);
Log("Allocated %zu bytes for entities\n", entities_size); Log("Allocated %zu bytes for entities\n", entities_size);
// unlock the explosive
if (true)
{
}
// one box policy // one box policy
if (false) if (false)
{ {
@ -122,6 +127,9 @@ void server(void* data)
event.peer->data = (void*)player_slot; event.peer->data = (void*)player_slot;
gs.players[player_slot] = (struct Player){ 0 }; gs.players[player_slot] = (struct Player){ 0 };
gs.players[player_slot].connected = true; gs.players[player_slot].connected = true;
#ifdef UNLOCK_ALL
gs.players[player_slot].unlocked_bombs = true;
#endif
} }
break; break;

@ -6,13 +6,12 @@
#define PLAYER_SIZE ((V2){.x = BOX_SIZE, .y = BOX_SIZE}) #define PLAYER_SIZE ((V2){.x = BOX_SIZE, .y = BOX_SIZE})
#define PLAYER_MASS 0.5f #define PLAYER_MASS 0.5f
#define PLAYER_JETPACK_FORCE 2.0f #define PLAYER_JETPACK_FORCE 2.0f
//#define PLAYER_JETPACK_SPICE_PER_SECOND 0.3f #define PLAYER_JETPACK_SPICE_PER_SECOND 0.3f
#define PLAYER_JETPACK_SPICE_PER_SECOND 0.0f
#define MAX_HAND_REACH 1.0f #define MAX_HAND_REACH 1.0f
#define GOLD_COLLECT_RADIUS 0.3f #define GOLD_COLLECT_RADIUS 0.3f
#define BUILD_BOX_SNAP_DIST_TO_SHIP 0.2f #define BUILD_BOX_SNAP_DIST_TO_SHIP 0.2f
#define BOX_MASS 1.0f #define BOX_MASS 1.0f
#define COLLISION_DAMAGE_SCALING 0.1f #define COLLISION_DAMAGE_SCALING 0.15f
#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
@ -25,6 +24,11 @@
#define DAMAGE_TO_PLAYER_PER_BLOCK 0.1f #define DAMAGE_TO_PLAYER_PER_BLOCK 0.1f
#define BATTERY_CAPACITY DAMAGE_TO_PLAYER_PER_BLOCK #define BATTERY_CAPACITY DAMAGE_TO_PLAYER_PER_BLOCK
#define PLAYER_ENERGY_RECHARGE_PER_SECOND 0.1f #define PLAYER_ENERGY_RECHARGE_PER_SECOND 0.1f
#define EXPLOSION_TIME 0.5f
#define EXPLOSION_PUSH_STRENGTH 5.0f
#define EXPLOSION_DAMAGE_PER_SEC 10.0f
#define EXPLOSION_RADIUS 1.0f
#define EXPLOSION_DAMAGE_THRESHOLD 0.2f // how much damage until it explodes
#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)
@ -86,6 +90,7 @@ enum BoxType
BoxCockpit, BoxCockpit,
BoxMedbay, BoxMedbay,
BoxSolarPanel, BoxSolarPanel,
BoxExplosive,
BoxLast, BoxLast,
}; };
@ -150,6 +155,12 @@ typedef struct Entity
EntityID currently_inside_of_box; EntityID currently_inside_of_box;
float goldness; // how much the player is a winner float goldness; // how much the player is a winner
// explosion
bool is_explosion;
V2 explosion_pos;
V2 explosion_vel;
float explosion_progresss; // in seconds
// grids // grids
bool is_grid; bool is_grid;
float total_energy_capacity; float total_energy_capacity;
@ -171,6 +182,7 @@ typedef struct Entity
typedef struct Player typedef struct Player
{ {
bool connected; bool connected;
bool unlocked_bombs;
EntityID entity; EntityID entity;
InputFrame input; InputFrame input;
} Player; } Player;
@ -269,7 +281,6 @@ V2 grid_world_to_local(Entity* grid, V2 world);
V2 grid_snapped_box_pos(Entity* grid, V2 world); // returns the snapped pos in world coords V2 grid_snapped_box_pos(Entity* grid, V2 world); // returns the snapped pos in world coords
float entity_angular_velocity(Entity* grid); float entity_angular_velocity(Entity* grid);
V2 entity_shape_pos(Entity* box); V2 entity_shape_pos(Entity* box);
V2 box_pos(Entity* box); // returns in world coords
float box_rotation(Entity* box); float box_rotation(Entity* box);
// thruster // thruster

Loading…
Cancel
Save