From 73b7fef7685a5ca6fd5a5bf547a6e5ccd5a3b735 Mon Sep 17 00:00:00 2001 From: jacob Date: Sat, 12 Oct 2024 00:37:15 -0500 Subject: [PATCH] more fixed up capsule collision. remove transform matrix skewing --- res/graphics/box_rounded.ase | 3 + src/collider.c | 153 +++++++++++++++++++++-------------- src/game.c | 56 ++++++------- src/math.h | 19 +---- src/user.c | 25 +++--- 5 files changed, 136 insertions(+), 120 deletions(-) create mode 100644 res/graphics/box_rounded.ase diff --git a/res/graphics/box_rounded.ase b/res/graphics/box_rounded.ase new file mode 100644 index 00000000..a40658f3 --- /dev/null +++ b/res/graphics/box_rounded.ase @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1fd40d4f1716fac09d9a84ff3e1e44e4d4de461ab0fc9c83229a55de9d2bf66a +size 1168 diff --git a/src/collider.c b/src/collider.c index ade8d335..764c0380 100644 --- a/src/collider.c +++ b/src/collider.c @@ -24,58 +24,6 @@ INTERNAL void _dbgbreakable(void) struct v2 collider_support_point(struct collider_shape *a, struct xform xf, struct v2 dir) { -#if 0 - struct v2 *points = a->points; - u32 count = a->count; - f32 radius = a->radius; - - /* TODO: Could probably binary search for largest dot since shape is convex */ - struct v2 furthest = ZI; - f32 furthest_dot = -F32_INFINITY; - for (u32 i = 0; i < count; ++i) { - struct v2 p = xform_mul_v2(xf, points[i]); - f32 dot = v2_dot(dir, p); - if (dot > furthest_dot) { - furthest = p; - furthest_dot = dot; - } - } - - if (radius > 0.0) { - dir = v2_mul_v2(v2_with_len(dir, radius), xform_get_scale(xf)); - furthest = v2_add(furthest, dir); - } - - return furthest; -#elif 0 - struct v2 *points = a->points; - u32 count = a->count; - f32 radius = a->radius; - - /* TODO: Could probably binary search for largest dot since shape is convex */ - struct xform inv = xform_invert(xf); - dir = xform_basis_mul_v2(inv, dir); - - struct v2 furthest = ZI; - f32 furthest_dot = -F32_INFINITY; - for (u32 i = 0; i < count; ++i) { - struct v2 p = points[i]; - f32 dot = v2_dot(dir, p); - if (dot > furthest_dot) { - furthest = p; - furthest_dot = dot; - } - } - - if (radius > 0.0) { - dir = v2_with_len(dir, radius); - furthest = v2_add(furthest, dir); - } - - furthest = xform_mul_v2(xf, furthest); - - return furthest; -#else struct v2 *points = a->points; u32 count = a->count; f32 radius = a->radius; @@ -102,7 +50,6 @@ struct v2 collider_support_point(struct collider_shape *a, struct xform xf, stru furthest = xform_mul_v2(xf, furthest); return furthest; -#endif } INTERNAL u32 collider_support_point_index(struct collider_shape *a, struct xform xf, struct v2 dir) @@ -149,8 +96,8 @@ struct collider_collision_points_result collider_collision_points(struct collide /* TODO: Parameterize */ /* How close can non-overlapping shapes be before collision is considered */ //const f32 tolerance = 0.f; - const f32 tolerance = 0.05f; //const f32 tolerance = 0.05f; + const f32 tolerance = 0.005f; /* NOTE: Should always be less than tolerance, since colliding=true if origin is within this distance. */ const f32 min_unique_pt_dist_sq = 0.0001f * 0.0001f; @@ -468,7 +415,7 @@ struct collider_collision_points_result collider_collision_points(struct collide DBGSTEP; { - const f32 wedge_epsilon = 0.001f; + const f32 wedge_epsilon = 0.05f; //const f32 wedge_epsilon = 0.1f; /* shape0 a -> b winding = clockwise */ @@ -610,20 +557,87 @@ struct collider_collision_points_result collider_collision_points(struct collide struct v2 vab1 = v2_sub(b1, a1); { - struct v2 va0a1 = v2_sub(a1, a0); - struct v2 vb0b1 = v2_sub(b1, b0); f32 vab0_wedge_normal = v2_wedge(vab0, normal); f32 vab1_wedge_normal = v2_wedge(vab1, normal); + + b32 collapse0 = math_fabs(vab0_wedge_normal) < wedge_epsilon; + b32 collapse1 = math_fabs(vab1_wedge_normal) < wedge_epsilon; + + if (collapse0) { + if (v2_dot(b0, normal) >= v2_dot(a0, normal)) { + a0 = b0; + a0t = 1; + b0t = 0; + } else { + b0 = a0; + a0t = 0; + b0t = 1; + } + vab0 = V2(0, 0); + } + + if (collapse1) { + if (v2_dot(b1, normal) < v2_dot(a1, normal)) { + a1 = b1; + a1t = 1; + b1t = 0; + } else { + b1 = a1; + a1t = 0; + b1t = 1; + } + vab1 = V2(0, 0); + } + + struct v2 va0a1 = v2_sub(a1, a0); + struct v2 vb0b1 = v2_sub(b1, b0); f32 va0a1_wedge_normal = v2_wedge(va0a1, normal); f32 vb0b1_wedge_normal = v2_wedge(vb0b1, normal); - if (math_fabs(vab0_wedge_normal) > 0.01f) { + +#if 0 + if (math_fabs(vab0_wedge_normal) > 0.1f) { f32 w = 1 / vab0_wedge_normal; a0t = clamp_f32(va0a1_wedge_normal * w, 0, 1); b0t = clamp_f32(vb0b1_wedge_normal * -w, 0, 1); } else { DEBUGBREAKABLE; + if (v2_dot(b0, normal) >= v2_dot(a0, normal)) { + a0t = 1; + b0t = 0; + } else { + a0t = 0; + b0t = 1; + } + } + + if (math_fabs(vab1_wedge_normal) > 0.1f) { + f32 w = 1 / vab1_wedge_normal; + a1t = clamp_f32(-va0a1_wedge_normal * w, 0, 1); + b1t = clamp_f32(-vb0b1_wedge_normal * -w, 0, 1); + } else { + if (v2_dot(b1, normal) < v2_dot(a1, normal)) { + a1t = 1; + b1t = 0; + } else { + a1t = 0; + b1t = 1; + } + } +#elif 0 + if (math_fabs(vab0_wedge_normal) > 0.01f) { + f32 w = 1 / vab0_wedge_normal; + a0t = clamp_f32(va0a1_wedge_normal * w, 0, 1); + b0t = clamp_f32(vb0b1_wedge_normal * -w, 0, 1); + } else { + if (v2_dot(b0, normal) >= v2_dot(a0, normal)) { + a0t = 1; + b0t = 0; + } else { + a0t = 0; + b0t = 1; + } } if (math_fabs(vab1_wedge_normal) > 0.01f) { @@ -631,8 +645,27 @@ struct collider_collision_points_result collider_collision_points(struct collide a1t = clamp_f32(-va0a1_wedge_normal * w, 0, 1); b1t = clamp_f32(-vb0b1_wedge_normal * -w, 0, 1); } else { - DEBUGBREAKABLE; + if (v2_dot(b1, normal) < v2_dot(a1, normal)) { + a1t = 1; + b1t = 0; + } else { + a1t = 0; + b1t = 1; + } } +#else + if (!collapse0) { + f32 w = 1 / vab0_wedge_normal; + a0t = clamp_f32(va0a1_wedge_normal * w, 0, 1); + b0t = clamp_f32(vb0b1_wedge_normal * -w, 0, 1); + } + + if (!collapse1) { + f32 w = 1 / vab1_wedge_normal; + a1t = clamp_f32(-va0a1_wedge_normal * w, 0, 1); + b1t = clamp_f32(-vb0b1_wedge_normal * -w, 0, 1); + } +#endif } struct v2 a0_clipped = v2_add(a0, v2_mul(vab0, a0t)); @@ -675,7 +708,7 @@ struct collider_collision_points_result collider_collision_points(struct collide point->point = contact_b; } -#if 0 +#if 1 res.a0 = a0_clipped; res.a1 = a1_clipped; res.b0 = b0_clipped; diff --git a/src/game.c b/src/game.c index 725be8e0..7d6f6ef1 100644 --- a/src/game.c +++ b/src/game.c @@ -136,19 +136,20 @@ INTERNAL void spawn_test_entities(f32 offset) struct entity *e = entity_alloc(root); -#if 1 //struct v2 pos = V2(0.25, -10); //struct v2 pos = V2(0.25, -7); //struct v2 pos = V2(0.25, -5.27); - struct v2 pos = V2(0.5, -1); + struct v2 pos = V2(0.5, -2); //struct v2 pos = V2(1.0295, -1); pos = v2_add(pos, V2(0, offset)); pos = v2_add(pos, V2(0, offset_all)); //struct v2 size = V2(1, 1); - //struct v2 size = V2(0.5, 0.5); - struct v2 size = V2(1.0, 0.5); + struct v2 size = V2(0.5, 0.5); + //struct v2 size = V2(3.0, 0.5); + //struct v2 size = V2(1.0, 1.0); + //struct v2 size = V2(1.5, 1.5); //f32 r = PI; //f32 r = PI / 4; //f32 r = PI / 3; @@ -156,22 +157,17 @@ INTERNAL void spawn_test_entities(f32 offset) //f32 r = PI / 2; //f32 r = PI; f32 r = 0; - //f32 skew = PI / 4; - //f32 skew = 0.9f; - f32 skew = 0; struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size); - xf = xform_skewed_to(xf, skew); -#else - struct xform xf = { .bx = {0.282509595, -0.412540406}, .by = {0.412528992, 0.282521814}, .og = {3.34883189, -1.35877287} }; -#endif + entity_set_xform(e, xf); //e->sprite = sprite_tag_from_path(STR("res/graphics/tim.ase")); - e->sprite = sprite_tag_from_path(STR("res/graphics/box.ase")); + e->sprite = sprite_tag_from_path(STR("res/graphics/box_rounded.ase")); //e->sprite_span_name = STR("idle.unarmed"); //e->sprite_span_name = STR("idle.one_handed"); e->sprite_span_name = STR("idle.two_handed"); + e->sprite_tint = RGBA_32_F(1, 1, 1, 0.25); entity_enable_prop(e, ENTITY_PROP_PLAYER_CONTROLLED); #if GAME_PHYSICS_ENABLE_GROUND_FRICTION @@ -200,7 +196,6 @@ INTERNAL void spawn_test_entities(f32 offset) { struct entity *e = entity_alloc(root); -#if 1 //struct v2 pos = V2(0.25, -10); //struct v2 pos = V2(0.25, -7); //struct v2 pos = V2(0.25, -5.27); @@ -217,15 +212,9 @@ INTERNAL void spawn_test_entities(f32 offset) //f32 r = PI / 3; //f32 r = 0.05; //f32 r = PI / 2; - //f32 r = 0; - //f32 skew = PI / 4; - f32 skew = 0; + f32 r = 0; struct xform xf = XFORM_TRS(.t = pos, .r = r, .s = size); - xf = xform_skewed_to(xf, skew); -#else - struct xform xf = { .bx = {0.256749988, 0.429049402}, .by = {-0.429063231, 0.256720454}, .og = {2.91935277, -0.965838134} }; -#endif entity_set_xform(e, xf); @@ -255,6 +244,7 @@ INTERNAL void spawn_test_entities(f32 offset) #endif /* Weapon */ +#if 1 if (player_ent->valid) { #if 0 struct v2 pos = V2(1, 0); @@ -275,6 +265,7 @@ INTERNAL void spawn_test_entities(f32 offset) player_ent->equipped = e->handle; } +#endif /* Box */ #if GAME_SPAWN_BOX @@ -288,6 +279,7 @@ INTERNAL void spawn_test_entities(f32 offset) #else //struct v2 size = V2(5000, 1); struct v2 size = V2(50, 1); + //struct v2 size = V2(1, 1); #endif //f32 rot = PI / 4; f32 rot = 0; @@ -1077,21 +1069,29 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) /* Update collider */ { + struct xform cxf = ent->sprite_local_xform; + + if (entity_has_prop(ent, ENTITY_PROP_TEST)) { + f32 scale = 0.5; + cxf = xform_scaled(cxf, V2(scale, scale)); + } + struct sprite_sheet_slice slice = sprite_sheet_get_slice(sheet, STR("shape"), ent->animation_frame); - ent->local_collider = collider_from_quad(xform_mul_quad(ent->sprite_local_xform, quad_from_rect(slice.rect))); + ent->local_collider = collider_from_quad(xform_mul_quad(cxf, quad_from_rect(slice.rect))); #if 1 if (entity_has_prop(ent, ENTITY_PROP_TEST)) { + //if ((true)) { #if 0 ent->local_collider.points[0] = V2(0, 0); ent->local_collider.count = 1; ent->local_collider.radius = 0.5; -#elif 0 +#elif 1 ent->local_collider.points[0] = V2(0, 0.5); ent->local_collider.points[1] = V2(0, -0.5); ent->local_collider.count = 2; ent->local_collider.radius = 0.25; -#elif 1 +#elif 0 #if 1 /* "Bad" winding order */ ent->local_collider.points[0] = V2(-0.5, 0.5); @@ -1106,7 +1106,9 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) ent->local_collider.radius = 0.25; //ent->local_collider.radius = math_fabs(math_sin(G.tick.time) / 3); #else - ent->local_collider.radius = 0.5; + //ent->local_collider.radius = 0.5; + ent->local_collider.radius = 0.25; + //ent->local_collider.radius = 0.; #endif } #endif @@ -1220,7 +1222,6 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) struct v2 og = v2_mul(V2(math_cos(t), math_sin(t)), 3); f32 r = t * 3; struct v2 s = V2(1 + (math_fabs(math_sin(t * 5)) * 3), 1); - f32 skew = t * PI / 10; (UNUSED)og; (UNUSED)r; (UNUSED)s; @@ -1228,29 +1229,24 @@ INTERNAL void game_update(struct game_cmd_array game_cmds) og = v2_add(og, ent->test_start_local_xform.og); r += xform_get_rotation(ent->test_start_local_xform); s = v2_add(s, xform_get_scale(ent->test_start_local_xform)); - skew += xform_get_skew(ent->test_start_local_xform); struct xform xf = entity_get_local_xform(ent); xf.og = og; xf = xform_rotated_to(xf, r); xf = xform_scaled_to(xf, s); - xf = xform_skewed_to(xf, skew); entity_set_local_xform(ent, xf); #else f32 t = (f32)time; struct v2 og = v2_mul(V2(math_cos(t), math_sin(t)), 3); f32 rot = t * PI / 3; struct v2 scale = V2(1 + (math_fabs(math_sin(t * 5)) * 3), 1); - f32 skew = t * PI / 10; (UNUSED)og; (UNUSED)rot; (UNUSED)scale; - (UNUSED)skew; struct xform xf = entity_get_local_xform(ent); //xf = xform_rotated_to(xf, rot); //xf = xform_scaled_to(xf, scale); - xf = xform_skewed_to(xf, skew); entity_set_local_xform(ent, xf); #endif } diff --git a/src/math.h b/src/math.h index 9c2a8a85..f01f99af 100644 --- a/src/math.h +++ b/src/math.h @@ -874,8 +874,6 @@ INLINE struct v2 xform_mul_v2(struct xform xf, struct v2 v); INLINE struct xform xform_scaled_to(struct xform xf, struct v2 s); INLINE f32 xform_get_determinant(struct xform xf); INLINE struct v2 xform_get_scale(struct xform xf); -INLINE f32 xform_get_skew(struct xform xf); -INLINE struct xform xform_skewed_to(struct xform xf, f32 s); INLINE f32 xform_get_rotation(struct xform xf); INLINE b32 xform_eq(struct xform xf1, struct xform xf2) @@ -930,14 +928,13 @@ INLINE struct xform xform_scaled(struct xform xf, struct v2 v) INLINE struct xform xform_rotated_to(struct xform xf, f32 r) { + /* TODO: Maintain skew/shear? */ struct v2 scale = xform_get_scale(xf); - f32 skew = xform_get_skew(xf); f32 c = math_cos(r); f32 s = math_sin(r); xf.bx = V2(c, s); xf.by = V2(-s, c); xf = xform_scaled_to(xf, scale); - xf = xform_skewed_to(xf, skew); return xf; } @@ -979,12 +976,10 @@ INLINE struct xform xform_lerp(struct xform a, struct xform b, f32 t) struct v2 og = v2_lerp(a.og, b.og, t); f32 rot = math_lerp_angle(xform_get_rotation(a), xform_get_rotation(b), t); struct v2 scale = v2_lerp(xform_get_scale(a), xform_get_scale(b), t); - f32 skew = math_lerp_angle(xform_get_skew(a), xform_get_skew(b), t); struct xform res = xform_from_pos(og); res = xform_rotated(res, rot); res = xform_scaled(res, scale); - res = xform_skewed_to(res, skew); return res; } @@ -1061,18 +1056,6 @@ INLINE f32 xform_get_determinant(struct xform xf) return v2_wedge(xf.bx, xf.by); } -INLINE f32 xform_get_skew(struct xform xf) -{ - return v2_angle_from_dirs(v2_norm(xf.bx), v2_norm(xf.by)) - PI / 2; -} - -INLINE struct xform xform_skewed_to(struct xform xf, f32 s) -{ - f32 angle = v2_angle(xf.bx) + s + (PI / 2); - xf.by = v2_mul(v2_from_angle(angle), v2_len(xf.by)); - return xf; -} - INLINE struct v2 xform_get_right(struct xform xf) { return xf.bx; diff --git a/src/user.c b/src/user.c index c013420f..97c14ba5 100644 --- a/src/user.c +++ b/src/user.c @@ -362,13 +362,10 @@ INTERNAL void pubilsh_game_cmds(struct game_cmd_list *list) * ========================== */ /* TODO: remove this (testing) */ -INTERNAL void debug_draw_xform(struct xform xf) +INTERNAL void debug_draw_xform(struct xform xf, u32 color_x, u32 color_y) { f32 thickness = 2.f; f32 arrowhead_len = 15.f; - u32 color = RGBA_32_F(0, 1, 1, 0.3); - u32 color_x = RGBA_32_F(1, 0, 0, 0.3); - u32 color_y = RGBA_32_F(0, 1, 0, 0.3); struct v2 pos = xform_mul_v2(G.world_view, xf.og); struct v2 x_ray = xform_basis_mul_v2(G.world_view, xform_get_right(xf)); @@ -378,12 +375,13 @@ INTERNAL void debug_draw_xform(struct xform xf) x_ray = v2_mul(x_ray, ray_scale); y_ray = v2_mul(y_ray, ray_scale); - struct quad quad = quad_from_rect(RECT(0, 0, 1, -1)); - quad = xform_mul_quad(xf, quad_scale(quad, 0.075f)); - draw_solid_arrow_ray(G.viewport_canvas, pos, x_ray, thickness, arrowhead_len, color_x); draw_solid_arrow_ray(G.viewport_canvas, pos, y_ray, thickness, arrowhead_len, color_y); - draw_solid_quad(G.viewport_canvas, quad, color); + + //u32 color_quad = RGBA_32_F(0, 1, 1, 0.3); + //struct quad quad = quad_from_rect(RECT(0, 0, 1, -1)); + //quad = xform_mul_quad(xf, quad_scale(quad, 0.075f)); + //draw_solid_quad(G.viewport_canvas, quad, color); } /* TODO: remove this (testing) */ @@ -835,8 +833,8 @@ INTERNAL void user_update(void) struct xform parent_xf = entity_get_xform(parent); b32 skip_debug_draw = !G.debug_camera && ent == active_camera; - //b32 skip_debug_draw_transform = entity_has_prop(ent, ENTITY_PROP_CAMERA); - b32 skip_debug_draw_transform = true; + b32 skip_debug_draw_transform = entity_has_prop(ent, ENTITY_PROP_CAMERA); + //b32 skip_debug_draw_transform = true; struct xform sprite_xform = xf; @@ -870,7 +868,8 @@ INTERNAL void user_update(void) #endif /* Draw sprite */ - if (!sprite_tag_is_nil(sprite) && ((false))) { + if ((false)) { + //if (!sprite_tag_is_nil(sprite)) { /* Calculate sprite xform */ sprite_xform = xform_mul(xf, ent->sprite_local_xform); @@ -934,7 +933,9 @@ INTERNAL void user_update(void) } if (!skip_debug_draw_transform) { - debug_draw_xform(xf); + u32 color_x = RGBA_32_F(1, 0, 0, 0.3); + u32 color_y = RGBA_32_F(0, 1, 0, 0.3); + debug_draw_xform(xf, color_x, color_y); } #if 0