NEON-29: Ledge peel via move_and_collide + fallback gravity

Direct global_position.y edits may not stick vs Jolt after move_and_slide.
Use move_and_collide for the peel step so motion goes through physics.

If get_gravity() is near zero, use -9.81 for peel, walk air, and idle air.
pull/41/head
VinPropane 2026-04-12 18:41:20 -04:00
parent fb1ac80fb0
commit a78b44263c
1 changed files with 16 additions and 4 deletions

View File

@ -85,6 +85,8 @@ const WALK_CONTINUATION_MAX_BELOW_FEET: float = 0.14
## ~0.42 m: **TerracePlatformB** top (~0.6 m) → floor (0) qualifies; **TerraceStepB** (~0.3 m) → floor does
## not — shallow drops still rely on [method _walk_has_close_floor_probe_below].
const WALK_DEEP_DESCENT_FEET_ABOVE_GOAL: float = 0.42
## [method get_gravity] can be ~0 with missing/odd project defaults; ledge peel + airborne walk still need a pull.
const WALK_FALLBACK_GRAVITY_Y: float = -9.81
## CapsuleShape3D in scene: height = 1.0 (cylinder portion), radius = 0.4.
## Total half-height from body origin to physical bottom = 0.5 + 0.4 = 0.9
## (`CAPSULE_HALF_HEIGHT + PLAYER_CAPSULE_RADIUS`).
@ -454,7 +456,7 @@ func _walk_has_close_floor_probe_below(move_dir_xz: Vector2) -> bool:
## velocity does **not** move the body off a terrace lip; use [method _apply_walk_post_slide_ledge_peel].
func _apply_walk_air_gravity(delta: float, _feet_y: float, _move_dir_xz: Vector2 = Vector2.ZERO) -> void:
if not is_on_floor():
velocity += get_gravity() * delta
velocity += _effective_gravity(delta) * delta
## After [method move_and_slide], peel the capsule down when the authoritative goal is below the feet
@ -479,8 +481,11 @@ func _apply_walk_post_slide_ledge_peel(
if not peel:
_walk_ledge_peel_vy = 0.0
return
_walk_ledge_peel_vy += get_gravity().y * delta
global_position.y += _walk_ledge_peel_vy * delta
_walk_ledge_peel_vy += _effective_gravity(delta).y * delta
var dy: float = _walk_ledge_peel_vy * delta
if absf(dy) > 1e-9:
# Raw [code]global_position[/code] edits can be ignored/overwritten vs Jolt sync after [method move_and_slide].
move_and_collide(Vector3(0.0, dy, 0.0), false, safe_margin, false)
func _walk_floor_snap_length(
@ -576,6 +581,13 @@ func _set_horizontal_velocity_from_nav_path_or_goal(fallback_goal_xz: Vector3) -
velocity.y = 0.0
func _effective_gravity(_delta: float) -> Vector3:
var g: Vector3 = get_gravity()
if g.length_squared() < 0.25:
return Vector3(0.0, WALK_FALLBACK_GRAVITY_Y, 0.0)
return g
static func capsule_feet_y(body_origin_y: float, capsule_half_height: float) -> float:
return body_origin_y - capsule_half_height
@ -595,7 +607,7 @@ func _physics_idle_tick(delta: float) -> void:
# cannot reach the lower floor — the capsule idles in mid-air until a new walk goal runs.
velocity.x = 0.0
velocity.z = 0.0
velocity += get_gravity() * delta
velocity += _effective_gravity(delta) * delta
floor_snap_length = FLOOR_SNAP_MOVING
move_and_slide()