#endif
-/*
- *
- * Prediction system
- *
- *
- */
-
-/*
- * Trace a path given a velocity rotation.
- *
- * TODO: this MIGHT be worth doing RK4 on the gravity field.
- */
-VG_STATIC void skate_score_biased_path( v3f co, v3f v, m3x3f vr,
- struct land_prediction *prediction )
+VG_STATIC
+void player__approximate_best_trajectory( player_instance *player )
{
- float pstep = VG_TIMESTEP_FIXED * 10.0f;
- float k_bias = 0.96f;
-
- v3f pco, pco1, pv;
- v3_copy( co, pco );
- v3_muls( v, k_bias, pv );
-
- m3x3_mulv( vr, pv, pv );
- v3_muladds( pco, pv, pstep, pco );
-
- struct grind_edge *best_grind = NULL;
- float closest_grind = INFINITY;
+ struct player_skate *s = &player->_skate;
+ float k_trace_delta = k_rb_delta * 10.0f;
- float grind_score = INFINITY,
- air_score = INFINITY,
- time_to_impact = 0.0f;
+ s->state.air_start = vg.time;
+ v3_copy( player->rb.v, s->state.air_init_v );
+ v3_copy( player->rb.co, s->state.air_init_co );
- v3f ground_normal,
- grind_normal;
+ s->prediction_count = 0;
- v3_copy( (v3f){0.0f,1.0f,0.0f}, ground_normal );
- v3_copy( (v3f){0.0f,1.0f,0.0f}, grind_normal );
+ v3f axis;
+ v3_cross( player->rb.v, player->rb.to_world[1], axis );
+ v3_normalize( axis );
- prediction->log_length = 0;
- v3_copy( pco, prediction->apex );
+ /* at high slopes, Y component is low */
+ float angle_begin = -(1.0f-fabsf( player->rb.to_world[1][1] )),
+ angle_end = 1.0f;
- for( int i=0; i<vg_list_size(prediction->log); i++ )
+ for( int m=0;m<=15; m++ )
{
- v3_copy( pco, pco1 );
-
- pv[1] += -k_gravity * pstep;
+ struct land_prediction *p = &s->predictions[ s->prediction_count ++ ];
- m3x3_mulv( vr, pv, pv );
- v3_muladds( pco, pv, pstep, pco );
+ p->log_length = 0;
+ p->land_dist = 0.0f;
+ v3_zero( p->apex );
+ p->type = k_prediction_none;
- if( pco[1] > prediction->apex[1] )
- v3_copy( pco, prediction->apex );
-
- v3f vdir;
+ v3f launch_co, launch_v, co0, co1;
+ v3_copy( player->rb.co, launch_co );
+ v3_copy( player->rb.v, launch_v );
+ v3_copy( launch_co, co0 );
- v3_sub( pco, pco1, vdir );
+ float vt = (float)m * (1.0f/15.0f),
+ ang = vg_lerpf( angle_begin, angle_end, vt ) * 0.15f;
- float l = v3_length( vdir );
- v3_muls( vdir, 1.0f/l, vdir );
+ v4f qbias;
+ q_axis_angle( qbias, axis, ang );
+ q_mulv( qbias, launch_v, launch_v );
+ v3_copy( launch_v, p->v );
-#if 0
- v3f c0, c1;
- struct grind_edge *ge = skate_collect_grind_edge( pco, pco1,
- c0, c1, 0.4f );
-
- if( ge && (v3_dot((v3f){0.0f,1.0f,0.0f},vdir) < -0.2f ) )
+ for( int i=1; i<=50; i++ )
{
- float d2 = v3_dist2( c0, c1 );
- if( d2 < closest_grind )
- {
- closest_grind = d2;
- best_grind = ge;
- grind_score = closest_grind * 0.05f;
- }
- }
-#endif
+ float t = (float)i * k_trace_delta;
- /* TODO: binary search grind once we find it, do not need to
- * recompute scansq, or collision. only distance
- */
+ v3_muls( launch_v, t, co1 );
+ co1[1] += -0.5f * k_gravity * t*t;
+ v3_add( launch_co, co1, co1 );
- v3f closest;
- if( bh_closest_point( world.geo_bh, pco, closest, k_board_length ) != -1 )
- {
- struct grind_info inf;
- if( skate_grind_scansq( closest, vdir, 0.5f, &inf ) )
- {
- float score = -v3_dot( pv, inf.n ) * 0.06f;
+ float t1;
+ v3f n;
- if( (score > 0.0f) && (score < grind_score) )
- {
- grind_score = score;
- }
+ int idx = spherecast_world( co0, co1, k_board_radius, &t1, n );
+ if( idx != -1 )
+ {
+ 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 );
+ p->land_dist = t + k_trace_delta * t1;
+ break;
}
- }
-
- v3f n1;
- float t1;
- int idx = spherecast_world( pco1, pco, 0.4f, &t1, n1 );
- if( idx != -1 )
- {
- v3_copy( n1, ground_normal );
- air_score = -v3_dot( pv, n1 );
-
- u32 vert_index = world.scene_geo->arrindices[ idx*3 ];
- struct world_material *mat = world_tri_index_material( vert_index );
-
- /* Bias prediction towords ramps */
- if( mat->info.flags & k_material_flag_skate_surface )
- air_score *= 0.1f;
-
- v3_lerp( pco1, pco, t1, prediction->log[ prediction->log_length ++ ] );
- time_to_impact += t1 * pstep;
- break;
+ v3_copy( co1, p->log[ p->log_length ++ ] );
+ v3_copy( co1, co0 );
}
- time_to_impact += pstep;
- v3_copy( pco, prediction->log[ prediction->log_length ++ ] );
- }
-
- if( grind_score < air_score )
- {
- prediction->score = grind_score;
- prediction->type = k_prediction_grind;
- v3_copy( grind_normal, prediction->n );
+ if( p->type == k_prediction_none )
+ s->prediction_count --;
}
- else if( air_score < INFINITY )
- {
- prediction->score = air_score;
- prediction->type = k_prediction_land;
- v3_copy( ground_normal, prediction->n );
- }
- else
- {
- prediction->score = INFINITY;
- prediction->type = k_prediction_none;
- }
-
- prediction->land_dist = time_to_impact;
-}
-VG_STATIC
-void player__approximate_best_trajectory( player_instance *player )
-{
- struct player_skate *s = &player->_skate;
-
- float pstep = VG_TIMESTEP_FIXED * 10.0f;
- float best_velocity_delta = -9999.9f;
-
- v3f axis;
- v3_cross( player->rb.to_world[1], player->rb.v, axis );
- v3_normalize( axis );
+ float score_min = INFINITY,
+ score_max = -INFINITY;
- s->prediction_count = 0;
- m3x3_identity( s->state.velocity_bias );
-
- float best_vmod = 0.0f,
- min_score = INFINITY,
- max_score = -INFINITY;
-
- v3_zero( s->state.apex );
- v3_copy( (v3f){0.0f,1.0f,0.0f}, s->land_normal );
- /* TODO: Make part of state */
+ struct land_prediction *best = NULL;
- s->land_dist = 0.0f;
-
- /*
- * Search a broad selection of futures
- */
- for( int m=-3;m<=12; m++ )
+ for( int i=0; i<s->prediction_count; i ++ )
{
- struct land_prediction *p = &s->predictions[ s->prediction_count ++ ];
-
- float vmod = ((float)m / 15.0f)*0.09f;
-
- m3x3f bias;
- v4f bias_q;
-
- q_axis_angle( bias_q, axis, vmod );
- q_m3x3( bias_q, bias );
-
- skate_score_biased_path( player->rb.co, player->rb.v, bias, p );
-
- if( p->type != k_prediction_none )
- {
- if( p->score < min_score )
- {
- min_score = p->score;
- best_vmod = vmod;
- s->land_dist = p->land_dist;
- v3_copy( p->apex, s->state.apex );
- v3_copy( p->n, s->land_normal );
+ struct land_prediction *p = &s->predictions[i];
- /* TODO: Store this as pointer? */
- }
+ if( p->score < score_min )
+ best = p;
- if( p->score > max_score )
- max_score = p->score;
- }
+ score_min = vg_minf( score_min, p->score );
+ score_max = vg_maxf( score_max, p->score );
}
- v4f vr_q;
- q_axis_angle( vr_q, axis, best_vmod*0.1f );
- q_m3x3( vr_q, s->state.velocity_bias );
-
- q_axis_angle( vr_q, axis, best_vmod );
- q_m3x3( vr_q, s->state.velocity_bias_pstep );
-
- /*
- * Logging
- */
for( int i=0; i<s->prediction_count; i ++ )
{
struct land_prediction *p = &s->predictions[i];
+ float s = p->score;
- float l = p->score;
+ s -= score_min;
+ s /= (score_max-score_min);
+ s = 1.0f - s;
- if( l < 0.0f )
- {
- vg_error( "negative score! (%f)\n", l );
- }
-
- l -= min_score;
- l /= (max_score-min_score);
- l = 1.0f - l;
+ p->score = s;
+ p->colour = s * 255.0f;
- p->score = l;
- p->colour = l * 255.0f;
-
- if( p->type == k_prediction_land )
+ if( p == best )
+ p->colour <<= 16;
+ else if( p->type == k_prediction_land )
p->colour <<= 8;
p->colour |= 0xff000000;
}
+ if( best )
+ {
+ v3_copy( best->n, s->land_normal );
+ v3_copy( best->v, player->rb.v );
+ s->land_dist = best->land_dist;
- v2f steer = { player->input_js1h->axis.value,
- player->input_js1v->axis.value };
- v2_normalize_clamp( steer );
+ v2f steer = { player->input_js1h->axis.value,
+ player->input_js1v->axis.value };
+ v2_normalize_clamp( steer );
- if( (fabsf(steer[1]) > 0.5f) && (s->land_dist >= 1.0f) )
- {
- s->state.flip_rate = (1.0f/s->land_dist) * vg_signf(steer[1]) *
- s->state.reverse ;
- s->state.flip_time = 0.0f;
- v3_copy( player->rb.to_world[0], s->state.flip_axis );
+ if( (fabsf(steer[1]) > 0.5f) && (s->land_dist >= 1.5f) )
+ {
+ s->state.flip_rate = (1.0f/s->land_dist) * vg_signf(steer[1]) *
+ s->state.reverse ;
+ s->state.flip_time = 0.0f;
+ v3_copy( player->rb.to_world[0], s->state.flip_axis );
+ }
+ else
+ {
+ s->state.flip_rate = 0.0f;
+ v3_zero( s->state.flip_axis );
+ }
}
else
{
- s->state.flip_rate = 0.0f;
- v3_zero( s->state.flip_axis );
+ v3_copy( (v3f){0.0f,1.0f,0.0f}, s->land_normal );
}
}
if( s->state.activity_prev != k_skate_activity_air )
player__approximate_best_trajectory( player );
+#if 0
m3x3_mulv( s->state.velocity_bias, player->rb.v, player->rb.v );
-#if 0
ray_hit hit;
/*
* Prediction
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);
vg_line_pt3( p->apex, 0.02f, 0xffffffff );
}
+#if 0
vg_line_pt3( s->state.apex, 0.030f, 0xff0000ff );
+#endif
}
/*
}
rb_update_transform( &player->rb );
-
- v3f gravity = { 0.0f, -9.6f, 0.0f };
- v3_muladds( player->rb.v, gravity, s->substep_delta, player->rb.v );
+ player->rb.v[1] += -k_gravity * s->substep_delta;
s->substep -= s->substep_delta;
-
rb_ct manifold[128];
int manifold_len = 0;
*/
m4x3_mulv( player->rb.to_world, s->state.head_position, head_wp1 );
-#if 0
float t;
v3f n;
if( (v3_dist2( head_wp0, head_wp1 ) > 0.001f) &&
player__dead_transition( player );
return;
}
-#endif
/*
* Phase 1: Regular collision detection
s->state.slip = 0.0f;
v3_copy( player->rb.co, s->state.prev_pos );
+#if 0
m3x3_identity( s->state.velocity_bias );
m3x3_identity( s->state.velocity_bias_pstep );
+#endif
+
v3_zero( s->state.throw_v );
v3_zero( s->state.trick_vel );
v3_zero( s->state.trick_euler );