enwauhwduwa
authorhgn <hgodden00@gmail.com>
Thu, 16 Feb 2023 21:13:13 +0000 (21:13 +0000)
committerhgn <hgodden00@gmail.com>
Thu, 16 Feb 2023 21:13:13 +0000 (21:13 +0000)
common.h
player_skate.c
player_skate.h

index a568d188fc73b6be5805a569d3d1811ddb6d191b..3d60978f2da5d64f23145acec6392f96a97041d0 100644 (file)
--- a/common.h
+++ b/common.h
@@ -132,9 +132,9 @@ VG_STATIC float
    k_spring_force          = 300.0f,
    k_spring_dampener       = 5.0f,
 
-   k_grind_spring          = 150.0f,
+   k_grind_spring          = 50.0f,
    k_grind_aligment        = 10.0f,
-   k_grind_dampener        = 10.0f,
+   k_grind_dampener        = 5.0f,
 
    k_board_spring          = 100.0f,
    k_board_dampener        = 40.0f,
index 2e6e07b78aac0359cc6e1022247ffcebb910c853..6b564ef8a11dc6c819052190ecc9981597a0de98 100644 (file)
@@ -596,6 +596,70 @@ VG_STATIC int skate_grind_scansq( player_instance *player, v3f pos,
 
 #endif
 
+VG_STATIC int solve_prediction_for_target( player_instance *player,
+                                           v3f target, float max_angle,
+                                           struct land_prediction *p )
+{
+   /* calculate the exact solution(s) to jump onto that grind spot */
+
+   v3f v0;
+   v3_sub( target, player->rb.co, v0 );
+
+   v3f ax;
+   v3_copy( v0, ax );
+   ax[1] = 0.0f;
+   v3_normalize( ax );
+
+   v2f d = { v3_dot( v0, ax ), v0[1] },
+       v = { v3_dot( player->rb.v, ax ), player->rb.v[1] };
+
+   float a = atan2f( v[1], v[0] ),
+         m = v2_length( v ),
+         root = m*m*m*m - k_gravity*(k_gravity*d[0]*d[0] + 2.0f*d[1]*m*m);
+
+   if( root > 0.0f )
+   {
+      root = sqrtf( root );
+      float a0 = atanf( (m*m + root) / (k_gravity * d[0]) ),
+            a1 = atanf( (m*m - root) / (k_gravity * d[0]) );
+
+      if( fabsf(a0-a) > fabsf(a1-a) )
+         a0 = a1;
+
+      if( fabsf(a0-a) > max_angle )
+         return 0;
+
+      /* TODO: sweep the path before chosing the smallest dist */
+      /* TODO: Jump in normal direction not to_world[1] */
+      /* TODO: Max Y angle */
+
+      p->log_length = 0;
+      p->land_dist = 0.0f;
+      v3_zero( p->apex );
+      p->type = k_prediction_grind;
+
+      v3_muls( ax, cosf( a0 ) * m, p->v );
+      p->v[1] += sinf( a0 ) * m;
+      p->land_dist = d[0] / (cosf(a0)*m);
+
+      /* add a trace */
+      for( int i=0; i<=20; i++ )
+      {
+         float t = (float)i * (1.0f/20.0f) * p->land_dist;
+
+         v3f p0;
+         v3_muls( p->v, t, p0 );
+         p0[1] += -0.5f * k_gravity * t*t;
+
+         v3_add( player->rb.co, p0, p->log[ p->log_length ++ ] );
+      }
+
+      return 1;
+   }
+   else
+      return 0;
+}
+
 VG_STATIC 
 void player__approximate_best_trajectory( player_instance *player )
 {
@@ -682,15 +746,27 @@ void player__approximate_best_trajectory( player_instance *player )
          int idx = spherecast_world( co0, co1, k_board_radius, &t1, n );
          if( idx != -1 )
          {
+            v3f co;
+            v3_lerp( co0, co1, t1, co );
+            v3_copy( co, p->log[ p->log_length ++ ] ); 
+
             v3_copy( n, p->n );
-            v3_lerp( co0, co1, t1, p->log[ p->log_length ++ ] ); 
             p->type = k_prediction_land;
 
             v3f ve;
             v3_copy( launch_v, ve );
             ve[1] -= k_gravity * t;
-            p->score = -v3_dot( ve, n );
+
+            struct grind_info replace_grind;
+            if( skate_grind_scansq( co, ve, 0.3f, &replace_grind ) )
+            {
+               v3_copy( replace_grind.n, p->n );
+               p->type = k_prediction_grind;
+            }
+
+            p->score = -v3_dot( ve, p->n );
             p->land_dist = t + k_trace_delta * t1;
+
             break;
          }
 
@@ -706,72 +782,24 @@ void player__approximate_best_trajectory( player_instance *player )
 
    if( grind_located )
    {
-      v3f v0;
-      v3_sub( grind.co, player->rb.co, v0 );
-
-      v3f ax;
-      v3_copy( v0, ax );
-      ax[1] = 0.0f;
-      v3_normalize( ax );
-
-      v2f d = { v3_dot( v0, ax ), v0[1] },
-          v = { v3_dot( player->rb.v, ax ), player->rb.v[1] };
+      /* calculate the exact solution(s) to jump onto that grind spot */
+      struct land_prediction *p = &s->predictions[ s->prediction_count ];
 
-      float a = atan2f( v[1], v[0] ),
-            m = v2_length( v ),
-
-            root = m*m*m*m - k_gravity*(k_gravity*d[0]*d[0] + 2.0f*d[1]*m*m);
-
-      if( root > 0.0f )
+      if( solve_prediction_for_target( player, grind.co, 0.125f*VG_PIf, p ) )
       {
-         root = sqrtf( root );
-         float a0 = atanf( (m*m + root) / (k_gravity * d[0]) ),
-               a1 = atanf( (m*m - root) / (k_gravity * d[0]) );
-
-         if( fabsf(a0-a) < fabsf(a1-a) )
-            a = a0;
-         else
-            a = a1;
-         /* TODO: sweep the path before chosing the smallest dist */
-         /* TODO: Jump in normal direction not to_world[1] */
-         /* TODO: Grind require manual be pulled in correct direction */
-
-         struct land_prediction *p = &s->predictions[ s->prediction_count ++ ];
-
-         p->log_length = 0;
-         p->land_dist = 0.0f;
-         v3_zero( p->apex );
-         p->type = k_prediction_grind;
-
-         v3_muls( ax, cosf( a ) * m, p->v );
-         p->v[1] += sinf( a ) * m;
-         p->land_dist = d[0] / (cosf(a)*m);
-
          v3_copy( grind.n, p->n );
 
-         /* add a trace */
-         for( int i=0; i<=20; i++ )
-         {
-            float t = (float)i * (1.0f/20.0f) * p->land_dist;
-
-            v3f p0;
-            v3_muls( p->v, t, p0 );
-            p0[1] += -0.5f * k_gravity * t*t;
-
-            v3_add( player->rb.co, p0, p->log[ p->log_length ++ ] );
-         }
-
          /* determine score */
          v3f ve;
          v3_copy( p->v, ve );
          ve[1] -= k_gravity * p->land_dist;
          p->score = -v3_dot( ve, grind.n ) * 0.85f;
+
+         s->prediction_count ++;
       }
    }
 
 
-
-
    float score_min =  INFINITY,
          score_max = -INFINITY;
 
@@ -1049,12 +1077,6 @@ VG_STATIC void skate_apply_steering_model( player_instance *player )
       top  = 1.5f;
    }
 
-   else if( s->state.manual_direction )
-   {
-      rate = 35.0f;
-      top  = 1.5f;
-   }
-
    else if( s->state.activity >= k_skate_activity_grind_any )
    {
       rate *= fabsf(steer_scaled);
@@ -1076,6 +1098,12 @@ VG_STATIC void skate_apply_steering_model( player_instance *player )
       v3_normalize( s->grind_vec );
    }
 
+   else if( s->state.manual_direction )
+   {
+      rate = 35.0f;
+      top  = 1.5f;
+   }
+
    float current  = v3_dot( player->rb.to_world[1], player->rb.w ),
          addspeed = (steer_scaled * -top) - current,
          maxaccel = rate * k_rb_delta,
@@ -1687,13 +1715,21 @@ VG_STATIC void skate_grind_decay( player_instance *player,
 }
 
 VG_STATIC void skate_grind_truck_apply( player_instance *player,
-                                        v3f grind_co, struct grind_info *inf,
+                                        float sign, struct grind_info *inf,
                                         float strength )
 {
    struct player_skate *s = &player->_skate;
 
+   /* TODO: Trash compactor this */
+   v3f ra = { 0.0f, -k_board_radius, sign * k_board_length };
+   v3f raw, wsp;
+   m3x3_mulv( player->rb.to_world, ra, raw );
+   v3_add( player->rb.co, raw, wsp );
+
+
+
    v3f delta;
-   v3_sub( inf->co, grind_co, delta );
+   v3_sub( inf->co, wsp, delta );
 
    /* spring force */
    v3_muladds( player->rb.v, delta, k_spring_force*strength*k_rb_delta, 
@@ -1703,10 +1739,9 @@ VG_STATIC void skate_grind_truck_apply( player_instance *player,
    skate_grind_friction( player, inf, strength );
 
    /* yeah yeah yeah yeah */
-   v3f raw, axis;
-   v3_sub( grind_co, player->rb.co, raw );
-   v3_muladds( raw, inf->n, -v3_dot( inf->n, raw ), raw );
-   v3_cross( raw, inf->n, axis );
+   v3f raw_nplane, axis;
+   v3_muladds( raw, inf->n, -v3_dot( inf->n, raw ), raw_nplane );
+   v3_cross( raw_nplane, inf->n, axis );
    v3_normalize( axis );
 
    /* orientation */
@@ -1714,7 +1749,7 @@ VG_STATIC void skate_grind_truck_apply( player_instance *player,
    skate_grind_orient( inf, mtx );
    v3f target_fwd, fwd, up, target_up;
    m3x3_mulv( mtx, s->grind_vec, target_fwd );
-   v3_copy( raw, fwd );
+   v3_copy( raw_nplane, fwd );
    v3_copy( player->rb.to_world[1], up );
    v3_copy( inf->n, target_up );
 
@@ -1725,7 +1760,7 @@ VG_STATIC void skate_grind_truck_apply( player_instance *player,
    v3_normalize( fwd );
 
    float way = player->input_js1v->axis.value *
-                  vg_signf( v3_dot( raw, player->rb.v ) );
+                  vg_signf( v3_dot( raw_nplane, player->rb.v ) );
                
    v4f q;
    q_axis_angle( q, axis, VG_PIf*0.125f * way );
@@ -1750,15 +1785,25 @@ VG_STATIC void skate_grind_truck_apply( player_instance *player,
 
    /* Fake contact */
    struct grind_limit *limit = &s->limits[ s->limit_count ++ ];
-   m4x3_mulv( player->rb.to_local, grind_co, limit->ra );
+   m4x3_mulv( player->rb.to_local, wsp, limit->ra );
    m3x3_mulv( player->rb.to_local, inf->n, limit->n );
    limit->p = 0.0f;
+
+   v3_copy( inf->dir, s->grind_dir );
+}
+
+VG_STATIC void skate_5050_apply( player_instance *player, 
+                                 struct grind_info *inf_front,
+                                 struct grind_info *inf_back )
+{
+   struct player_skate *s = &player->_skate;
+   struct grind_info inf_avg;
 }
 
-VG_STATIC int skate_grind_truck_singular( player_instance *player, float sign )
+VG_STATIC int skate_grind_truck_renew( player_instance *player, float sign,
+                                       struct grind_info *inf )
 {
    struct player_skate *s = &player->_skate;
-   struct grind_info inf;
 
    v3f wheel_co = { 0.0f, 0.0f,            sign * k_board_length },
        grind_co = { 0.0f, -k_board_radius, sign * k_board_length };
@@ -1767,34 +1812,31 @@ VG_STATIC int skate_grind_truck_singular( player_instance *player, float sign )
    m4x3_mulv( player->rb.to_world, grind_co, grind_co );
 
    /* Exit condition: lost grind tracking */
-   if( !skate_grind_scansq( grind_co, player->rb.v, 0.3f, &inf ) )
+   if( !skate_grind_scansq( grind_co, player->rb.v, 0.3f, inf ) )
       return 0;
 
    /* Exit condition: cant see grind target directly */
-   if( !skate_point_visible( wheel_co, inf.co ) )
+   if( !skate_point_visible( wheel_co, inf->co ) )
       return 0;
 
    /* Exit condition: minimum velocity not reached, but allow a bit of error */
-   float dv   = fabsf(v3_dot( player->rb.v, inf.dir )),
+   float dv   = fabsf(v3_dot( player->rb.v, inf->dir )),
          minv = k_grind_axel_min_vel*0.8f;
 
    if( dv < minv )
       return 0;
 
-   if( fabsf(v3_dot( inf.dir, s->grind_dir )) < k_grind_max_edge_angle )
+   if( fabsf(v3_dot( inf->dir, s->grind_dir )) < k_grind_max_edge_angle )
       return 0;
 
-   v3_copy( inf.dir, s->grind_dir );
-
-   float t = vg_clampf( (dv-minv)/(k_grind_axel_min_vel-minv), 0.0f, 1.0f );
-   skate_grind_truck_apply( player, grind_co, &inf, t );
+   v3_copy( inf->dir, s->grind_dir );
    return 1;
 }
 
-VG_STATIC int skate_truck_entry_condition( player_instance *player, float sign )
+VG_STATIC int skate_grind_truck_entry( player_instance *player, float sign,
+                                       struct grind_info *inf )
 {
    struct player_skate *s = &player->_skate;
-   struct grind_info inf;
 
    /* TODO: Trash compactor this */
    v3f ra = { 0.0f, -k_board_radius, sign * k_board_length };
@@ -1803,33 +1845,36 @@ VG_STATIC int skate_truck_entry_condition( player_instance *player, float sign )
    m3x3_mulv( player->rb.to_world, ra, raw );
    v3_add( player->rb.co, raw, wsp );
 
-   if( skate_grind_scansq( wsp, player->rb.v, 0.3, &inf ) )
+   if( skate_grind_scansq( wsp, player->rb.v, 0.3, inf ) )
    {
-      if( fabsf(v3_dot( player->rb.v, inf.dir )) < k_grind_axel_min_vel )
+      if( fabsf(v3_dot( player->rb.v, inf->dir )) < k_grind_axel_min_vel )
          return 0;
 
       /* velocity should be at least 60% aligned */
       v3f pv, axis;
-      v3_cross( inf.n, inf.dir, axis );
-      v3_muladds( player->rb.v, inf.n, -v3_dot( player->rb.v, inf.n ), pv );
+      v3_cross( inf->n, inf->dir, axis );
+      v3_muladds( player->rb.v, inf->n, -v3_dot( player->rb.v, inf->n ), pv );
       
       if( v3_length2( pv ) < 0.0001f )
          return 0;
       v3_normalize( pv );
 
-      if( fabsf(v3_dot( pv, inf.dir )) < k_grind_axel_max_angle )
+      if( fabsf(v3_dot( pv, inf->dir )) < k_grind_axel_max_angle )
+         return 0;
+
+      if( v3_dot( player->rb.v, inf->n ) > 0.5f )
          return 0;
 
+#if 0
       /* check for vertical alignment */
-      if( v3_dot( player->rb.to_world[1], inf.n ) < k_grind_axel_max_vangle )
+      if( v3_dot( player->rb.to_world[1], inf->n ) < k_grind_axel_max_vangle )
          return 0;
-      
-      /* TODO: new condition, opposite wheel MUST be in-air or close to it */
+#endif
       
       v3f local_co, local_dir, local_n;
-      m4x3_mulv( player->rb.to_local, inf.co,  local_co );
-      m3x3_mulv( player->rb.to_local, inf.dir, local_dir );
-      m3x3_mulv( player->rb.to_local, inf.n,   local_n );
+      m4x3_mulv( player->rb.to_local, inf->co,  local_co );
+      m3x3_mulv( player->rb.to_local, inf->dir, local_dir );
+      m3x3_mulv( player->rb.to_local, inf->n,   local_n );
 
       v2f delta = { local_co[0], local_co[2] - k_board_length*sign };
 
@@ -1840,17 +1885,8 @@ VG_STATIC int skate_truck_entry_condition( player_instance *player, float sign )
       v3_add( player->rb.v, rv, rv );
 
       if( (local_co[1] >= truck_height) &&
-          (v2_length2( delta ) <= k_board_radius*k_board_radius) &&
-          (v3_dot( rv, inf.n ) < 0.1f) )
+          (v2_length2( delta ) <= k_board_radius*k_board_radius) )
       {
-         m3x3f mtx;
-         skate_grind_orient( &inf, mtx );
-         m3x3_transpose( mtx, mtx );
-         m3x3_mulv( mtx, raw, s->grind_vec );
-         v3_normalize( s->grind_vec );
-         v3_copy( inf.dir, s->grind_dir );
-
-         skate_grind_truck_apply( player, wsp, &inf, 1.0f );
          return 1;
       }
    }
@@ -1897,31 +1933,30 @@ VG_STATIC void skate_boardslide_apply( player_instance *player,
 
    vg_line_arrow( player->rb.co, dir, 0.5f, VG__GREEN );
    vg_line_arrow( player->rb.co, perp, 0.5f, VG__BLUE );
+
+   v3_copy( inf->dir, s->grind_dir );
 }
 
-VG_STATIC int skate_boardslide_entry_condition( player_instance *player )
+VG_STATIC int skate_boardslide_entry( player_instance *player,
+                                      struct grind_info *inf )
 {
    struct player_skate *s = &player->_skate;
 
-   struct grind_info inf;
    if( skate_grind_scansq( player->rb.co, 
                            player->rb.to_world[0], k_board_length,
-                           &inf ) )
+                           inf ) )
    {
       v3f local_co, local_dir;
-      m4x3_mulv( player->rb.to_local, inf.co, local_co );
-      m3x3_mulv( player->rb.to_local, inf.dir, local_dir );
+      m4x3_mulv( player->rb.to_local, inf->co, local_co );
+      m3x3_mulv( player->rb.to_local, inf->dir, local_dir );
 
       if( (fabsf(local_co[2]) <= k_board_length) &&   /* within wood area */
           (local_co[1] >= 0.0f) &&                    /* at deck level */
           (fabsf(local_dir[0]) >= 0.5f) )             /* perpendicular to us */
       {
-         if( fabsf(v3_dot( player->rb.v, inf.dir )) < k_grind_axel_min_vel )
+         if( fabsf(v3_dot( player->rb.v, inf->dir )) < k_grind_axel_min_vel )
             return 0;
 
-         v3_copy( inf.dir, s->grind_dir );
-
-         skate_boardslide_apply( player, &inf );
          return 1;
       }
    }
@@ -1929,47 +1964,152 @@ VG_STATIC int skate_boardslide_entry_condition( player_instance *player )
    return 0;
 }
 
-VG_STATIC int skate_boardslide_singular( player_instance *player )
+VG_STATIC int skate_boardslide_renew( player_instance *player,
+                                      struct grind_info *inf )
 {
    struct player_skate *s = &player->_skate;
 
-   struct grind_info inf;
    if( !skate_grind_scansq( player->rb.co, 
                             player->rb.to_world[0], k_board_length,
-                            &inf ) )
+                            inf ) )
       return 0;
 
    /* Exit condition: cant see grind target directly */
    v3f vis;
    v3_muladds( player->rb.co, player->rb.to_world[1], 0.2f, vis );
-   if( !skate_point_visible( vis, inf.co ) )
+   if( !skate_point_visible( vis, inf->co ) )
       return 0;
 
    /* Exit condition: minimum velocity not reached, but allow a bit of error 
     * TODO: trash compactor */
-   float dv   = fabsf(v3_dot( player->rb.v, inf.dir )),
+   float dv   = fabsf(v3_dot( player->rb.v, inf->dir )),
          minv = k_grind_axel_min_vel*0.8f;
 
    if( dv < minv )
       return 0;
 
-   if( fabsf(v3_dot( inf.dir, s->grind_dir )) < k_grind_max_edge_angle )
+   if( fabsf(v3_dot( inf->dir, s->grind_dir )) < k_grind_max_edge_angle )
       return 0;
-   v3_copy( inf.dir, s->grind_dir );
 
-   float t = vg_clampf( (dv-minv)/(k_grind_axel_min_vel-minv), 0.0f, 1.0f );
-
-   skate_boardslide_apply( player, &inf );
    return 1;
 }
 
+VG_STATIC void skate_store_grind_vec( player_instance *player,
+                                      struct grind_info *inf )
+{
+   struct player_skate *s = &player->_skate;
+
+   m3x3f mtx;
+   skate_grind_orient( inf, mtx );
+   m3x3_transpose( mtx, mtx );
+
+   v3f raw;
+   v3_sub( inf->co, player->rb.co, raw );
+
+   m3x3_mulv( mtx, raw, s->grind_vec );
+   v3_normalize( s->grind_vec );
+   v3_copy( inf->dir, s->grind_dir );
+}
+
 VG_STATIC enum skate_activity skate_availible_grind( player_instance *player )
 {
    struct player_skate *s = &player->_skate;
 
+   /* debounces this state manager a little bit */
+   if( s->frames_since_activity_change < 10 )
+   {
+      s->frames_since_activity_change ++;
+      return k_skate_activity_undefined;
+   }
+
+   struct grind_info inf_back50,
+                     inf_front50,
+                     inf_slide;
+
+   int res_back50  = 0,
+       res_front50 = 0,
+       res_slide   = 0;
+
    if( s->state.activity == k_skate_activity_grind_boardslide )
    {
-      int result = skate_boardslide_singular( player );
+      res_slide = skate_boardslide_renew( player, &inf_slide );
+   }
+   else if( s->state.activity == k_skate_activity_grind_back50 )
+   {
+      res_back50  = skate_grind_truck_renew( player,  1.0f, &inf_back50 );
+      res_front50 = skate_grind_truck_entry( player, -1.0f, &inf_front50 );
+   }
+   else if( s->state.activity == k_skate_activity_grind_front50 )
+   {
+      res_front50 = skate_grind_truck_renew( player, -1.0f, &inf_front50 );
+      res_back50  = skate_grind_truck_entry( player,  1.0f, &inf_back50 );
+   }
+   else if( s->state.activity == k_skate_activity_grind_5050 )
+   {
+      res_front50 = skate_grind_truck_renew( player, -1.0f, &inf_front50 );
+      res_back50  = skate_grind_truck_entry( player,  1.0f, &inf_back50 );
+   }
+   else
+   {
+      res_slide   = skate_boardslide_entry( player, &inf_slide );
+      res_back50  = skate_grind_truck_entry( player,  1.0f, &inf_back50 );
+      res_front50 = skate_grind_truck_entry( player, -1.0f, &inf_front50 );
+
+      if( res_back50 != res_front50 )
+      {
+         int wants_to_do_that = fabsf(player->input_js1v->axis.value) >= 0.25f;
+
+         res_back50  &= wants_to_do_that;
+         res_front50 &= wants_to_do_that;
+      }
+   }
+
+   const enum skate_activity table[] =
+   {                                      /* slide | back | front */
+      k_skate_activity_undefined,         /* 0       0      0     */
+      k_skate_activity_grind_front50,     /* 0       0      1     */
+      k_skate_activity_grind_back50,      /* 0       1      0     */
+      k_skate_activity_grind_5050,        /* 0       1      1     */
+
+      /* slide has priority always */
+      k_skate_activity_grind_boardslide,  /* 1       0      0     */
+      k_skate_activity_grind_boardslide,  /* 1       0      1     */
+      k_skate_activity_grind_boardslide,  /* 1       1      0     */
+      k_skate_activity_grind_boardslide,  /* 1       1      1     */
+   }
+   , new_activity = table[ res_slide << 2 | res_back50 << 1 | res_front50 ];
+
+   if(      new_activity == k_skate_activity_undefined )
+   {
+      s->frames_since_activity_change = 0;
+   }
+   else if( new_activity == k_skate_activity_grind_boardslide )
+   {
+      skate_boardslide_apply( player, &inf_slide );
+   }
+   else if( new_activity == k_skate_activity_grind_back50 )
+   {
+      if( s->state.activity != k_skate_activity_grind_back50 )
+         skate_store_grind_vec( player, &inf_back50 );
+
+      skate_grind_truck_apply( player,  1.0f, &inf_back50, 1.0f );
+   }
+   else if( new_activity == k_skate_activity_grind_front50 )
+   {
+      if( s->state.activity != k_skate_activity_grind_front50 )
+         skate_store_grind_vec( player, &inf_front50 );
+
+      skate_grind_truck_apply( player, -1.0f, &inf_front50, 1.0f );
+   }
+   else if( new_activity == k_skate_activity_grind_5050 )
+      skate_5050_apply( player, &inf_front50, &inf_back50 );
+
+   return new_activity;
+
+#if 0
+   if( s->state.activity == k_skate_activity_grind_boardslide )
+   {
+      int res_slide = skate_boardslide_singular( player );
 
       const enum skate_activity table[] =
       {
@@ -2036,6 +2176,7 @@ VG_STATIC enum skate_activity skate_availible_grind( player_instance *player )
    }
 
    return 0;
+#endif
 }
 
 VG_STATIC void player__skate_update( player_instance *player )
@@ -2049,7 +2190,6 @@ VG_STATIC void player__skate_update( player_instance *player )
       v3f   pos;
       float radius;
 
-      int   apply_angular;
       u32   colour;
 
       enum  board_collider_state
@@ -2065,27 +2205,13 @@ VG_STATIC void player__skate_update( player_instance *player )
       { 
          { 0.0f, 0.0f,    -k_board_length }, 
          .radius = k_board_radius,
-         .apply_angular = 1,
          .colour = VG__RED
       },
       { 
          { 0.0f, 0.0f,     k_board_length }, 
          .radius = k_board_radius,
-         .apply_angular = 1,
          .colour = VG__GREEN
-      },
-      { 
-         { 0.0f, 0.2f,    -k_board_length - k_board_end_radius }, 
-         .radius = k_board_end_radius,
-         .apply_angular = 0,
-         .colour = VG__YELOW
-      },
-      {  
-         { 0.0f, 0.2f,     k_board_length + k_board_end_radius },
-         .radius = k_board_end_radius,
-         .apply_angular = 0,
-         .colour = VG__YELOW
-      },
+      }
    };
 
    const int k_wheel_count = 2;
@@ -2190,6 +2316,13 @@ begin_collision:;
       q_mul( rotation, player->rb.q, future_q );
       q_normalize( future_q );
    }
+   else
+      v4_copy( player->rb.q, future_q );
+
+   v3f future_cg, current_cg, cg_offset;
+   q_mulv( player->rb.q, s->weight_distribution, current_cg );
+   q_mulv( future_q, s->weight_distribution, future_cg );
+   v3_sub( future_cg, current_cg, cg_offset );
 
    /* calculate the minimum time we can move */
    float max_time = s->substep;
@@ -2199,9 +2332,11 @@ begin_collision:;
       if( wheels[i].state == k_collider_state_disabled )
          continue;
 
-      v3f current, future;
+      v3f current, future, r_cg;
+      
       q_mulv( future_q, wheels[i].pos, future );
       v3_add( future, future_co, future );
+      v3_add( cg_offset, future, future );
 
       q_mulv( player->rb.q, wheels[i].pos, current );
       v3_add( current, player->rb.co, current );
@@ -2234,6 +2369,11 @@ begin_collision:;
       v3_divs( axis, mag, axis );
       q_axis_angle( rotation, axis, mag*s->substep_delta );
       q_mul( rotation, player->rb.q, player->rb.q );
+      q_normalize( player->rb.q );
+
+      q_mulv( player->rb.q, s->weight_distribution, future_cg );
+      v3_sub( current_cg, future_cg, cg_offset );
+      v3_add( player->rb.co, cg_offset, player->rb.co );
    }
 
    rb_update_transform( &player->rb );
@@ -2264,9 +2404,6 @@ begin_collision:;
 
    /*
     * Phase 1: Regular collision detection
-    *          TODO: Me might want to automatically add contacts from CCD, 
-    *                since at high angular velocities, theres a small change
-    *                that discreet detection will miss.
     * --------------------------------------------------------------------------
     */
 
@@ -2287,20 +2424,6 @@ begin_collision:;
       if( l )
          wheels[i].state = k_collider_state_colliding;
 
-      /* for non-angular contacts we just want Y. contact positions are
-       * snapped to the local xz plane */
-      if( !wheels[i].apply_angular )
-      {
-         for( int j=0; j<l; j++ )
-         {
-            v3f ra;
-            v3_sub( man[j].co, player->rb.co, ra );
-
-            float dy = v3_dot( player->rb.to_world[1], ra );
-            v3_muladds( man[j].co, player->rb.to_world[1], -dy, man[j].co );
-         }
-      }
-
       manifold_len += l;
    }
 
@@ -2345,6 +2468,11 @@ begin_collision:;
     * --------------------------------------------------------------------------
     */
 
+
+   v3f world_cog;
+   m4x3_mulv( player->rb.to_world, s->weight_distribution, world_cog );
+   vg_line_pt3( world_cog, 0.02f, VG__BLACK );
+
    for( int i=0; i<manifold_len; i ++ )
    {
       rb_prepare_contact( &manifold[i], s->substep_delta );
@@ -2376,10 +2504,6 @@ begin_collision:;
    m3x3_mul( iI, player->rb.to_local, iIw );
    m3x3_mul( player->rb.to_world, iIw, iIw );
 
-   v3f world_cog;
-   m4x3_mulv( player->rb.to_world, s->weight_distribution, world_cog );
-   vg_line_pt3( world_cog, 0.02f, VG__BLACK );
-
    for( int j=0; j<10; j++ )
    {
       for( int i=0; i<manifold_len; i++ )
index e54754e570f5bf61fda3bb6a01066fbf6868c36a..c26e8459f08858b5b25d950fbf1281909a2852d1 100644 (file)
@@ -139,6 +139,8 @@ struct player_skate
        grind_vec,
        grind_dir;
 
+   u32 frames_since_activity_change;
+
    float grind_strength;
 
    struct grind_limit