NS-23: simplify client movement — horizontal only, no bump nav hacks
Replace stacked NS-19 workarounds (underfoot rays, plateau nav skip, 3D climb/descent steering, rim escape) with one rule: set horizontal velocity toward waypoint/goal, force velocity.y = 0, move_and_slide + floor_* handle height along geometry. Server MoveCommand remains the single place for allow/deny on illegal steps.pull/23/head
parent
2291a0ec07
commit
b8176f8fa1
|
|
@ -1,28 +1,17 @@
|
|||
extends CharacterBody3D
|
||||
|
||||
## NS-23: Nav waypoints + stored server goal for arrival.
|
||||
## NS-19: any underfoot ray into `ns19_bump` → skip nav (waypoints); bumps are small vs obstacles.
|
||||
## NS-23: Follow server move target on walkable geometry.
|
||||
##
|
||||
## Horizontal velocity toward nav waypoint or goal only; `velocity.y` stays 0. Height along ramps
|
||||
## and steps comes from `move_and_slide` + floor_* on CharacterBody3D. Move **legality** (step,
|
||||
## distance, bounds) is server MoveCommand only — not reimplemented here.
|
||||
##
|
||||
## NavigationAgent3D detours obstacles; steering uses target **xz** only.
|
||||
|
||||
const MOVE_SPEED: float = 5.0
|
||||
const ARRIVE_EPS: float = 0.35
|
||||
## Must be **below** NS-19 bump rise (~0.12–0.15) or we "arrive" while still on the plateau when the
|
||||
## goal is on the floor beside the bump (small horiz offset + ~0.15 m vertical).
|
||||
const VERT_ARRIVE_EPS: float = 0.055
|
||||
const MAX_CLIMB_SPEED: float = 2.6
|
||||
const MAX_DESCENT_SPEED: float = 2.2
|
||||
const DIRECT_APPROACH_RADIUS: float = 0.85
|
||||
const NS19_RAY_DOWN: float = 3.0
|
||||
## Origins (world-space offset from body) before casting down. Wider xz helps the 1 m Bump A rim
|
||||
## where a single vertical line can clear the frustum; Bump B stays covered too.
|
||||
const NS19_UNDERFOOT_OFFSETS: Array[Vector3] = [
|
||||
Vector3(0, 0, 0),
|
||||
Vector3(0, -0.45, 0),
|
||||
Vector3(0, -0.82, 0),
|
||||
Vector3(0.42, -0.28, 0),
|
||||
Vector3(-0.42, -0.28, 0),
|
||||
Vector3(0, -0.28, 0.42),
|
||||
Vector3(0, -0.28, -0.42),
|
||||
]
|
||||
|
||||
var _has_walk_goal: bool = false
|
||||
var _auth_walk_goal: Vector3 = Vector3.ZERO
|
||||
|
|
@ -53,57 +42,13 @@ func snap_to_server(world_pos: Vector3) -> void:
|
|||
_nav_agent.set_target_position(world_pos)
|
||||
|
||||
|
||||
func _should_skip_nav_for_ns19_bump() -> bool:
|
||||
for off: Vector3 in NS19_UNDERFOOT_OFFSETS:
|
||||
if _ns19_bump_under_ray(global_position + off):
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func _ns19_bump_under_ray(from: Vector3) -> bool:
|
||||
var space: PhysicsDirectSpaceState3D = get_world_3d().direct_space_state
|
||||
var to: Vector3 = from + Vector3(0.0, -NS19_RAY_DOWN, 0.0)
|
||||
var q: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(from, to)
|
||||
q.collision_mask = 1
|
||||
q.exclude = [get_rid()]
|
||||
var hit: Dictionary = space.intersect_ray(q)
|
||||
if hit.is_empty():
|
||||
return false
|
||||
var col: Variant = hit.get("collider")
|
||||
var n: Node = col as Node
|
||||
while n:
|
||||
if n.is_in_group("ns19_bump"):
|
||||
return true
|
||||
n = n.get_parent()
|
||||
return false
|
||||
|
||||
|
||||
func _steer_toward_world_point(point: Vector3) -> void:
|
||||
func _set_horizontal_velocity_toward(point: Vector3) -> void:
|
||||
var pos := global_position
|
||||
var delta_h: Vector3 = Vector3(point.x - pos.x, 0.0, point.z - pos.z)
|
||||
# Full 3D toward a waypoint that is mostly *below* (same xz, on the slope) while standing on
|
||||
# the plateau yields almost no horizontal speed, so you never reach the rim. Nav in xz + floor
|
||||
# slide handles ramps and departure from bump tops.
|
||||
if delta_h.length_squared() > 1e-8:
|
||||
velocity = delta_h.normalized() * MOVE_SPEED
|
||||
return
|
||||
var dy: float = point.y - pos.y
|
||||
if dy > 0.08:
|
||||
var delta: Vector3 = point - pos
|
||||
if delta.length_squared() < 1e-8:
|
||||
velocity = Vector3.ZERO
|
||||
return
|
||||
var desired: Vector3 = delta.normalized() * MOVE_SPEED
|
||||
desired.y = clampf(desired.y, -MAX_DESCENT_SPEED, MAX_CLIMB_SPEED)
|
||||
velocity = desired
|
||||
elif dy < 0.0:
|
||||
# Same xz, goal slightly lower (e.g. -0.03): old threshold left velocity at zero (“hang”).
|
||||
var escape_h := Vector3(-global_transform.basis.z.x, 0.0, -global_transform.basis.z.z)
|
||||
if escape_h.length_squared() < 1e-8:
|
||||
escape_h = Vector3(1.0, 0.0, 0.0)
|
||||
velocity = escape_h.normalized() * MOVE_SPEED
|
||||
else:
|
||||
velocity = Vector3.ZERO
|
||||
var dh: Vector3 = Vector3(point.x - pos.x, 0.0, point.z - pos.z)
|
||||
if dh.length_squared() < 1e-10:
|
||||
dh = Vector3(1.0, 0.0, 0.0)
|
||||
velocity = dh.normalized() * MOVE_SPEED
|
||||
velocity.y = 0.0
|
||||
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
|
|
@ -122,31 +67,22 @@ func _physics_process(_delta: float) -> void:
|
|||
move_and_slide()
|
||||
return
|
||||
|
||||
# Waypoints route around obstacles; steering stays horizontal-only (see _steer_toward_world_point)
|
||||
# so bump plateaus do not get a mostly-vertical first segment. If next waypoint aligns under the
|
||||
# player (small xz delta), fall back to steering toward the goal xz.
|
||||
var nav_map: RID = _nav_agent.get_navigation_map()
|
||||
if NavigationServer3D.map_get_iteration_id(nav_map) == 0:
|
||||
_steer_toward_world_point(_auth_walk_goal)
|
||||
move_and_slide()
|
||||
return
|
||||
|
||||
# On bump: skip nav waypoints (drop-first paths); bump area is small vs the obstacle.
|
||||
if _should_skip_nav_for_ns19_bump():
|
||||
_steer_toward_world_point(_auth_walk_goal)
|
||||
_set_horizontal_velocity_toward(_auth_walk_goal)
|
||||
move_and_slide()
|
||||
return
|
||||
|
||||
if horiz_dist <= DIRECT_APPROACH_RADIUS:
|
||||
_steer_toward_world_point(_auth_walk_goal)
|
||||
_set_horizontal_velocity_toward(_auth_walk_goal)
|
||||
else:
|
||||
var next_path_position: Vector3 = _nav_agent.get_next_path_position()
|
||||
var to_next_h: Vector3 = Vector3(
|
||||
next_path_position.x - global_position.x, 0.0, next_path_position.z - global_position.z
|
||||
)
|
||||
if to_next_h.length_squared() > 0.0025:
|
||||
_steer_toward_world_point(next_path_position)
|
||||
_set_horizontal_velocity_toward(next_path_position)
|
||||
else:
|
||||
_steer_toward_world_point(_auth_walk_goal)
|
||||
_set_horizontal_velocity_toward(_auth_walk_goal)
|
||||
|
||||
move_and_slide()
|
||||
|
|
|
|||
Loading…
Reference in New Issue