medfall

A super great game engine
Log | Files | Refs

commit b194ede036bb409c4e8b73e51c8e15bb9dc3f6f0
parent 81dbce2d8a5d6112380a3f1747aff281d3e417ae
Author: Michael Savage <mikejsavage@gmail.com>
Date:   Wed Jul 26 21:24:21 +0300

Basic player physics. Walking up hills doesn't work yet

Diffstat:
game.h | 3++-
hm.cc | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
linear_algebra.h | 5+++++
terrain_manager.cc | 16++++++++--------
4 files changed, 142 insertions(+), 12 deletions(-)
diff --git a/game.h b/game.h @@ -24,7 +24,8 @@ struct GameState { NONCOPYABLE( GameState ); GameState() { } - v3 pos; + v3 pos, velocity; + bool on_ground; float pitch, yaw; TerrainManager tm; diff --git a/hm.cc b/hm.cc @@ -1,3 +1,5 @@ +#include <float.h> + #include "game.h" #include "intrinsics.h" #include "log.h" @@ -63,6 +65,7 @@ GAME_INIT( game_init ) { net_init(); game->pos = v3( 1500, 1500, 120 ); + game->pos = v3( 1160, 1160, 3 ); game->pitch = 0; game->yaw = 45; @@ -177,24 +180,143 @@ GAME_FRAME( game_frame ) { const float dsun = ( input->keys[ KEY_EQUALS ] - input->keys[ KEY_MINUS ] ) * dt * 0.25f; game->sun_angle += dsun; - const float speed = 100.0f; - const v3 world_up = v3( 0, 0, 1 ); v3 forward = v3_forward( game->pitch, game->yaw ); v3 right = normalize( cross( forward, world_up ) ); v3 up = normalize( cross( right, forward ) ); +#if 1 + if( game->on_ground ) { + if( input->keys[ KEY_SPACE ] ) { + game->velocity.z = 9.8; + game->on_ground = false; + } + } + + const float acceleration = 12; + if( game->on_ground ) { + // apply friction + if( dot( game->velocity, game->velocity ) < 0.01 ) { + game->velocity.x = 0; + game->velocity.y = 0; + } + else { + float current_speed = length( game->velocity ); + float drop = max( acceleration, current_speed ) * acceleration * dt / 2.0f; + float new_speed = max( 0.0f, current_speed - drop ); + game->velocity = new_speed * ( game->velocity / current_speed ); + } + + if( fb != 0 || lr != 0 ) { + // apply acceleration + float max_speed = 10; + + v3 forward_xy = v3_forward_xy( game->yaw ); + v3 right_xy = normalize( cross( forward_xy, world_up ) ); + v3 desired_direction = fb * forward_xy + lr * right_xy; + + desired_direction = normalize( desired_direction ); + + float speed_in_desired_direction = dot( game->velocity, desired_direction ); + + if( speed_in_desired_direction < max_speed ) { + float accel_speed = min( acceleration * dt * max_speed, max_speed - speed_in_desired_direction ); + game->velocity += accel_speed * desired_direction; + } + } + } + + int spins = 0; + float remaining_t = dt; + while( remaining_t > 0 && spins < 5 ) { + spins++; + if( game->on_ground ) { + v3 start = game->pos + v3( 0, 0, 0.001f ); + v3 end = start + game->velocity * remaining_t; + + float t; + float step_t = FLT_MAX; + v3 normal, step_normal; + + const float step_height = 0.1f; + v3 step_start = game->pos + v3( 0, 0, step_height ); + + bool hit = segment_vs_terrain( &game->tm, start, end, &t, &normal ); + bool step_hit = false; + + bool step_up_hit = segment_vs_terrain( &game->tm, start, step_start, NULL, NULL ); + if( !step_up_hit ) { + v3 step_end = step_start + game->velocity * remaining_t; + step_hit = segment_vs_terrain( &game->tm, step_start, step_end, &step_t, &step_normal ); + } + + if( step_t > t ) { + v3 step_intersection = step_start + game->velocity * remaining_t * min( 1.0f, step_t ); + v3 step_down = step_intersection - v3( 0, 0, step_height ); + + float step_down_t; + bool step_down_hit = segment_vs_terrain( &game->tm, step_intersection, step_down, &step_down_t, &step_normal ); + if( !step_down_hit ) { + step_t = 1.0f; + game->on_ground = false; + } + } + + if( hit ) { + game->pos = start + game->velocity * t * remaining_t + v3( 0, 0, 0.001f ); + remaining_t = ( 1.0f - t ) * remaining_t; + } + else { + v3 down_end = end - v3( 0, 0, 0.2f ); + float down_t; + bool down_hit = segment_vs_terrain( &game->tm, end, down_end, &down_t, NULL ); + if( !down_hit ) { + game->on_ground = false; + down_t = 1; + } + game->pos = lerp( end, down_t, down_end ) + v3( 0, 0, 0.001f ); + // TODO: probably not right + remaining_t = 0; + } + } + else { + const float gravity = -30.0f; + game->velocity += v3( 0, 0, gravity ) * remaining_t; + + v3 end = game->pos + game->velocity * remaining_t; + float t; + v3 normal; + bool hit = segment_vs_terrain( &game->tm, game->pos, end, &t, &normal ); + if( hit ) { + // TODO: check normal is flat enough, otherwise stay in the air + game->on_ground = true; + game->pos += game->velocity * t * remaining_t + v3( 0, 0, 0.001 ); + // TODO: truncate velocity + game->velocity.z = 0; + + remaining_t = ( 1.0f - t ) * remaining_t; + } + else { + game->pos = end; + remaining_t = 0; + } + } + } +#else + const float speed = 100.0f; game->pos += forward * dt * fb * speed; game->pos += right * dt * lr * speed; game->pos.z += dt * dz * speed; +#endif // game->pos.z = terrain_height( &game->tm, game->pos ) + 1.8f; // game->pos.z += dz * 50.0f * dt; terrain_update( &game->tm, game->pos ); + v3 eye_pos = game->pos + v3( 0, 0, 1.8f ); m4 P = m4_perspective( VERTICAL_FOV, get_aspect_ratio(), NEAR_PLANE_DEPTH, FAR_PLANE_DEPTH ); - m4 V = m4_view( forward, right, up, game->pos ); + m4 V = m4_view( forward, right, up, eye_pos ); m4 Vsky = m4_view( forward, right, up, v3( 0 ) ); v3 sun_dir = v3( -cosf( game->sun_angle ), 0, sinf( game->sun_angle ) ); @@ -409,5 +531,7 @@ GAME_FRAME( game_frame ) { dt * 1000.0f, 1.0f / dt, connected ? "connected!" : "connecting", game->pos ); draw_text( status.c_str(), 2, 2, 16.0f ); + + draw_text( str< 128 >( "velocity = {.1}, speed = {.2}", game->velocity, length( game->velocity.xy() ) ).c_str(), 2, 20, 16 ); } } diff --git a/linear_algebra.h b/linear_algebra.h @@ -445,6 +445,11 @@ forceinline v3 v3_forward( float pitch, float yaw ) { ); } +forceinline v3 v3_forward_xy( float yaw ) { + yaw = deg_to_rad( yaw ); + return v3( cosf( yaw ), sinf( yaw ), 0 ); +} + /* * v3u32 */ diff --git a/terrain_manager.cc b/terrain_manager.cc @@ -1,4 +1,5 @@ #include <stdio.h> +#include <float.h> #include "intrinsics.h" #include "log.h" @@ -415,15 +416,15 @@ v3 terrain_normal( const TerrainManager * tm, v3 position ) { bool segment_vs_terrain( const TerrainManager * tm, v3 seg_origin, v3 seg_end, float * t, v3 * xnormal ) { PROFILE_FUNCTION(); - v3 dont_care = v3( 0, 0, 0 ); - if( xnormal == NULL ) { - xnormal = &dont_care; - } + float dont_care_t; + v3 dont_care_xnormal = v3( 0, 0, 0 ); + if( t == NULL ) t = &dont_care_t; + if( xnormal == NULL ) xnormal = &dont_care_xnormal; float segment_length = length( seg_end - seg_origin ); Ray3 ray( seg_origin, normalize( seg_end - seg_origin ) ); - bool hit = false; + *t = FLT_MAX; // TODO: bresenhams vs top level for( u16 vy = 0; vy < VIEW_SIZE; vy++ ) { @@ -445,12 +446,11 @@ bool segment_vs_terrain( const TerrainManager * tm, v3 seg_origin, v3 seg_end, f float tile_t; bool tile_hit = ray_vs_quadtree( qt, ray, &tile_t, xnormal ); - if( tile_hit && ( !hit || tile_t < *t ) && tile_t <= segment_length ) { - hit = true; + if( tile_hit && tile_t <= segment_length && tile_t < *t ) { *t = tile_t; } } } - return hit; + return *t < FLT_MAX; }