NEON-29: fix step assist triggering on floor bumps (directional wall check)
The is_on_wall() short-circuits in _step_assist_has_support() and _step_assist_wallish_blocks() caused the assist to fire whenever the capsule touched any wall contact — including the sides of random floor bumps while crossing flat ground toward a distant elevated goal. After a 0.11 m lift, floor_snap_length = 0.09 m could not reach the original floor (0.11 m away) and _step_assist_active never cleared, so the capsule floated permanently. Fixes: - Remove is_on_wall() blanket short-circuit from both functions. - _step_assist_has_support() now takes want_dir_xz and accepts wall-ish contacts only when they oppose the direction of travel (dot < -0.2), i.e. genuine step faces, not sideways bump contacts. - _step_assist_wallish_blocks() relies solely on the directional collision loop (dot < -0.04); no is_on_wall() bypass. - _try_walk_step_assist() reordered to compute want before calling both functions so the same direction vector is used throughout. - Added "floating free" fallback: if _step_assist_active and no collisions and not on floor, clear the flag so FLOOR_SNAP_MOVING restores on the next tick. Applied to all three physics paths.pull/41/head
parent
453000d721
commit
1944eeafe8
|
|
@ -139,18 +139,33 @@ func snap_to_server(world_pos: Vector3) -> void:
|
|||
reset_physics_interpolation()
|
||||
|
||||
|
||||
func _step_assist_has_support() -> bool:
|
||||
if is_on_floor() or is_on_wall():
|
||||
## Returns true when the capsule has something to stand on **or** is pressing against a step face
|
||||
## in the direction of travel. `want_dir_xz` is the normalised horizontal goal direction.
|
||||
## Using `is_on_wall()` as a blanket short-circuit was too broad: any floor-bump side-contact
|
||||
## satisfied it, causing the assist to fire prematurely and then be unable to snap back.
|
||||
func _step_assist_has_support(want_dir_xz: Vector3) -> bool:
|
||||
if is_on_floor():
|
||||
return true
|
||||
var w2 := Vector2(want_dir_xz.x, want_dir_xz.z)
|
||||
var have_dir: bool = w2.length_squared() > 1e-8
|
||||
if have_dir:
|
||||
w2 = w2.normalized()
|
||||
for i: int in get_slide_collision_count():
|
||||
if get_slide_collision(i).get_normal().y > 0.35:
|
||||
return true
|
||||
var n: Vector3 = get_slide_collision(i).get_normal()
|
||||
if n.y > 0.35:
|
||||
return true # upward-facing = floor support
|
||||
# Wall-ish contact opposing forward direction = step face immediately ahead.
|
||||
if have_dir and abs(n.y) < 0.52:
|
||||
var n2 := Vector2(n.x, n.z)
|
||||
if n2.length_squared() > 1e-8 and n2.normalized().dot(w2) < -0.2:
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
## Returns true when slide collisions contain a wall-ish contact that opposes forward motion.
|
||||
## The `is_on_wall()` short-circuit was removed: it returned true for any wall contact regardless
|
||||
## of direction, firing the assist for sideways bump-skin contacts unrelated to step climbing.
|
||||
func _step_assist_wallish_blocks(want_dir_xz: Vector3) -> bool:
|
||||
if is_on_wall():
|
||||
return true
|
||||
var w2 := Vector2(want_dir_xz.x, want_dir_xz.z)
|
||||
if w2.length_squared() < 1e-8:
|
||||
return false
|
||||
|
|
@ -183,16 +198,17 @@ func _try_walk_step_assist() -> bool:
|
|||
var actual_feet_y: float = global_position.y - CAPSULE_HALF_HEIGHT - PLAYER_CAPSULE_RADIUS
|
||||
if _auth_walk_goal.y < actual_feet_y + 0.025:
|
||||
return false
|
||||
if not _step_assist_has_support():
|
||||
return false
|
||||
var pos: Vector3 = global_position
|
||||
var to_h: Vector3 = Vector3(_auth_walk_goal.x - pos.x, 0.0, _auth_walk_goal.z - pos.z)
|
||||
if to_h.length_squared() < 0.03:
|
||||
return false
|
||||
# Compute want direction before the support/blocking checks so both can use it.
|
||||
var want: Vector3 = to_h.normalized()
|
||||
var vel_h: Vector3 = Vector3(velocity.x, 0.0, velocity.z)
|
||||
if not _step_assist_wallish_blocks(want) or vel_h.dot(want) > WALK_STEP_ASSIST_MAX_FORWARD_DOT:
|
||||
return false
|
||||
if not _step_assist_has_support(want):
|
||||
return false
|
||||
# Target capsule centre once standing on the goal surface.
|
||||
var target_center_y: float = _auth_walk_goal.y + CAPSULE_HALF_HEIGHT + PLAYER_CAPSULE_RADIUS
|
||||
var lift: float = clampf(target_center_y - global_position.y, 0.0, WALK_STEP_ASSIST_DELTA)
|
||||
|
|
@ -545,7 +561,10 @@ func _physics_process(_delta: float) -> void:
|
|||
floor_snap_length = WALK_STEP_ASSIST_SNAP if _step_assist_active else FLOOR_SNAP_MOVING
|
||||
move_and_slide()
|
||||
_after_walk_move_and_slide()
|
||||
if _step_assist_active and is_on_floor() and not is_on_wall():
|
||||
if _step_assist_active and (
|
||||
(is_on_floor() and not is_on_wall())
|
||||
or (not is_on_floor() and get_slide_collision_count() == 0)
|
||||
):
|
||||
_step_assist_active = false
|
||||
_debug_trace_transform("physics")
|
||||
_snap_capsule_upright()
|
||||
|
|
@ -557,7 +576,10 @@ func _physics_process(_delta: float) -> void:
|
|||
floor_snap_length = FLOOR_SNAP_MOVING
|
||||
move_and_slide()
|
||||
_after_walk_move_and_slide()
|
||||
if _step_assist_active and is_on_floor() and not is_on_wall():
|
||||
if _step_assist_active and (
|
||||
(is_on_floor() and not is_on_wall())
|
||||
or (not is_on_floor() and get_slide_collision_count() == 0)
|
||||
):
|
||||
_step_assist_active = false
|
||||
_debug_trace_transform("physics")
|
||||
_snap_capsule_upright()
|
||||
|
|
@ -578,7 +600,13 @@ func _physics_process(_delta: float) -> void:
|
|||
floor_snap_length = WALK_STEP_ASSIST_SNAP if _step_assist_active else FLOOR_SNAP_MOVING
|
||||
move_and_slide()
|
||||
_after_walk_move_and_slide()
|
||||
if _step_assist_active and is_on_floor() and not is_on_wall():
|
||||
_step_assist_active = false
|
||||
if _step_assist_active:
|
||||
if is_on_floor() and not is_on_wall():
|
||||
# Landed cleanly on a surface — done climbing.
|
||||
_step_assist_active = false
|
||||
elif not is_on_floor() and get_slide_collision_count() == 0:
|
||||
# Floating free with no contacts: assist must have fired spuriously.
|
||||
# Clear the flag so FLOOR_SNAP_MOVING restores normal gravity next tick.
|
||||
_step_assist_active = false
|
||||
_debug_trace_transform("physics")
|
||||
_snap_capsule_upright()
|
||||
|
|
|
|||
Loading…
Reference in New Issue