diff --git a/src/entity.c b/src/entity.c index 739a3bf1..1fe3777c 100644 --- a/src/entity.c +++ b/src/entity.c @@ -344,11 +344,10 @@ void entity_apply_angular_impulse(struct entity *ent, f32 impulse) ent->angular_velocity += impulse * inv_inertia; } -#if 0 void entity_apply_torque(struct entity *ent, f32 torque) { + ent->torque += torque; } -#endif /* ========================== * * Tree diff --git a/src/entity.h b/src/entity.h index df1de502..01e17029 100644 --- a/src/entity.h +++ b/src/entity.h @@ -142,7 +142,8 @@ struct entity { f32 mass_unscaled; /* Mass of entity in kg before any transformations */ f32 inertia_unscaled; /* Inertia of entity in kg*m^2 before any transformations */ - f32 ground_friction; + f32 linear_ground_friction; + f32 angular_ground_friction; struct v2 linear_velocity; /* m/s */ f32 angular_velocity; /* rad/s */ diff --git a/src/game.c b/src/game.c index bcbcc6ae..70e7cdd8 100644 --- a/src/game.c +++ b/src/game.c @@ -127,8 +127,9 @@ INTERNAL void spawn_test_entities(void) //struct v2 pos = V2(0.374142020941, -0.246118023992); /* Touching glitch spot */ struct v2 size = V2(1, 1); //f32 r = PI / 4; - f32 r = PI / 3; - //f32 r = 0; + //f32 r = PI / 3; + //f32 r = PI / 2; + f32 r = 0; f32 skew = 0; struct entity *e = entity_alloc(root); @@ -143,15 +144,16 @@ INTERNAL void spawn_test_entities(void) e->sprite_span_name = STR("idle.two_handed"); entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED); - //e->control_force = 4500; - e->control_force = 1200; + e->control_force = 4500; + //e->control_force = 1200; e->control_torque = 10; e->control.focus = V2(0, -1); entity_enable_prop(e, ENTITY_PROP_PHYSICAL); e->mass_unscaled = 100; - e->inertia_unscaled = 5; - e->ground_friction = 1000; + e->inertia_unscaled = 25; + e->linear_ground_friction = 1000; + e->angular_ground_friction = 100; //entity_enable_prop(e, ENTITY_PROP_TEST); @@ -192,13 +194,14 @@ INTERNAL void spawn_test_entities(void) entity_enable_prop(e, ENTITY_PROP_PHYSICAL); #if 0 - e->mass_unscaled = 300; - e->inertia_unscaled = 500; + e->mass_unscaled = 1000; + e->inertia_unscaled = 1000; #else e->mass_unscaled = F32_INFINITY; e->inertia_unscaled = F32_INFINITY; #endif - //e->ground_friction = 1000; + e->linear_ground_friction = 10000; + e->angular_ground_friction = 10000; entity_set_xform(e, XFORM_TRS(.t = pos, .s = size, .r = rot)); } @@ -761,17 +764,17 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) #endif /* ========================== * - * Create ground friction force + * Create ground friction force (gravity) * ========================== */ -#if 0 +#if 1 /* TODO: Do this globally rather than creating entities for constant forces */ for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { struct entity *ent = &store->entities[entity_index]; if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue; if (!entity_has_prop(ent, ENTITY_PROP_PHYSICAL)) continue; - if (ent->ground_friction != 0) { -#if 0 +#if 1 + if (ent->linear_ground_friction != 0) { /* Linear velocity */ { struct v2 linear_velocity = ent->linear_velocity; @@ -780,52 +783,45 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) const f32 clamp_epsilon = 0.01; f32 linear_velocity_len = v2_len(linear_velocity); if (linear_velocity_len >= clamp_epsilon) { - f32 force_len = -linear_velocity_len * ent->ground_friction; - struct entity *force = entity_alloc(ent); - entity_enable_prop(force, ENTITY_PROP_FORCE); - force->force = v2_mul(v2_norm(linear_velocity), force_len); - activate_now(force); + f32 force_len = -linear_velocity_len * ent->linear_ground_friction; + struct v2 force = v2_mul(v2_norm(linear_velocity), force_len); + entity_apply_force_to_center(ent, force); } else { /* If linear_velocity is below clamp_epsilon, stop entity movement. */ struct xform xf = entity_get_xform(ent); f32 mass = ent->mass_unscaled * math_fabs(xform_get_determinant(xf)); - struct entity *impulse = entity_alloc(ent); - entity_enable_prop(impulse, ENTITY_PROP_LINEAR_IMPULSE); - impulse->force = v2_mul(v2_neg(linear_velocity), mass); - activate_now(impulse); + struct v2 impulse = v2_mul(v2_neg(linear_velocity), mass); + entity_apply_linear_impulse_to_center(ent, impulse); } } } + } + if (ent->angular_ground_friction != 0) { /* Angular velocity */ { f32 angular_velocity = ent->angular_velocity; if (angular_velocity != 0) { - /* FIXME: Incorrect behavior at low FPS & low entity density */ + /* FIXME: Incorrect (just testing) */ const f32 clamp_epsilon = 0.001; if (math_fabs(angular_velocity) >= clamp_epsilon) { - struct entity *torque = entity_alloc(ent); - entity_enable_prop(torque, ENTITY_PROP_TORQUE); - /* TODO: Different ground friction for rotation */ - torque->torque = -angular_velocity * 3; - activate_now(torque); + f32 torque = -angular_velocity * ent->angular_ground_friction; + entity_apply_torque(ent, torque); } else { /* If angular_velocity is below clamp_epsilon, stop entity movement. */ struct xform xf = entity_get_xform(ent); f32 inertia = ent->inertia_unscaled * math_fabs(xform_get_determinant(xf)); - struct entity *impulse = entity_alloc(ent); - entity_enable_prop(impulse, ENTITY_PROP_ANGULAR_IMPULSE); - impulse->torque = -angular_velocity * inertia; - activate_now(impulse); + f32 impulse = -angular_velocity * inertia; + entity_apply_angular_impulse(ent, impulse); } } } + } #else /* TODO: Remove this (gravity test) */ struct xform xf = entity_get_xform(ent); f32 mass = ent->mass_unscaled * math_fabs(xform_get_determinant(xf)); entity_apply_force_to_center(ent, V2(0, 9.81 * mass)); #endif - } } #endif @@ -833,6 +829,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) * Integrate forces * ========================== */ +#if 0 for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { struct entity *ent = &store->entities[entity_index]; if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue; @@ -845,9 +842,10 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) /* Determine force & torque acceleration */ struct v2 tick_force_accel = v2_mul(v2_div(ent->force, mass), dt); - f32 tick_torque_accel = ent->torque / inertia * dt; + f32 tick_torque_accel = (ent->torque / inertia) * dt; /* Integrate */ + /* TODO: Don't need to multiply each term by dt separately */ struct v2 tick_linear_velocity = v2_add(v2_mul(ent->linear_velocity, dt), v2_mul(tick_force_accel, dt)); f32 tick_angular_velocity = (ent->angular_velocity * dt) + (tick_torque_accel * dt); @@ -861,6 +859,30 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) entity_set_xform(ent, xf); } +#else + for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { + struct entity *ent = &store->entities[entity_index]; + if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue; + if (!entity_has_prop(ent, ENTITY_PROP_PHYSICAL)) continue; + + struct xform xf = entity_get_xform(ent); + f32 det_abs = math_fabs(xform_get_determinant(xf)); + f32 mass = ent->mass_unscaled * det_abs; + f32 inertia = ent->inertia_unscaled * det_abs; + + /* Determine force & torque acceleration */ + struct v2 force_accel = v2_mul(v2_div(ent->force, mass), dt); + f32 torque_accel = (ent->torque / inertia) * dt; + + /* Integrate */ + ent->linear_velocity = v2_add(ent->linear_velocity, force_accel); + ent->angular_velocity += torque_accel; + + /* Reset forces */ + ent->force = V2(0, 0); + ent->torque = 0; + } +#endif #if 1 /* ========================== * @@ -942,13 +964,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) } { -#if 0 - if (colliding) { - xf1.og = v2_add(xf1.og, pen); - //e0->verlet_xform.og = xf0.og; - //e0->verlet_xform.og = v2_sub(xf1.og, velocity); - } -#else +#if 1 if (colliding) { struct entity *e1 = colliding_with; struct xform e1_xf = entity_get_xform(e1); @@ -972,11 +988,10 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) struct v2 pen_norm = v2_norm(pen); #if 1 - f32 bias_factor = 10; - f32 bias_slop = 0.01; + f32 bias_factor = 0.2; + f32 bias_slop = 0.005; - f32 bias = (v2_len(pen) * bias_factor) - bias_slop; - bias = max(bias, 0); + f32 bias = (bias_factor / dt) * max((v2_len(pen) - bias_slop), 0); #else f32 bias = 0; #endif @@ -991,6 +1006,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) struct v2 vrel = v2_sub(p1_vel, p0_vel); f32 vn = v2_dot(vrel, pen_norm); + vn = max_f32(vn, 0); struct v2 idk0 = v2_perp_mul(vcp0, v2_wedge(vcp0, pen_norm) * inv_i0); @@ -1000,7 +1016,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) /* (to be applied along n) */ f32 j = (vn + bias) / k; - j = max_f32(j, 0); + //j = max_f32(j, 0); @@ -1031,6 +1047,23 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) } #endif + /* ========================== * + * Update positions + * ========================== */ + + for (u64 entity_index = 0; entity_index < store->reserved; ++entity_index) { + struct entity *ent = &store->entities[entity_index]; + if (!(ent->valid && entity_has_prop(ent, ENTITY_PROP_ACTIVE))) continue; + if (!entity_has_prop(ent, ENTITY_PROP_PHYSICAL)) continue; + + struct xform xf = entity_get_xform(ent); + struct v2 tick_linear_velocity = v2_mul(ent->linear_velocity, dt); + f32 tick_angular_velocity = ent->angular_velocity * dt; + xf.og = v2_add(xf.og, tick_linear_velocity); + xf = xform_rotated(xf, tick_angular_velocity); + entity_set_xform(ent, xf); + } + /* ========================== * * Initialize bullet kinematics from sources * ========================== */ @@ -1053,7 +1086,7 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) entity_set_xform(ent, xf); entity_enable_prop(ent, ENTITY_PROP_PHYSICAL); - entity_apply_linear_impulse_to_center(src, impulse); + entity_apply_linear_impulse_to_center(ent, impulse); } } diff --git a/src/gjk.c b/src/gjk.c index 203ba8b0..7151cc70 100644 --- a/src/gjk.c +++ b/src/gjk.c @@ -225,8 +225,8 @@ struct gjk_extended_result gjk_extended(struct v2_array shape0, struct v2_array } /* ========================== * - * Expand simplex towards closest edge to origin inside menkowski - * ========================== */ + * Expand simplex towards closest edge to origin inside menkowski + * ========================== */ while (true) { f32 pen_len_sq = F32_INFINITY; diff --git a/src/math.h b/src/math.h index d4008ddb..7ebab470 100644 --- a/src/math.h +++ b/src/math.h @@ -651,7 +651,7 @@ INLINE struct v2 v2_perp(struct v2 a) return V2(-a.y, a.x); } -/* Perpendicular vector scaled by s */ +/* Right (clockwise) perpendicular vector scaled by s */ INLINE struct v2 v2_perp_mul(struct v2 a, f32 s) { return V2(s * -a.y, s * a.x); @@ -659,9 +659,8 @@ INLINE struct v2 v2_perp_mul(struct v2 a, f32 s) INLINE struct v2 v2_perp_towards_dir(struct v2 v, struct v2 dir) { - struct v2 perp = v2_perp(v); - f32 dot = v2_dot(perp, dir); - return v2_mul(perp, (dot >= 0) - (dot < 0)); + f32 wedge = v2_wedge(v, dir); + return v2_perp_mul(v, (wedge >= 0) - (wedge < 0)); } INLINE struct v2 v2_norm(struct v2 a) diff --git a/src/user.c b/src/user.c index 5de624bf..602e8964 100644 --- a/src/user.c +++ b/src/user.c @@ -993,33 +993,21 @@ INTERNAL void user_update(void) (UNUSED)e1; (UNUSED)colliding; -#if 0 +#if 1 /* Create shapes */ - struct quad ent_quad_xf0; - struct v2_array ent_poly_xf0; - struct quad ent_quad_xf1; - struct v2_array ent_poly_xf1; + struct quad ent_quad; + struct v2_array ent_poly; struct quad e1_quad; struct v2_array e1_poly; { { struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, ent->sprite); struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("shape"), ent->animation_frame); - ent_quad_xf0 = xform_mul_quad(ent->sprite_local_xform, quad_from_rect(slice.rect)); - ent_quad_xf0 = xform_mul_quad(ent->xf0, ent_quad_xf0); - ent_poly_xf0 = (struct v2_array) { - .count = ARRAY_COUNT(ent_quad_xf0.e), - .points = ent_quad_xf0.e - }; - } - { - struct sprite_sheet *sheet = sprite_sheet_from_tag_await(sprite_frame_scope, ent->sprite); - struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("shape"), ent->animation_frame); - ent_quad_xf1 = xform_mul_quad(ent->sprite_local_xform, quad_from_rect(slice.rect)); - ent_quad_xf1 = xform_mul_quad(ent->xf1, ent_quad_xf1); - ent_poly_xf1 = (struct v2_array) { - .count = ARRAY_COUNT(ent_quad_xf1.e), - .points = ent_quad_xf1.e + ent_quad = xform_mul_quad(ent->sprite_local_xform, quad_from_rect(slice.rect)); + ent_quad = xform_mul_quad(xf, ent_quad); + ent_poly = (struct v2_array) { + .count = ARRAY_COUNT(ent_quad.e), + .points = ent_quad.e }; } { @@ -1036,19 +1024,10 @@ INTERNAL void user_update(void) /* Draw collision shapes */ { - (UNUSED)ent_poly_xf0; - (UNUSED)ent_poly_xf1; f32 thickness = 2; - { - u32 color = RGBA_32_F(1, 0, 0, 0.25); - struct quad quad = xform_mul_quad(G.world_view, ent_quad_xf0); - draw_solid_quad_line(G.viewport_canvas, quad, thickness, color); - } - { - u32 color = RGBA_32_F(0, 1, 0, 0.25); - struct quad quad = xform_mul_quad(G.world_view, ent_quad_xf1); - draw_solid_quad_line(G.viewport_canvas, quad, thickness, color); - } + u32 color = RGBA_32_F(1, 0, 0, 0.25); + struct quad quad = xform_mul_quad(G.world_view, ent_quad); + draw_solid_quad_line(G.viewport_canvas, quad, thickness, color); } /* Draw menkowski */ @@ -1058,8 +1037,8 @@ INTERNAL void user_update(void) f32 thickness = 2; (UNUSED)thickness; - struct v2_array m = menkowski(temp.arena, ent_poly_xf0, e1_poly); - //struct v2_array m = menkowski(temp.arena, ent_poly_xf0, e1_poly, v2_sub(ent->xf1.og, ent->xf0.og)); + struct v2_array m = menkowski(temp.arena, ent_poly, e1_poly); + //struct v2_array m = menkowski(temp.arena, ent_poly, e1_poly, v2_sub(ent->xf1.og, ent->xf0.og)); for (u64 i = 0; i < m.count; ++i) m.points[i] = xform_mul_v2(G.world_view, m.points[i]); draw_solid_poly_line(G.viewport_canvas, m, true, thickness, color); @@ -1071,7 +1050,7 @@ INTERNAL void user_update(void) u32 color = RGBA_32_F(1, 1, 1, 1); f32 radius = 2; - struct v2_array m = cloud(temp.arena, ent_poly_xf0, e1_poly); + struct v2_array m = cloud(temp.arena, ent_poly, e1_poly); for (u64 i = 0; i < m.count; ++i) { struct v2 p = xform_mul_v2(G.world_view, m.points[i]);;