NS-23: Arrival footing uses footprint max_y (avoid false stop on bump lip)
Premature arrival used _floor_y_under_body() vs dest footing; at the rim that can read floor while xz is already within ARRIVE_EPS, clearing the walk goal. Match step-down logic: compare destination footing to footprint max_y and cache footprint scan once per physics frame.pull/23/head
parent
003750c7ae
commit
8053f08804
|
|
@ -31,6 +31,8 @@ const NEXT_WAYPOINT_MIN_HORIZ_SQ: float = 0.01
|
||||||
|
|
||||||
var _has_walk_goal: bool = false
|
var _has_walk_goal: bool = false
|
||||||
var _auth_walk_goal: Vector3 = Vector3.ZERO
|
var _auth_walk_goal: Vector3 = Vector3.ZERO
|
||||||
|
var _footprint_cache_frame: int = -1
|
||||||
|
var _footprint_cache: Dictionary = {}
|
||||||
|
|
||||||
@onready var _nav_agent: NavigationAgent3D = $NavigationAgent3D
|
@onready var _nav_agent: NavigationAgent3D = $NavigationAgent3D
|
||||||
|
|
||||||
|
|
@ -94,7 +96,7 @@ func _floor_y_under_body() -> float:
|
||||||
|
|
||||||
|
|
||||||
## One ray pass: max floor Y under footprint + whether any hit is an NS-19 bump (`ns19_bump` group).
|
## One ray pass: max floor Y under footprint + whether any hit is an NS-19 bump (`ns19_bump` group).
|
||||||
func _footprint_step_down_state() -> Dictionary:
|
func _compute_footprint_step_down_state() -> Dictionary:
|
||||||
var p: Vector3 = global_position
|
var p: Vector3 = global_position
|
||||||
var h: float = STEP_FOOTPRINT_HALF
|
var h: float = STEP_FOOTPRINT_HALF
|
||||||
var oxz: Array[Vector3] = [
|
var oxz: Array[Vector3] = [
|
||||||
|
|
@ -140,6 +142,14 @@ func _footprint_step_down_state() -> Dictionary:
|
||||||
return {"max_y": best_y, "touches_ns19_bump": on_bump}
|
return {"max_y": best_y, "touches_ns19_bump": on_bump}
|
||||||
|
|
||||||
|
|
||||||
|
func _footprint_step_down_state() -> Dictionary:
|
||||||
|
var f: int = Engine.get_physics_frames()
|
||||||
|
if f != _footprint_cache_frame:
|
||||||
|
_footprint_cache = _compute_footprint_step_down_state()
|
||||||
|
_footprint_cache_frame = f
|
||||||
|
return _footprint_cache
|
||||||
|
|
||||||
|
|
||||||
## Footing under goal xz (surface Y). Server goal.y may be capsule center (e.g. 0.9) or pick surface
|
## Footing under goal xz (surface Y). Server goal.y may be capsule center (e.g. 0.9) or pick surface
|
||||||
## (e.g. 0) — do not compare that directly to `_floor_y_under_body()` (always surface).
|
## (e.g. 0) — do not compare that directly to `_floor_y_under_body()` (always surface).
|
||||||
func _destination_footing_y() -> float:
|
func _destination_footing_y() -> float:
|
||||||
|
|
@ -190,9 +200,12 @@ func _physics_process(_delta: float) -> void:
|
||||||
var full_to_goal: Vector3 = _auth_walk_goal - global_position
|
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 horiz_dist: float = Vector2(full_to_goal.x, full_to_goal.z).length()
|
||||||
var vert_err_capsule: float = absf(full_to_goal.y)
|
var vert_err_capsule: float = absf(full_to_goal.y)
|
||||||
var footing_match: bool = (
|
var dest_foot_y: float = _destination_footing_y()
|
||||||
absf(_floor_y_under_body() - _destination_footing_y()) <= VERT_ARRIVE_EPS
|
var fp: Dictionary = _footprint_step_down_state()
|
||||||
)
|
var max_foot_y: float = float(fp["max_y"])
|
||||||
|
# Same lip issue as step-off: `_floor_y_under_body()` can read floor early and match `dest_foot_y`
|
||||||
|
# while xz is within ARRIVE_EPS — false “arrived”, goal clears. Use footprint max_y.
|
||||||
|
var footing_match: bool = absf(max_foot_y - dest_foot_y) <= VERT_ARRIVE_EPS
|
||||||
if horiz_dist <= ARRIVE_EPS and (vert_err_capsule <= VERT_ARRIVE_EPS or footing_match):
|
if horiz_dist <= ARRIVE_EPS and (vert_err_capsule <= VERT_ARRIVE_EPS or footing_match):
|
||||||
velocity = Vector3.ZERO
|
velocity = Vector3.ZERO
|
||||||
_has_walk_goal = false
|
_has_walk_goal = false
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue