summaryrefslogtreecommitdiff
path: root/src/game/physics
diff options
context:
space:
mode:
authoraura <nw@moneybot.cc>2026-03-01 18:04:13 +0100
committeraura <nw@moneybot.cc>2026-03-01 18:04:13 +0100
commitda27ee18bef82c2152e348e8ff805cb64c80643e (patch)
tree795e8161b4451bec2ef20b62e197aa1df727bc75 /src/game/physics
parent78db9dd151f7c7719787a7e092f0c34ae6b85179 (diff)
fix ramps make movement s m o o t h
Diffstat (limited to 'src/game/physics')
-rw-r--r--src/game/physics/movement.cpp111
1 files changed, 76 insertions, 35 deletions
diff --git a/src/game/physics/movement.cpp b/src/game/physics/movement.cpp
index 73c5202..1e2e973 100644
--- a/src/game/physics/movement.cpp
+++ b/src/game/physics/movement.cpp
@@ -80,23 +80,6 @@ void gmove_end_tick() {
p->flags &= ~PFL_ONGROUND;
}
-VEC3 gmove_clip_velocity( VEC3 in, VEC3 norm, F32 overbounce ) {
- F32 blocked = vec_dot( in, norm );
- F32 backoff = blocked * overbounce;
- VEC3 out = in - norm * backoff;
-
- F32 adjust = vec_dot( out, norm );
- if( adjust < 0.f )
- out -= (norm * adjust);
-
- if( var_geti( mv_wallboost ) ) {
- F32 len = vec_len( out );
- if( len > 0.f )
- out *= ( -1.f * blocked + len ) / len;
- }
-
- return out;
-}
void gmove_check_velocity() {
F32 maxspeed = var_getf( mv_maxspeed );
@@ -203,6 +186,27 @@ void gmove_categorize_pos() {
gmove->ground = objl->world;
}
}
+
+ if( gmove->ground )
+ gmove->velocity.z = 0.f;
+}
+
+VEC3 gmove_clip_velocity( VEC3 in, VEC3 norm, F32 overbounce ) {
+ F32 blocked = vec_dot( in, norm );
+ F32 backoff = blocked * overbounce;
+ VEC3 out = in - norm * backoff;
+
+ F32 adjust = vec_dot( out, norm );
+ if( adjust < 0.f )
+ out -= (norm * adjust);
+
+ if( var_geti( mv_wallboost ) ) {
+ F32 len = vec_len( out );
+ if( len > 0.f )
+ out *= ( -1.f * blocked + len ) / len;
+ }
+
+ return out;
}
VEC3 gmove_clip_planes( VEC3 vel, VEC3* pos, LIST<VEC3>* planes, F32 overbounce ) {
@@ -236,9 +240,11 @@ VEC3 gmove_clip_planes( VEC3 vel, VEC3* pos, LIST<VEC3>* planes, F32 overbounce
}
F32 gmove_try_move( BSP_TRACE* t, VEC3* pos, VEC3* vel ) {
+ VEC3 origin = *pos;
F32 dt = TICK_INTERVAL;
AABB aabb = gmove->aabb;
LIST<VEC3> planes;
+ I32 nudges = 0;
for( U32 bump = 0; bump < 4; ++bump ) {
VEC3 wishmove = *vel * dt;
@@ -248,12 +254,24 @@ F32 gmove_try_move( BSP_TRACE* t, VEC3* pos, VEC3* vel ) {
break;
}
+ F32 dot = vec_dot( *vel, t->normal );
*pos += wishmove * t->frac;
// nudge player away from wall
- if( vec_dot( *vel, t->normal ) < 0.f )
- *pos += t->normal * (BSP_TRACE_EPSILON * 2.f);
-
- planes.push( t->normal );
+ *pos += t->normal * BSP_TRACE_EPSILON * 4.f;
+
+ // avoid clipping planes twice
+ // in a rare edge case its possible to get stuck in the plane again after pushing away from it
+ if( fabsf( dot ) > 0.0001f || planes.idx_of( t->normal ) == -1 )
+ planes.push( t->normal );
+ else {
+ --bump;
+ if( nudges++ > 3 ) {
+ *vel = {};
+ *pos = origin;
+ break;
+ }
+ continue;
+ }
dt *= (1.f - t->frac);
if( dt <= 0.0001f )
@@ -396,19 +414,20 @@ void gmove_stay_on_ground() {
start.z += 2.f;
end.z -= gmove->pl->stepsize;
- bsp_trace( &tr, gmove->bsp, gmove->aabb, start, end );
- start = tr.point + BSP_TRACE_EPSILON;
+ bsp_trace( &tr, gmove->bsp, gmove->aabb, gmove->pos, start );
+ start = tr.point;
bsp_trace( &tr, gmove->bsp, gmove->aabb, start, end );
if( tr.frac > 0.f && tr.frac < 1.f && !tr.startsolid && tr.normal.z >= 0.7f ) {
F32 delta = fabs( gmove->pos.z - tr.point.z );
- if( delta > BSP_TRACE_EPSILON )
- gmove->pos = tr.point + tr.normal * BSP_EDGE_TOLERANCE;
+ if( delta > BSP_TRACE_EPSILON ) {
+ gmove->pos = tr.point + tr.normal * BSP_TRACE_EPSILON * 2.f;
+ gmove_check_stuck( &gmove->pos );
+ }
}
}
-
void gmove_step_move( VEC3 dest, BSP_TRACE* tr ) {
VEC3 endpos = dest;
VEC3 pos = gmove->pos;
@@ -416,17 +435,32 @@ void gmove_step_move( VEC3 dest, BSP_TRACE* tr ) {
VEC3 up = pos, down = pos;
VEC3 upvel = vel, downvel = vel;
+ F32 groundn = 0.f;
+ if( gmove->ground ) {
+ VEC3 ground = pos;
+ ground.z += 2.f;
+ bsp_trace( tr, gmove->bsp, gmove->aabb, pos, ground );
+ if( tr->hit )
+ groundn = tr->normal.z;
+ }
+
+ // try moving forward first
gmove_try_move( tr, &down, &downvel );
VEC3 downn = tr->normal;
- endpos.z += gmove->pl->stepsize + BSP_DIST_EPSILON;
+ // move up a step
+ endpos = pos;
+ endpos.z += (gmove->pl->stepsize + BSP_DIST_EPSILON);
+
bsp_trace( tr, gmove->bsp, gmove->aabb, pos, endpos );
- if( !tr->startsolid && tr->frac > BSP_TRACE_EPSILON ) {
+ if( !tr->startsolid )
up = tr->point;
- }
gmove_try_move( tr, &up, &upvel );
+ VEC3 upnorm = tr->normal;
+
+ // move back down onto the ground
endpos = up;
endpos.z -= (gmove->pl->stepsize + BSP_DIST_EPSILON);
@@ -443,9 +477,8 @@ void gmove_step_move( VEC3 dest, BSP_TRACE* tr ) {
return;
}
- if( !tr->startsolid && tr->frac > BSP_TRACE_EPSILON ) {
+ if( !tr->startsolid )
up = tr->point;
- }
F32 updist = vec_dist( pos, up );
F32 downdist = vec_dist( pos, down );
@@ -454,13 +487,15 @@ void gmove_step_move( VEC3 dest, BSP_TRACE* tr ) {
if( downdist > updist ) {
gmove->pos = down;
if( downn.z < 0.99f )
- gmove->pos += downn * BSP_TRACE_EPSILON * 2.f;
+ gmove->pos += downn * BSP_TRACE_EPSILON;
gmove->velocity = downvel;
}
else {
+ // likely unnecessary but a sanity check
+ // avoid moving more than velocity per tick horizontally
VEC3 delta = up - pos;
- F32 dist = vec_len( delta );
- F32 speed = vec_len( gmove->velocity ) * TICK_INTERVAL;
+ F32 dist = vec_len2d( delta );
+ F32 speed = vec_len2d( gmove->velocity ) * TICK_INTERVAL;
if( dist > speed ) {
for( U32 i = 0; i < 2; ++i )
delta[i] *= speed / dist;
@@ -469,7 +504,11 @@ void gmove_step_move( VEC3 dest, BSP_TRACE* tr ) {
gmove->pos += delta;
if( tr->normal.z < 0.99f )
gmove->pos += tr->normal * BSP_TRACE_EPSILON * 2.f;
+ // hack : moving to a steeper slope, move up a bit to avoid getting stuck in the edge
+ if( gmove->ground && tr->normal.z < groundn )
+ gmove->pos.z += BSP_TRACE_EPSILON;
gmove->velocity = upvel;
+ gmove->velocity.z = downvel.z;
}
}
@@ -496,12 +535,13 @@ void gmove_walk_move() {
gmove->velocity[2] = 0;
speed = vec_len( gmove->velocity );
- defer( gmove_check_stuck( &gmove->pos ) );
if( speed < 1.f ) {
gmove->velocity = {};
+ gmove_check_stuck( &gmove->pos );
return;
}
+
VEC3 dest = gmove->pos + gmove->velocity * TICK_INTERVAL;
BSP_TRACE tr{};
bsp_trace( &tr, gmove->bsp, gmove->aabb, gmove->pos, dest );
@@ -509,6 +549,7 @@ void gmove_walk_move() {
defer( gmove_stay_on_ground() );
if( !tr.hit ) {
gmove->pos = dest;
+ gmove_check_stuck( &gmove->pos );
return;
}