X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=player_device_walk.h;fp=player_device_walk.h;h=0559acdc2dce064965391a9794f702bb19189a69;hb=2ab1c45f664daf5a452fd212c89dcfd918f7dd81;hp=0000000000000000000000000000000000000000;hpb=d45f2b7d71311ce5ce8cd3496844b4ec7d2f46ac;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/player_device_walk.h b/player_device_walk.h new file mode 100644 index 0000000..0559acd --- /dev/null +++ b/player_device_walk.h @@ -0,0 +1,324 @@ +#ifndef PLAYER_DEVICE_WALK_H +#define PLAYER_DEVICE_WALK_H + +#include "player_interface.h" + +VG_STATIC float + k_walkspeed = 10.0f, + k_airspeed = 2.0f, + k_stopspeed = 4.0f, + k_walk_accel = 10.0f, + k_walk_air_accel = 7.0f, + k_walk_friction = 10.0f, + k_walk_step_height = 0.2f; + +struct player_device_walk +{ + rb_capsule collider; + + struct + { + v3f angles; + + enum walk_activity + { + k_walk_activity_air, + k_walk_activity_ground, + k_walk_activity_sleep + } + activity; + } + state; + + enum mdl_surface_prop surface; +}; + +VG_STATIC void player_walk_pre_update( player_interface *player, + player_attachment *at ) +{ + struct player_device_walk *w = at->storage; + player_look( player, w->state.angles ); + +#if 0 + v3f walk = { player->input_walkh->axis.value, + 0.0f, + -player->input_walkv->axis.value }; + + v3_muls( walk, 10.0f * vg.time_delta, walk ); + + m3x3f m; + euler_m3x3( w->angles, m ); + v3_muladds( player->rb.co, m[0], walk[0], player->rb.co ); + v3_muladds( player->rb.co, m[1], walk[1], player->rb.co ); + v3_muladds( player->rb.co, m[2], walk[2], player->rb.co ); +#endif +} + +VG_STATIC int player_walk_normal_standable( v3f n ) +{ + return n[1] > 0.70710678118f; +} + +VG_STATIC void player_accelerate( v3f v, v3f movedir, float speed, float accel ) +{ + float currentspeed = v3_dot( v, movedir ), + addspeed = speed - currentspeed; + + if( addspeed <= 0 ) + return; + + float accelspeed = accel * k_rb_delta * speed; + + if( accelspeed > addspeed ) + accelspeed = addspeed; + + v3_muladds( v, movedir, accelspeed, v ); +} + +VG_STATIC void player_friction( v3f v ) +{ + float speed = v3_length( v ), + drop = 0.0f, + control = vg_maxf( speed, k_stopspeed ); + + if( speed < 0.04f ) + return; + + drop += control * k_walk_friction * k_rb_delta; + + float newspeed = vg_maxf( 0.0f, speed - drop ); + newspeed /= speed; + + v3_muls( v, newspeed, v ); +} + +VG_STATIC void player_walk_update( player_interface *player, + player_attachment *at ) +{ + struct player_device_walk *w = at->storage; + w->collider.height = 2.0f; + w->collider.radius = 0.3f; + + m4x3f mtx; + m3x3_identity( mtx ); + v3_add( player->rb.co, (v3f){0.0f, 1.0f, 0.0f}, mtx[3] ); + + debug_capsule( mtx, w->collider.radius, w->collider.height, VG__WHITE ); + + rb_ct manifold[64]; + int len; + + float yaw = w->state.angles[0]; + + v3f forward_dir = { sinf(yaw), 0.0f, -cosf(yaw) }; + v3f right_dir = { -forward_dir[2], 0.0f, forward_dir[0] }; + + v2f walk = { player->input_walkh->axis.value, + player->input_walkv->axis.value }; + + if( v2_length2(walk) > 0.001f ) + v2_normalize_clamp( walk ); + + /* + * Collision detection + */ + len = rb_capsule__scene( mtx, &w->collider, NULL, + &world.rb_geo.inf.scene, manifold ); + rb_manifold_filter_coplanar( manifold, len, 0.01f ); + len = rb_manifold_apply_filtered( manifold, len ); + + v3f surface_avg = { 0.0f, 0.0f, 0.0f }; + w->state.activity = k_walk_activity_air; + + for( int i=0; in ) ) + { + w->state.activity = k_walk_activity_ground; + v3_add( surface_avg, ct->n, surface_avg ); + } + + rb_prepare_contact( ct ); + } + + + /* + * Move & Friction + */ + float accel_speed = 0.0f, nominal_speed = 0.0f; + v3f movedir; + v3_muls( right_dir, walk[0], movedir ); + v3_muladds( movedir, forward_dir, walk[1], movedir ); + + if( w->state.activity == k_walk_activity_ground ) + { + v3_normalize( surface_avg ); + + v3f tx, ty; + rb_tangent_basis( surface_avg, tx, ty ); + + if( v2_length2(walk) > 0.001f ) + { + /* clip movement to the surface */ + float d = v3_dot(surface_avg,movedir); + v3_muladds( movedir, surface_avg, -d, movedir ); + } + + accel_speed = k_walk_accel; + nominal_speed = k_walkspeed; + + /* jump */ + if( player->input_jump->button.value ) + { + player->rb.v[1] = 5.0f; + w->state.activity = k_walk_activity_air; + accel_speed = k_walk_air_accel; + nominal_speed = k_airspeed; + } + else + { + player_friction( player->rb.v ); + + struct world_material *surface_mat = world_contact_material(manifold); + w->surface = surface_mat->info.surface_prop; + } + } + else + { + accel_speed = k_walk_air_accel; + nominal_speed = k_airspeed; + } + + if( v2_length2(walk) > 0.001f ) + { + vg_info( "%f %f\n", walk[0], walk[1] ); + player_accelerate( player->rb.v, movedir, nominal_speed, accel_speed ); + v3_normalize( movedir ); + } + + /* + * Resolve velocity constraints + */ + for( int j=0; j<5; j++ ) + { + for( int i=0; irb.v, ct->n ); + + float temp = ct->norm_impulse; + ct->norm_impulse = vg_maxf( temp + vn, 0.0f ); + vn = ct->norm_impulse - temp; + + v3_muladds( player->rb.v, ct->n, vn, player->rb.v ); + } + } + + /* + * Depenetrate + */ + v3f dt; + v3_zero( dt ); + for( int j=0; j<8; j++ ) + { + for( int i=0; in, dt ), + remaining = (ct->p-k_penetration_slop) - resolved_amt, + apply = vg_maxf( remaining, 0.0f ) * 0.3f; + + v3_muladds( dt, ct->n, apply, dt ); + } + } + v3_add( dt, player->rb.co, player->rb.co ); + + /* TODO: Stepping...... + * + * ideas; walkgrid style steps + */ +#if 0 + if( w->state.activity == k_walk_activity_ground ) + { + /* step */ + float max_dist = 0.4f; + + v3f pa, pb; + v3_copy( player->rb.co, pa ); + pa[1] += w->collider.radius + max_dist; + + v3_muladds( pa, (v3f){0.0f,1.0f,0.0f}, -max_dist * 2.0f, pb ); + vg_line( pa, pb, 0xff000000 ); + + v3f n; + float t; + if( spherecast_world( pa, pb, w->collider.radius, &t, n ) != -1 ) + { + if( player_walk_normal_standable( n ) ) + { + v3_lerp( pa, pb, t, player->rb.co ); + player->rb.co[1] -= w->collider.radius; + } + } + } +#endif + + + /* integrate */ + if( w->state.activity == k_walk_activity_air ) + player->rb.v[1] += -k_gravity * k_rb_delta; + + v3_muladds( player->rb.co, player->rb.v, k_rb_delta, player->rb.co ); + + + v3_add( player->rb.co, (v3f){0.0f, 1.0f, 0.0f}, mtx[3] ); + debug_capsule( mtx, w->collider.radius, w->collider.height, VG__GREEN ); +} + +VG_STATIC void player_walk_post_update( player_interface *player, + player_attachment *at ) +{ + +} + +VG_STATIC void player_walk_get_camera( player_interface *player, + player_attachment *at, camera *cam ) +{ + struct player_device_walk *w = at->storage; + + float substep = vg_clampf( vg.accumulator / k_rb_delta, 0.0f, 1.0f ); + v3f pos; + v3_muladds( player->rb.co, player->rb.v, k_rb_delta*substep, pos ); + + v3_add( pos, (v3f){0.0f,1.8f,0.0f}, cam->pos ); + v3_copy( w->state.angles, cam->angles ); + cam->fov = 90.0f; +} + +VG_STATIC void player_walk_ui( player_interface *player, + player_attachment *at ) +{ + player_debugtext( 1, "V: %5.2f %5.2f %5.2f",player->rb.v[0], + player->rb.v[1], + player->rb.v[2] ); + player_debugtext( 1, "CO: %5.2f %5.2f %5.2f",player->rb.co[0], + player->rb.co[1], + player->rb.co[2] ); +} + +player_device player_device_walk = +{ + .pre_update = player_walk_pre_update, + .update = player_walk_update, + .post_update = player_walk_post_update, + .get_camera = player_walk_get_camera, + .debug_ui = player_walk_ui +}; + +#endif /* PLAYER_DEVICE_WALK_H */