NEON-29: Stable idle latch + Y anchor for approach treads
Hold latched zero-vel idle through STABLE_IDLE_UNLATCH_TICKS consecutive unstable readings so thin tread lips do not drop into corrective move_and_slide every other frame. Idle anchor now freezes Y as well as XZ. Reset latch on goal/snap/arrival; seed latch on arrival when support is stable after idle tick. Update hold_idle_anchor GdUnit expectation.pull/41/head
parent
ff6c337e1d
commit
8d9ad0ecd3
|
|
@ -32,6 +32,8 @@ const IDLE_RIM_MIN_FLOOR_UP_DOT: float = 0.968
|
|||
const STABLE_IDLE_FLOOR_MIN_UP_DOT: float = 0.999
|
||||
## Rare edge contacts can keep corrective nudges alive forever; budget them, then hold x/z.
|
||||
const IDLE_MANUAL_CORRECTION_MAX_TICKS: int = 8
|
||||
## Consecutive unstable-idle physics ticks before leaving latched stable idle (thin tread lip).
|
||||
const STABLE_IDLE_UNLATCH_TICKS: int = 2
|
||||
## Horizontal nudge per tick for rim / straddle settle (**`_maybe_idle_rim_settle_nudge`**).
|
||||
const IDLE_RIM_SETTLE_STEP: float = 0.004
|
||||
## Used by tests and vertical routing checks (feet vs goal surface).
|
||||
|
|
@ -77,6 +79,10 @@ var _step_assist_cooldown: int = 0
|
|||
var _step_assist_active: bool = false
|
||||
var _idle_anchor_active: bool = false
|
||||
var _idle_anchor_xz: Vector2 = Vector2.ZERO
|
||||
var _idle_anchor_y: float = 0.0
|
||||
## Latched stable idle: stay on zero-vel + anchor through brief Jolt false negatives on treads.
|
||||
var _idle_stable_latched: bool = false
|
||||
var _idle_stable_unlatch_streak: int = 0
|
||||
var _idle_manual_correction_ticks: int = 0
|
||||
var _debug_last_idle_xz: Vector2 = Vector2.INF
|
||||
var _debug_idle_heartbeat: int = 0
|
||||
|
|
@ -103,6 +109,8 @@ func set_authoritative_nav_goal(world_pos: Vector3) -> void:
|
|||
_step_assist_active = false
|
||||
_idle_anchor_active = false
|
||||
_idle_manual_correction_ticks = 0
|
||||
_idle_stable_latched = false
|
||||
_idle_stable_unlatch_streak = 0
|
||||
_walk_nav_column_steering = false
|
||||
_nav_agent.set_target_position(world_pos)
|
||||
|
||||
|
|
@ -114,6 +122,8 @@ func clear_nav_goal() -> void:
|
|||
_step_assist_active = false
|
||||
_idle_anchor_active = false
|
||||
_idle_manual_correction_ticks = 0
|
||||
_idle_stable_latched = false
|
||||
_idle_stable_unlatch_streak = 0
|
||||
_walk_nav_column_steering = false
|
||||
_nav_agent.set_target_position(global_position)
|
||||
|
||||
|
|
@ -151,6 +161,8 @@ func snap_to_server(world_pos: Vector3) -> void:
|
|||
_step_assist_active = false
|
||||
_idle_anchor_active = false
|
||||
_idle_manual_correction_ticks = 0
|
||||
_idle_stable_latched = false
|
||||
_idle_stable_unlatch_streak = 0
|
||||
_walk_nav_column_steering = false
|
||||
_nav_agent.set_target_position(settled)
|
||||
reset_physics_interpolation()
|
||||
|
|
@ -416,9 +428,10 @@ func _hold_idle_anchor() -> void:
|
|||
var pos := global_position
|
||||
if not _idle_anchor_active:
|
||||
_idle_anchor_xz = Vector2(pos.x, pos.z)
|
||||
_idle_anchor_y = pos.y
|
||||
_idle_anchor_active = true
|
||||
return
|
||||
global_position = Vector3(_idle_anchor_xz.x, pos.y, _idle_anchor_xz.y)
|
||||
global_position = Vector3(_idle_anchor_xz.x, _idle_anchor_y, _idle_anchor_xz.y)
|
||||
|
||||
|
||||
func _debug_trace_idle_state(tag: String) -> void:
|
||||
|
|
@ -624,7 +637,17 @@ func _physics_process(delta: float) -> void:
|
|||
)
|
||||
if not _has_walk_goal:
|
||||
floor_block_on_wall = true
|
||||
if _stable_idle_support():
|
||||
var raw_stable: bool = _stable_idle_support()
|
||||
if raw_stable:
|
||||
_idle_stable_unlatch_streak = 0
|
||||
_idle_stable_latched = true
|
||||
elif _idle_stable_latched:
|
||||
_idle_stable_unlatch_streak += 1
|
||||
if _idle_stable_unlatch_streak >= STABLE_IDLE_UNLATCH_TICKS:
|
||||
_idle_stable_latched = false
|
||||
_idle_stable_unlatch_streak = 0
|
||||
_idle_anchor_active = false
|
||||
if _idle_stable_latched:
|
||||
_idle_manual_correction_ticks = 0
|
||||
velocity = Vector3.ZERO
|
||||
floor_snap_length = FLOOR_SNAP_IDLE
|
||||
|
|
@ -685,10 +708,14 @@ func _physics_process(delta: float) -> void:
|
|||
_step_assist_active = false
|
||||
_idle_anchor_active = false
|
||||
_idle_manual_correction_ticks = 0
|
||||
_idle_stable_latched = false
|
||||
_idle_stable_unlatch_streak = 0
|
||||
_walk_nav_column_steering = false
|
||||
_nav_agent.set_target_position(global_position)
|
||||
_physics_idle_tick(delta)
|
||||
if _stable_idle_support():
|
||||
_idle_stable_latched = true
|
||||
_idle_stable_unlatch_streak = 0
|
||||
_idle_manual_correction_ticks = 0
|
||||
velocity = Vector3.ZERO
|
||||
floor_snap_length = FLOOR_SNAP_IDLE
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ func test_hold_idle_anchor_sets_anchor_first_then_clamps_xz() -> void:
|
|||
|
||||
p.global_position = Vector3(1.2, 0.7, 2.3)
|
||||
p.call("_hold_idle_anchor")
|
||||
assert_that(p.global_position).is_equal(Vector3(1.0, 0.7, 2.0))
|
||||
assert_that(p.global_position).is_equal(Vector3(1.0, 0.5, 2.0))
|
||||
|
||||
|
||||
func test_snap_to_server_clears_idle_anchor() -> void:
|
||||
|
|
|
|||
Loading…
Reference in New Issue