From 0de25596501d8aba67b08c92bdab417d6947cd13 Mon Sep 17 00:00:00 2001 From: hgn Date: Thu, 16 Feb 2023 21:13:13 +0000 Subject: [PATCH] enwauhwduwa --- common.h | 4 +- player_skate.c | 446 +++++++++++++++++++++++++++++++------------------ player_skate.h | 2 + 3 files changed, 289 insertions(+), 163 deletions(-) diff --git a/common.h b/common.h index a568d18..3d60978 100644 --- 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, diff --git a/player_skate.c b/player_skate.c index 2e6e07b..6b564ef 100644 --- a/player_skate.c +++ b/player_skate.c @@ -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; jrb.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; isubstep_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