NEON-29: End column stair ghost-walk (arrive + stuck release).
Traces showed has_goal=true, vlat&&ncol, MOVE_SPEED XZ flipping while stable=false: vert_err ~0.31 stayed above VERT_ARRIVE_EPS so arrival never cleared the goal — not idle jitter. Run vertical-route latch before arrival; when on floor with vlat&&ncol, allow vert_err up to WALK_COLUMN_NEAR_ARRIVE_VERT (0.36 m) if horiz_dist <= ARRIVE_EPS. Backup: clear_nav_goal after WALK_COLUMN_STUCK_FRAMES with net drift < WALK_COLUMN_STUCK_MAX_DRIFT in the same regime.pull/41/head
parent
50a8b609be
commit
2333d29ece
|
|
@ -49,6 +49,15 @@ const WALK_TREAD_FREEZE_VERT_ERR_MAX: float = 0.18
|
|||
## alternate with full snap each tick (~y≈1.0 jitter). Require this many consecutive probe-fail frames
|
||||
## before arming peel/snap aggression; [member WALK_DEEP_DESCENT_FEET_ABOVE_GOAL] still arms immediately.
|
||||
const WALK_PEEL_PROBE_FALSE_FRAMES: int = 2
|
||||
## [member VERT_ARRIVE_EPS] is too tight on column stairs: feet oscillate ~±6 cm vs goal surface while XZ is
|
||||
## already inside [member ARRIVE_EPS] → never [code]has_goal=false[/code], full [member MOVE_SPEED] path
|
||||
## steer flips forever (looks like “idle” jitter; NEON-16 traces).
|
||||
const WALK_COLUMN_NEAR_ARRIVE_VERT: float = 0.36
|
||||
## If [code]vlat && ncol[/code] and net displacement stays below this for [member WALK_COLUMN_STUCK_FRAMES],
|
||||
## clear the walk goal — path lookahead limit cycle with no progress (backup if widened arrival is not enough).
|
||||
const WALK_COLUMN_STUCK_FRAMES: int = 28
|
||||
const WALK_COLUMN_STUCK_MAX_DRIFT: float = 0.045
|
||||
const WALK_COLUMN_STUCK_HORIZ_MAX: float = 0.68
|
||||
## Hysteresis for [code]needs_vertical_routing[/code]: [code]feet_y[/code] wobbles with
|
||||
## [code]move_and_slide[/code] on treads (~7 cm), so a single margin (see [member DESCEND_GOAL_Y_MARGIN])
|
||||
## can flip path vs direct steering every tick → velocity sign ping-pong while [code]has_goal[/code].
|
||||
|
|
@ -160,6 +169,8 @@ var _walk_ledge_peel_vy: float = 0.0
|
|||
var _walk_peel_no_probe_streak: int = 0
|
||||
## True after streak / deep-descent check; drives zero snap and [method _apply_walk_post_slide_ledge_peel].
|
||||
var _walk_debounced_wants_ledge_peel: bool = false
|
||||
var _walk_column_stuck_frame: int = 0
|
||||
var _walk_column_stuck_origin: Vector3 = Vector3.ZERO
|
||||
@onready var _nav_agent: NavigationAgent3D = $NavigationAgent3D
|
||||
|
||||
|
||||
|
|
@ -187,6 +198,7 @@ func set_authoritative_nav_goal(world_pos: Vector3) -> void:
|
|||
_walk_ledge_peel_vy = 0.0
|
||||
_walk_peel_no_probe_streak = 0
|
||||
_walk_debounced_wants_ledge_peel = false
|
||||
_walk_column_stuck_frame = 0
|
||||
_nav_agent.set_target_position(world_pos)
|
||||
|
||||
|
||||
|
|
@ -205,6 +217,7 @@ func clear_nav_goal() -> void:
|
|||
_walk_vert_route_latched = false
|
||||
_walk_peel_no_probe_streak = 0
|
||||
_walk_debounced_wants_ledge_peel = false
|
||||
_walk_column_stuck_frame = 0
|
||||
_nav_agent.set_target_position(global_position)
|
||||
|
||||
|
||||
|
|
@ -494,6 +507,29 @@ func _apply_walk_air_gravity(delta: float, _feet_y: float, _move_dir_xz: Vector2
|
|||
velocity += _player_vertical_accel(delta) * delta
|
||||
|
||||
|
||||
func _walk_try_release_column_stuck_orbit(horiz_dist: float) -> bool:
|
||||
if not _has_walk_goal or not is_on_floor():
|
||||
_walk_column_stuck_frame = 0
|
||||
return false
|
||||
if not (_walk_vert_route_latched and _walk_nav_column_steering):
|
||||
_walk_column_stuck_frame = 0
|
||||
return false
|
||||
if horiz_dist > WALK_COLUMN_STUCK_HORIZ_MAX:
|
||||
_walk_column_stuck_frame = 0
|
||||
return false
|
||||
if _walk_column_stuck_frame == 0:
|
||||
_walk_column_stuck_origin = global_position
|
||||
_walk_column_stuck_frame += 1
|
||||
if _walk_column_stuck_frame < WALK_COLUMN_STUCK_FRAMES:
|
||||
return false
|
||||
var drift: float = global_position.distance_to(_walk_column_stuck_origin)
|
||||
_walk_column_stuck_frame = 0
|
||||
if drift > WALK_COLUMN_STUCK_MAX_DRIFT:
|
||||
return false
|
||||
clear_nav_goal()
|
||||
return true
|
||||
|
||||
|
||||
func _walk_peel_suspend_near_goal(feet_y: float, horiz_dist: float) -> bool:
|
||||
var vsep: float = absf(_auth_walk_goal.y - feet_y)
|
||||
if _walk_vert_route_latched and _walk_nav_column_steering and vsep < WALK_PEEL_SUSPEND_VERT_SEP:
|
||||
|
|
@ -1057,15 +1093,33 @@ func _physics_process(delta: float) -> void:
|
|||
var full_to_goal: Vector3 = _auth_walk_goal - global_position
|
||||
var horiz_dist: float = Vector2(full_to_goal.x, full_to_goal.z).length()
|
||||
var want_goal_h: Vector3 = Vector3(full_to_goal.x, 0.0, full_to_goal.z)
|
||||
# Use actual capsule bottom (CAPSULE_HALF_HEIGHT + PLAYER_CAPSULE_RADIUS = 0.9) so that a
|
||||
# step-surface goal (e.g. Y=0.3) is never considered "arrived" while the player is still at
|
||||
# floor height. Using only CAPSULE_HALF_HEIGHT (0.5) gives code-feet at Y=0.4, which is too
|
||||
# close to step surfaces and causes premature arrival when Jolt nudges the body down to ~0.8
|
||||
# while the capsule hemisphere contacts the step edge.
|
||||
# Feet + vertical routing **before** arrival: column stair oscillation keeps [code]vert_err[/code]
|
||||
# above [member VERT_ARRIVE_EPS] while XZ is already inside [member ARRIVE_EPS] — widen vertical
|
||||
# tolerance only for [code]vlat && ncol[/code] on floor (see [member WALK_COLUMN_NEAR_ARRIVE_VERT]).
|
||||
var feet_y: float = capsule_feet_y(
|
||||
global_position.y, CAPSULE_HALF_HEIGHT + PLAYER_CAPSULE_RADIUS
|
||||
)
|
||||
var vert_sep: float = absf(_auth_walk_goal.y - feet_y)
|
||||
if not _walk_vert_route_latched:
|
||||
if vert_sep > WALK_VERT_ROUTE_LATCH_ON_SEP:
|
||||
_walk_vert_route_latched = true
|
||||
else:
|
||||
if vert_sep < WALK_VERT_ROUTE_LATCH_OFF_SEP:
|
||||
_walk_vert_route_latched = false
|
||||
var needs_vertical_routing: bool = _walk_vert_route_latched
|
||||
if not needs_vertical_routing:
|
||||
_walk_nav_column_steering = false
|
||||
elif horiz_dist <= NAV_COLUMN_STEER_ENTER_DIST:
|
||||
_walk_nav_column_steering = true
|
||||
elif horiz_dist >= NAV_COLUMN_STEER_EXIT_DIST:
|
||||
_walk_nav_column_steering = false
|
||||
var vert_err: float = vertical_arrival_error(
|
||||
_auth_walk_goal.y, global_position.y, CAPSULE_HALF_HEIGHT + PLAYER_CAPSULE_RADIUS
|
||||
)
|
||||
if horiz_dist <= ARRIVE_EPS and vert_err <= VERT_ARRIVE_EPS:
|
||||
var vert_ok: float = VERT_ARRIVE_EPS
|
||||
if is_on_floor() and _walk_vert_route_latched and _walk_nav_column_steering:
|
||||
vert_ok = maxf(VERT_ARRIVE_EPS, WALK_COLUMN_NEAR_ARRIVE_VERT)
|
||||
if horiz_dist <= ARRIVE_EPS and vert_err <= vert_ok:
|
||||
velocity = Vector3.ZERO
|
||||
_has_walk_goal = false
|
||||
_walk_ledge_peel_vy = 0.0
|
||||
|
|
@ -1101,31 +1155,22 @@ func _physics_process(delta: float) -> void:
|
|||
_snap_capsule_upright()
|
||||
return
|
||||
|
||||
if _walk_try_release_column_stuck_orbit(horiz_dist):
|
||||
floor_block_on_wall = true
|
||||
_floor_angle_loose_ticks = FLOOR_ANGLE_LOOSE_TICKS_AFTER_STOP
|
||||
_physics_idle_tick(delta)
|
||||
_debug_trace_transform("physics")
|
||||
_snap_capsule_upright()
|
||||
return
|
||||
|
||||
_idle_manual_correction_ticks = 0
|
||||
|
||||
var feet_y: float = capsule_feet_y(
|
||||
global_position.y, CAPSULE_HALF_HEIGHT + PLAYER_CAPSULE_RADIUS
|
||||
)
|
||||
_apply_floor_block_for_descend_at_wall(feet_y)
|
||||
|
||||
# Horizontal motion toward the **authoritative** click target (XZ) by default. Use the baked
|
||||
# path only when vertical routing is latched **and** column hysteresis says so **and** we are
|
||||
# on floor — mid-air column steering flips XZ velocity each tick against `move_and_slide`
|
||||
# (NEON-16: `on_floor=false` + `vlat && ncol` while falling).
|
||||
var vert_sep: float = absf(_auth_walk_goal.y - feet_y)
|
||||
if not _walk_vert_route_latched:
|
||||
if vert_sep > WALK_VERT_ROUTE_LATCH_ON_SEP:
|
||||
_walk_vert_route_latched = true
|
||||
else:
|
||||
if vert_sep < WALK_VERT_ROUTE_LATCH_OFF_SEP:
|
||||
_walk_vert_route_latched = false
|
||||
var needs_vertical_routing: bool = _walk_vert_route_latched
|
||||
if not needs_vertical_routing:
|
||||
_walk_nav_column_steering = false
|
||||
elif horiz_dist <= NAV_COLUMN_STEER_ENTER_DIST:
|
||||
_walk_nav_column_steering = true
|
||||
elif horiz_dist >= NAV_COLUMN_STEER_EXIT_DIST:
|
||||
_walk_nav_column_steering = false
|
||||
if needs_vertical_routing and _walk_nav_column_steering and is_on_floor():
|
||||
_set_horizontal_velocity_from_nav_path_or_goal(want_goal_h)
|
||||
else:
|
||||
|
|
|
|||
Loading…
Reference in New Issue