a-game

2D platformer written from scratch.
git clone git://git.amin.space/a-game.git
Log | Files | Refs | README | LICENSE

collision.c (2062B)


      1 struct WallCollision
      2 {
      3     bool collision_occurred;
      4     f32 distance_scale_factor;
      5 };
      6 
      7 internal struct WallCollision get_wall_collision(v2 entity_p_initial, v2 entity_p_final, segment wall, v2 wall_normal)
      8 
      9 {
     10     struct WallCollision result = {0};
     11     result.collision_occurred = false;
     12 
     13     assert(math_v2_le(wall.min, wall.max));
     14 
     15     bool wall_is_horizontal = wall.min.y == wall.max.y;
     16     bool wall_is_vertical = wall.min.x == wall.max.x;
     17     assert(wall_is_horizontal || wall_is_vertical);
     18 
     19     enum VectorAxis wall_axis = AXIS_X;
     20     enum VectorAxis wall_normal_axis = AXIS_Y;
     21     if (wall_is_vertical)
     22     {
     23         wall_axis = AXIS_Y;
     24         wall_normal_axis = AXIS_X;
     25     }
     26 
     27     v2 player_delta = math_v2_s(entity_p_final, entity_p_initial);
     28 
     29     // NOTE(amin): We needn't normalize player_delta here because its magnitude
     30     // becomes irrelevant as the value of cos(theta) nears zero, and we are
     31     // concerned only about the behavior near pi/2 and 3pi/2, where cos(theta)
     32     // is zero. Therefore we simply treat player_delta as if it _were_
     33     // normalized.
     34     f32 cos_theta = math_v2_dot(player_delta, wall_normal);
     35 
     36     bool theta_is_obtuse = cos_theta < 0.0f;
     37     if (theta_is_obtuse)
     38     {
     39         f32 wall_position = wall.min.E[wall_normal_axis];
     40 
     41         // Not to be confused with the anime about street racing
     42         f32 initial_d = wall_position - entity_p_initial.E[wall_normal_axis];
     43 
     44         f32 segment_scale_factor = initial_d / player_delta.E[wall_normal_axis];
     45         v2 collision_point = math_v2_a(entity_p_initial, math_v2f_m(player_delta, segment_scale_factor));
     46 
     47         if (math_in_interval_open(segment_scale_factor, 0.0f, 1.0f))
     48         {
     49             if (math_in_interval_open(
     50                     collision_point.E[wall_axis],
     51                     wall.min.E[wall_axis],
     52                     wall.max.E[wall_axis]))
     53             {
     54                 result.collision_occurred = true;
     55                 result.distance_scale_factor = math_max(0.0f, segment_scale_factor);
     56             }
     57         }
     58     }
     59 
     60     return result;
     61 }