#endif
}
-/*
- * Entire Walking physics model
- * TODO: sleep when under certain velotiy
- */
-VG_STATIC void player_walk_physics(void)
+VG_STATIC void player_walk_update_collision(void)
{
struct player_phys *phys = &player.phys;
- rigidbody *rbf = &player.collide_front,
- *rbb = &player.collide_back;
-
- m3x3_copy( phys->rb.to_world, player.collide_front.to_world );
- m3x3_copy( phys->rb.to_world, player.collide_back.to_world );
-
float h0 = 0.3f,
h1 = 0.9f;
- m4x3_mulv( phys->rb.to_world, (v3f){0.0f,h0,0.0f}, rbf->co );
+ rigidbody *rbf = &player.collide_front,
+ *rbb = &player.collide_back;
+
+ v3_add( phys->rb.co, (v3f){0.0f,h0,0.0f}, rbf->co );
+ v3_add( phys->rb.co, (v3f){0.0f,h1,0.0f}, rbb->co );
v3_copy( rbf->co, rbf->to_world[3] );
- m4x3_mulv( phys->rb.to_world, (v3f){0.0f,h1,0.0f}, rbb->co );
v3_copy( rbb->co, rbb->to_world[3] );
-
m4x3_invert_affine( rbf->to_world, rbf->to_local );
m4x3_invert_affine( rbb->to_world, rbb->to_local );
rb_update_bounds( rbf );
rb_update_bounds( rbb );
+}
- rb_debug( rbf, 0xff0000ff );
- rb_debug( rbb, 0xff0000ff );
+VG_STATIC void player_integrate(void);
+/*
+ * Entire Walking physics model
+ * TODO: sleep when under certain velotiy
+ */
+VG_STATIC void player_walk_physics(void)
+{
+ struct player_phys *phys = &player.phys;
+ rigidbody *rbf = &player.collide_front,
+ *rbb = &player.collide_back;
- rb_ct manifold[64];
- int len = 0;
+ m3x3_identity( player.collide_front.to_world );
+ m3x3_identity( player.collide_back.to_world );
- len += rb_sphere_scene( rbf, &world.rb_geo, manifold+len );
- len += rb_sphere_scene( rbb, &world.rb_geo, manifold+len );
+ v3_zero( phys->rb.w );
+ q_axis_angle( phys->rb.q, (v3f){0.0f,1.0f,0.0f}, -player.angles[0] );
- rb_presolve_contacts( manifold, len );
+ rb_ct manifold[64];
+ int len;
- for( int j=0; j<5; j++ )
+ v3f forward_dir = { sinf(player.angles[0]),0.0f,-cosf(player.angles[0]) };
+ v3f right_dir = { -forward_dir[2], 0.0f, forward_dir[0] };
+
+ if( phys->in_air )
{
+ player_walk_update_collision();
+ rb_debug( rbf, 0xff0000ff );
+ rb_debug( rbb, 0xff0000ff );
+
+ len = 0;
+ len += rb_sphere_scene( rbf, &world.rb_geo, manifold+len );
+ len += rb_sphere_scene( rbb, &world.rb_geo, manifold+len );
+ rb_presolve_contacts( manifold, len );
+
for( int i=0; i<len; i++ )
{
struct contact *ct = &manifold[i];
-
- /*normal */
- float vn = -v3_dot( phys->rb.v, ct->n );
- vn += ct->bias;
+ if( v3_dot( ct->n, (v3f){0.0f,1.0f,0.0f} ) > 0.5f )
+ phys->in_air = 0;
+ }
- float temp = ct->norm_impulse;
- ct->norm_impulse = vg_maxf( temp + vn, 0.0f );
- vn = ct->norm_impulse - temp;
+ for( int j=0; j<5; j++ )
+ {
+ for( int i=0; i<len; i++ )
+ {
+ struct contact *ct = &manifold[i];
+
+ /*normal */
+ float vn = -v3_dot( phys->rb.v, ct->n );
+ vn += ct->bias;
- v3f impulse;
- v3_muls( ct->n, vn, impulse );
+ float temp = ct->norm_impulse;
+ ct->norm_impulse = vg_maxf( temp + vn, 0.0f );
+ vn = ct->norm_impulse - temp;
- v3_add( impulse, phys->rb.v, phys->rb.v );
+ v3f impulse;
+ v3_muls( ct->n, vn, impulse );
- /* friction */
- for( int j=0; j<2; j++ )
- {
- float f = k_friction * ct->norm_impulse,
- vt = v3_dot( phys->rb.v, ct->t[j] ),
- lambda = -vt;
-
- float temp = ct->tangent_impulse[j];
- ct->tangent_impulse[j] = vg_clampf( temp + lambda, -f, f );
- lambda = ct->tangent_impulse[j] - temp;
+ v3_add( impulse, phys->rb.v, phys->rb.v );
+
+ /* friction */
+ for( int j=0; j<2; j++ )
+ {
+ float f = k_friction * ct->norm_impulse,
+ vt = v3_dot( phys->rb.v, ct->t[j] ),
+ lambda = -vt;
+
+ float temp = ct->tangent_impulse[j];
+ ct->tangent_impulse[j] = vg_clampf( temp + lambda, -f, f );
+ lambda = ct->tangent_impulse[j] - temp;
- v3_muladds( phys->rb.v, ct->t[j], lambda, phys->rb.v );
+ v3_muladds( phys->rb.v, ct->t[j], lambda, phys->rb.v );
+ }
}
}
- }
- if( len == 0 )
- phys->in_air = 1;
+ player_integrate();
+ }
else
{
- phys->in_air = 0;
- struct world_material *surface_mat = world_contact_material( manifold );
- player.surface_prop = surface_mat->info.surface_prop;
- }
+ /* translate player */
+ v2f walk = { player.input_walkh->axis.value,
+ player.input_walkv->axis.value };
+
+ if( v2_length2(walk) > 0.001f )
+ v2_normalize( walk );
- if( !phys->in_air )
- {
- float const DOWNFORCE = -k_walk_downforce*VG_TIMESTEP_FIXED;
- v3_muladds( phys->rb.v, (v3f){0.0f,-1.0f,0.0f}, DOWNFORCE, phys->rb.v );
+ v2_muls( walk, vg_maxf( player.input_push->axis.value, 0.5f ) *
+ k_walkspeed * VG_TIMESTEP_FIXED, walk );
+ v3f walk_apply;
+ v3_zero( walk_apply );
+
+ /* Do XY translation */
+ v3_muladds( walk_apply, right_dir, walk[0], walk_apply );
+ v3_muladds( walk_apply, forward_dir, walk[1], walk_apply );
+ v3_add( walk_apply, phys->rb.co, phys->rb.co );
+ v3_divs( walk_apply, VG_TIMESTEP_FIXED, phys->rb.v );
+
+ /* Directly resolve collisions */
+ player_walk_update_collision();
+ rb_debug( rbf, 0xffffff00 );
+ rb_debug( rbb, 0xffffff00 );
+
+ len = 0;
+ len += rb_sphere_scene( rbf, &world.rb_geo, manifold+len );
+ len += rb_sphere_scene( rbb, &world.rb_geo, manifold+len );
+
+ v3f dt;
+ v3_zero( dt );
+ for( int j=0; j<3; j++ )
+ {
+ for( int i=0; i<len; i++ )
+ {
+ struct contact *ct = &manifold[i];
+
+ float p = vg_maxf( 0.0f, ct->p - 0.00f ),
+ cur = vg_clampf( v3_dot( ct->n, dt ), 0.0f, p );
+ v3_muladds( dt, ct->n, (p - cur) * 0.333333333f, dt );
+ }
+ }
+ v3_add( dt, phys->rb.co, phys->rb.co );
+
+ /* jump */
if( player.input_jump->button.value )
{
phys->rb.v[1] = 5.0f;
+ phys->in_air = 1;
+ return;
}
- }
-
- v3_zero( phys->rb.w );
- q_axis_angle( phys->rb.q, (v3f){0.0f,1.0f,0.0f}, -player.angles[0] );
-
- v3f forward_dir = { sinf(player.angles[0]),0.0f,-cosf(player.angles[0]) };
+
+ /* if we've put us in the air, step down slowly */
+ phys->in_air = 1;
+ float max_dist = 0.3f,
+ start_y = phys->rb.co[1];
- v3f p1;
- v3_muladds( phys->rb.co, forward_dir, 2.0f, p1 );
- vg_line( phys->rb.co, p1, 0xff0000ff );
+ for( int j=0; j<8; j++ )
+ {
+ for( int i=0; i<len; i++ )
+ {
+ struct contact *ct = &manifold[i];
+ if( v3_dot( ct->n, (v3f){0.0f,1.0f,0.0f} ) > 0.5f )
+ {
+ phys->in_air = 0;
+ if( j == 0 )
+ return;
+
+ v3f dt;
+ v3_zero( dt );
+ for( int j=0; j<3; j++ )
+ {
+ for( int i=0; i<len; i++ )
+ {
+ struct contact *ct = &manifold[i];
+
+ float p = vg_maxf( 0.0f, ct->p - 0.0025f ),
+ cur = vg_clampf( v3_dot( ct->n, dt ), 0.0f, p );
+ v3_muladds( dt, ct->n, (p - cur) * 0.333333333f, dt );
+ }
+ }
+ v3_add( dt, phys->rb.co, phys->rb.co );
+ return;
+ }
+ }
- float walk = player.input_walk->axis.value;
- player.walk = powf( walk, 4.0f );
+ phys->rb.co[1] -= max_dist * 0.125f;
- if( player.walk > 0.025f )
- {
- float
- speed = vg_lerpf( 0.025f*k_runspeed, k_runspeed, player.walk ),
- amt = k_walk_accel * VG_TIMESTEP_FIXED,
- zvel = v3_dot( phys->rb.v, forward_dir ),
- new_vel = vg_minf( zvel + amt, speed ),
- diff = new_vel - vg_minf( zvel, speed );
-
- if( !phys->in_air )
- {
- v3_muladds( phys->rb.v, forward_dir, diff, phys->rb.v );
+ player_walk_update_collision();
+ len = 0;
+ len += rb_sphere_scene( rbf, &world.rb_geo, manifold+len );
+ len += rb_sphere_scene( rbb, &world.rb_geo, manifold+len );
}
- }
-
- if( !phys->in_air )
- {
- phys->rb.v[0] *= 1.0f - (VG_TIMESTEP_FIXED * k_walk_friction);
- phys->rb.v[2] *= 1.0f - (VG_TIMESTEP_FIXED * k_walk_friction);
+
+ /* Transitioning into air mode */
+ phys->rb.co[1] = start_y;
}
}
rb_update_transform( &player.phys.rb );
}
+VG_STATIC void player_integrate(void)
+{
+ struct player_phys *phys = &player.phys;
+ apply_gravity( phys->rb.v, VG_TIMESTEP_FIXED );
+ v3_muladds( phys->rb.co, phys->rb.v, VG_TIMESTEP_FIXED, phys->rb.co );
+}
+
VG_STATIC void player_do_motion(void)
{
struct player_phys *phys = &player.phys;
}
}
+
+ v3f prevco;
+ v3_copy( phys->rb.co, prevco );
+
if( phys->on_board )
+ {
player_physics();
+ player_integrate();
+ }
else
player_walk_physics();
- /* Integrate velocity */
- v3f prevco;
- v3_copy( phys->rb.co, prevco );
- apply_gravity( phys->rb.v, VG_TIMESTEP_FIXED );
- v3_muladds( phys->rb.co, phys->rb.v, VG_TIMESTEP_FIXED, phys->rb.co );
-
/* Real angular velocity integration */
v3_lerp( phys->rb.w, (v3f){0.0f,0.0f,0.0f}, 0.125f, phys->rb.w );
if( v3_length2( phys->rb.w ) > 0.0f )
rb_update_transform( &phys->rb );
}
-/*
- * Free camera movement
- */
-VG_STATIC void player_mouseview(void)
-{
- if( ui_want_mouse() )
- return;
-
- static v2f mouse_last,
- view_vel = { 0.0f, 0.0f };
-
-#if 0
- if( vg_get_button_down( "primary" ) )
- v2_copy( vg.mouse, mouse_last );
-
- else if( vg_get_button( "primary" ) )
- {
- v2f delta;
- v2_sub( vg.mouse, mouse_last, delta );
- v2_copy( vg.mouse, mouse_last );
-
- v2_muladds( view_vel, delta, 0.06f*vg.time_delta, view_vel );
- }
-#endif
-
- v2_muls( view_vel, 1.0f-4.2f*vg.time_delta, view_vel );
- v2_add( view_vel, player.angles, player.angles );
- player.angles[1] = vg_clampf( player.angles[1], -VG_PIf*0.5f, VG_PIf*0.5f );
-}
-
VG_STATIC void player_freecam(void)
{
player_mouseview();