NS-24: Fix GDScript lint (line length, gdlint, gdformat)
- Shorten file-header and doc comments to satisfy max-line-length. - Rename bump collision preload const to BUMP_COLLISION_CONSTS_SCRIPT. - Refactor idle floor-angle and walk-step logic for return/format rules.pull/25/head
parent
7b11d4e238
commit
72897a4924
|
|
@ -3,7 +3,8 @@ extends Node3D
|
|||
## NS-16: composes ground pick + server authority; see `ground_pick.gd` /
|
||||
## `position_authority_client.gd`. NS-18: interaction POST + radius glow preview (see child nodes).
|
||||
## NS-23: bakes `NavigationRegion3D` on startup; boot snap vs nav goal from authority signal.
|
||||
## Prototype: two **random short bumps** (sibling `StaticBody3D` under `NavigationRegion3D`; see `random_floor_bumps.gd`) **before** nav bake.
|
||||
## Prototype: two random short bumps (sibling StaticBody3D under NavigationRegion3D; see
|
||||
## `random_floor_bumps.gd`) before nav bake.
|
||||
|
||||
const MOVE_REJECT_MSG_SECONDS: float = 4.0
|
||||
|
||||
|
|
|
|||
|
|
@ -1,66 +1,42 @@
|
|||
extends CharacterBody3D
|
||||
|
||||
## NS-23: Follow server move target on walkable geometry.
|
||||
## NS-24: Idle — **`velocity = 0`**, **`floor_snap_length = FLOOR_SNAP_IDLE`** (~**11 cm**), **`move_and_slide()`**
|
||||
## only. (Post-slide **ray Y lerp** was removed: on bump **rims** hit counts / spread can cross thresholds
|
||||
## frame-to-frame and **fight** the solver.) Walking snap **`FLOOR_SNAP_MOVING`**. **`snap_to_server`** calls
|
||||
## **`reset_physics_interpolation()`** when **`physics/common/physics_interpolation`** is on.
|
||||
## **`project.godot`:** **`physics/3d/physics_engine`** = **Jolt Physics**; **`physics/common/physics_interpolation`**
|
||||
## = **off** — when **on**, micro **position** changes on bump **rims** blend across frames and read as **ghosting / jitter**.
|
||||
## **`Player`** under **`World`**.
|
||||
## **Rendering (main.tscn / project):** curved default capsule + directional light → **specular highlight**
|
||||
## and **floor z-fight** often read as “jitter” even when `global_position` is stable — player uses
|
||||
## **no-specular** material, capsule mesh **Y** lift vs **`CapsuleShape3D`** (**z-fight** vs walkables), **no cast shadow** on mesh, **MSAA 3D**, **`light_specular=0`**.
|
||||
## **Timing:** **120** physics TPS. Jitter that vanishes at **2× run speed** points at **render vs physics** cadence.
|
||||
## NS-23 path-follow; NS-24 idle. Details in `client/README.md` (movement, idle).
|
||||
##
|
||||
## Horizontal velocity toward nav waypoint or goal only; `velocity.y` stays 0 while walking.
|
||||
## Move **legality** is server-only.
|
||||
##
|
||||
## Nav detours except when goal Y is below us: then xz toward goal (waypoints sit under bump rims).
|
||||
##
|
||||
## **Upright + floor angle (NS-24):** **`_snap_capsule_upright()`** each tick after motion — **`Transform3D(Basis.IDENTITY, pos)`**
|
||||
## so the capsule cannot **bank** on rim contacts. **`floor_max_angle`** is **looser while walking**; **stricter when idle** on
|
||||
## flat floor; **`_floor_angle_loose_ticks`** after a walk **stops**. **Rim / straddle idle:** **moving** `floor_max_angle` when
|
||||
## **`get_floor_normal()`** is **shallow** or **`_idle_ridged_floor_contacts()`** (slab + cylinder **edge**). After idle slide,
|
||||
## **`_maybe_idle_rim_settle_nudge()`** + **`_maybe_idle_bump_proximity_escape()`** (uses **`random_floor_bump_mesh`** group mesh radius vs
|
||||
## **`random_floor_bump_collision_constants.gd`** collision lip, including **cylinder wall** hug). Do **not** reset **`global_transform`** in **`_process`** — that can **desync**
|
||||
## **`CharacterBody3D`** from the physics/render path and read as **ghosting**. **`NavigationAgent3D.avoidance_enabled`** = **false**.
|
||||
## **`_try_walk_step_assist()`** — **Y nudge** when the nav goal is **higher**, **`test_move`** says there is **headroom**,
|
||||
## we have **support** (floor or slide normal with upward component), a **wall-ish** slide opposes **XZ** toward the goal,
|
||||
## and **horizontal motion** is **not** clearly advancing. A **second** **`move_and_slide()`** runs after a nudge to fix overlap
|
||||
## (avoids “floating” off the bump edge).
|
||||
## Summary: Jolt, no interp; dual floor_max_angle; rim/straddle, bump lip escape.
|
||||
## Snap upright after motion. Do not set global_transform in _process.
|
||||
## Walk assist may run a second move_and_slide().
|
||||
|
||||
const MOVE_SPEED: float = 5.0
|
||||
## `is_on_floor` / snap: **moving** — seam / curved-side transitions onto NS-19 bumps (~original 50°).
|
||||
## Moving: floor angle for seams onto stepped QA bumps (~50°).
|
||||
const FLOOR_MAX_ANGLE_MOVING_DEG: float = 50.0
|
||||
## **Idle** — tighter to reject **vertex / vertical-face** flicker when stably at rest.
|
||||
## Idle: tighter angle to reduce vertex / vertical-face flicker (~35°).
|
||||
const FLOOR_MAX_ANGLE_IDLE_DEG: float = 35.0
|
||||
## Physics ticks to keep **moving** floor angle after **`_has_walk_goal`** becomes false (arrival / clear).
|
||||
## Physics ticks to keep moving floor angle after walk goal clears (arrival).
|
||||
const FLOOR_ANGLE_LOOSE_TICKS_AFTER_STOP: int = 96
|
||||
const ARRIVE_EPS: float = 0.35
|
||||
const VERT_ARRIVE_EPS: float = 0.055
|
||||
const DIRECT_APPROACH_RADIUS: float = 0.85
|
||||
const FLOOR_SNAP_MOVING: float = 0.32
|
||||
## Idle snap — slightly **strong** to pin capsule on **rim** contacts without a second slide pass.
|
||||
## Idle floor snap length (stronger to pin rim contacts).
|
||||
const FLOOR_SNAP_IDLE: float = 0.11
|
||||
## Idle on a **rim**: if **`get_floor_normal().y`** dot world up is **below** this, use **moving** `floor_max_angle` for that tick.
|
||||
## Below this floor-normal dot up, idle tick uses **moving** `floor_max_angle` (rim).
|
||||
const IDLE_RIM_MIN_FLOOR_UP_DOT: float = 0.968
|
||||
## Per-tick horizontal pull when idle on a **rim** or **straddling** slab + bump (see **`_maybe_idle_rim_settle_nudge`**).
|
||||
## Horizontal nudge per tick for rim / straddle settle (**`_maybe_idle_rim_settle_nudge`**).
|
||||
const IDLE_RIM_SETTLE_STEP: float = 0.004
|
||||
const DESCEND_GOAL_Y_MARGIN: float = 0.06
|
||||
## Per-tick lift when **stuck** on a low vertical face while the nav goal is **higher** (NS-19 bump height ~0.15 m).
|
||||
## Y lift when blocked by wall-ish slide but nav goal is higher (stepped bumps).
|
||||
const WALK_STEP_ASSIST_DELTA: float = 0.11
|
||||
## If **`vel_h.dot(want) >` this**, we are making enough XZ progress — do not assist (corners may still slide slowly).
|
||||
## Skip assist when horizontal velocity already aligns enough with want-dir (corners slide slowly).
|
||||
const WALK_STEP_ASSIST_MAX_FORWARD_DOT: float = 0.52
|
||||
const WALK_STEP_ASSIST_COOLDOWN_TICKS: int = 8
|
||||
## Capsule **`height`** in **`main.tscn`** (**1.0**) → origin at **center**; feet ≈ **`y - 0.5`**.
|
||||
## Capsule height 1.0 in scene: origin at center, feet ~ **`y - 0.5`**.
|
||||
const CAPSULE_HALF_HEIGHT: float = 0.5
|
||||
const _random_floor_bump_collision: Script = preload(
|
||||
const BUMP_COLLISION_CONSTS_SCRIPT: Script = preload(
|
||||
"res://scripts/random_floor_bump_collision_constants.gd"
|
||||
)
|
||||
## Idle-only radial push off bump **lip** / **wall** (m/tick at **120** TPS).
|
||||
## Idle radial push per tick off bump lip / wall (meters; 120 Hz physics).
|
||||
const IDLE_BUMP_ESCAPE_STEP: float = 0.014
|
||||
## Player **`CapsuleShape3D.radius`** in **`main.tscn`** — wall contact can occur with axis distance **>** **`col_r`**.
|
||||
## Player capsule radius; wall touch can happen past axis distance **`col_r`**.
|
||||
const PLAYER_CAPSULE_RADIUS: float = 0.4
|
||||
|
||||
var _has_walk_goal: bool = false
|
||||
|
|
@ -138,9 +114,7 @@ func _step_assist_can_raise_by(dy: float) -> bool:
|
|||
|
||||
|
||||
func _try_walk_step_assist() -> bool:
|
||||
if not _has_walk_goal:
|
||||
return false
|
||||
if _auth_walk_goal.y < global_position.y + 0.025:
|
||||
if not _has_walk_goal or _auth_walk_goal.y < global_position.y + 0.025:
|
||||
return false
|
||||
if not _step_assist_has_support():
|
||||
return false
|
||||
|
|
@ -149,16 +123,12 @@ func _try_walk_step_assist() -> bool:
|
|||
if to_h.length_squared() < 0.03:
|
||||
return false
|
||||
var want: Vector3 = to_h.normalized()
|
||||
if not _step_assist_wallish_blocks(want):
|
||||
return false
|
||||
var vel_h: Vector3 = Vector3(velocity.x, 0.0, velocity.z)
|
||||
if vel_h.dot(want) > WALK_STEP_ASSIST_MAX_FORWARD_DOT:
|
||||
if not _step_assist_wallish_blocks(want) or vel_h.dot(want) > WALK_STEP_ASSIST_MAX_FORWARD_DOT:
|
||||
return false
|
||||
var lift: float = minf(WALK_STEP_ASSIST_DELTA, _auth_walk_goal.y - global_position.y + 0.45)
|
||||
lift = minf(lift, maxf(0.0, _auth_walk_goal.y + 0.55 - global_position.y))
|
||||
if lift <= 0.002:
|
||||
return false
|
||||
if not _step_assist_can_raise_by(lift):
|
||||
if lift <= 0.002 or not _step_assist_can_raise_by(lift):
|
||||
return false
|
||||
global_position.y += lift
|
||||
return true
|
||||
|
|
@ -206,8 +176,7 @@ func _maybe_idle_rim_settle_nudge() -> void:
|
|||
if get_slide_collision_count() < 1:
|
||||
return
|
||||
var shallow_floor: bool = (
|
||||
is_on_floor()
|
||||
and get_floor_normal().dot(Vector3.UP) < IDLE_RIM_MIN_FLOOR_UP_DOT
|
||||
is_on_floor() and get_floor_normal().dot(Vector3.UP) < IDLE_RIM_MIN_FLOOR_UP_DOT
|
||||
)
|
||||
if not shallow_floor and not _idle_ridged_floor_contacts():
|
||||
return
|
||||
|
|
@ -232,7 +201,7 @@ func _maybe_idle_rim_settle_nudge() -> void:
|
|||
func _maybe_idle_bump_proximity_escape() -> void:
|
||||
var feet_y: float = global_position.y - CAPSULE_HALF_HEIGHT
|
||||
for node: Node in get_tree().get_nodes_in_group(
|
||||
_random_floor_bump_collision.RANDOM_FLOOR_BUMP_MESH_GROUP
|
||||
BUMP_COLLISION_CONSTS_SCRIPT.RANDOM_FLOOR_BUMP_MESH_GROUP
|
||||
):
|
||||
if not node is MeshInstance3D:
|
||||
continue
|
||||
|
|
@ -245,8 +214,8 @@ func _maybe_idle_bump_proximity_escape() -> void:
|
|||
var r_mesh: float = cyl.top_radius
|
||||
var h: float = cyl.height
|
||||
var col_r: float = minf(
|
||||
r_mesh + _random_floor_bump_collision.COLLISION_RADIUS_EXTRA,
|
||||
_random_floor_bump_collision.COLLISION_RADIUS_MAX
|
||||
r_mesh + BUMP_COLLISION_CONSTS_SCRIPT.COLLISION_RADIUS_EXTRA,
|
||||
BUMP_COLLISION_CONSTS_SCRIPT.COLLISION_RADIUS_MAX
|
||||
)
|
||||
var dx: float = global_position.x - c.x
|
||||
var dz: float = global_position.z - c.z
|
||||
|
|
@ -266,11 +235,16 @@ func _maybe_idle_bump_proximity_escape() -> void:
|
|||
global_position += away
|
||||
return
|
||||
# On / above the disc, hugging the **visual** rim — step onto open slab.
|
||||
if feet_y >= bottom_y - 0.06 and feet_y <= top_y + 0.1 and d >= r_mesh * 0.86 and d <= r_mesh + 0.14:
|
||||
if (
|
||||
feet_y >= bottom_y - 0.06
|
||||
and feet_y <= top_y + 0.1
|
||||
and d >= r_mesh * 0.86
|
||||
and d <= r_mesh + 0.14
|
||||
):
|
||||
if not test_move(global_transform, away, null, safe_margin):
|
||||
global_position += away
|
||||
return
|
||||
# Floor beside **vertical** cylinder side: axis distance can exceed **`col_r`** while capsule still touches wall.
|
||||
# Beside vertical cylinder: axis distance may exceed **`col_r`** while capsule still touches wall.
|
||||
if (
|
||||
feet_y <= top_y + 0.14
|
||||
and d > r_mesh * 0.82
|
||||
|
|
@ -283,23 +257,18 @@ func _maybe_idle_bump_proximity_escape() -> void:
|
|||
|
||||
|
||||
func _snap_capsule_upright() -> void:
|
||||
# TODO(NS-24 follow-on): When the avatar has **facing yaw**, clear **pitch/roll** only — keep **Y** rotation;
|
||||
# full **`Basis.IDENTITY`** would erase look direction.
|
||||
# TODO(NS-24 follow-on): With facing yaw, clear pitch/roll only; keep Y rotation.
|
||||
# Full **`Basis.IDENTITY`** would erase look direction.
|
||||
var p: Vector3 = global_position
|
||||
global_transform = Transform3D(Basis.IDENTITY, p)
|
||||
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
var use_loose_floor_angle: bool = (
|
||||
_has_walk_goal or _floor_angle_loose_ticks > 0
|
||||
)
|
||||
if not _has_walk_goal and (
|
||||
(
|
||||
is_on_floor()
|
||||
and get_floor_normal().dot(Vector3.UP) < IDLE_RIM_MIN_FLOOR_UP_DOT
|
||||
)
|
||||
or _idle_ridged_floor_contacts()
|
||||
):
|
||||
var use_loose_floor_angle: bool = _has_walk_goal or _floor_angle_loose_ticks > 0
|
||||
if not _has_walk_goal:
|
||||
var floor_up_dot: float = get_floor_normal().dot(Vector3.UP)
|
||||
var shallow_idle_floor: bool = is_on_floor() and floor_up_dot < IDLE_RIM_MIN_FLOOR_UP_DOT
|
||||
if shallow_idle_floor or _idle_ridged_floor_contacts():
|
||||
use_loose_floor_angle = true
|
||||
floor_max_angle = deg_to_rad(
|
||||
FLOOR_MAX_ANGLE_MOVING_DEG if use_loose_floor_angle else FLOOR_MAX_ANGLE_IDLE_DEG
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
extends RefCounted
|
||||
|
||||
## Shared **`CylinderShape3D.radius`** fudge vs mesh for procedural **random floor QA bumps** (`random_floor_bumps.gd`).
|
||||
## Used by **`player.gd`** (idle lip escape). Change here only.
|
||||
## (Movement/step validation UX was originally tracked in Jira **NS-19** — not part of this script’s name.)
|
||||
## CylinderShape3D.radius fudge vs mesh for procedural QA bumps (spawned in random_floor_bumps.gd).
|
||||
## Used by `player.gd` (idle lip escape). Change here only.
|
||||
## (NS-19 tracked movement/step UX; unrelated to this script name.)
|
||||
|
||||
## **`MeshInstance3D.add_to_group`** for spawned bumps; **`player.gd`** queries this for proximity escape.
|
||||
## Group name for spawned bump meshes; `player.gd` queries it for proximity escape.
|
||||
const RANDOM_FLOOR_BUMP_MESH_GROUP: String = "random_floor_bump_mesh"
|
||||
|
||||
const COLLISION_RADIUS_EXTRA: float = 0.105
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
extends RefCounted
|
||||
|
||||
## Prototype QA: two short **cylinder** bumps, each on its own **`StaticBody3D`** **sibling** of **`Floor`** (same parent:
|
||||
## **`NavigationRegion3D`**). Avoids **compound internal edges** (floor box + cylinder on one body), which caused strong
|
||||
## idle jitter beside the bump. Meshes use group **`random_floor_bump_mesh`** (see **`random_floor_bump_collision_constants.gd`**). Loaded via **`main.gd`** **`load().call`**.
|
||||
## **Collision radius > mesh radius** (lip before visual rim); values in **`random_floor_bump_collision_constants.gd`**. Spawn **before** `NavigationRegion3D.bake_navigation_mesh()`.
|
||||
## Prototype QA: two short bumps on StaticBody3D siblings of Floor (same NavigationRegion3D parent).
|
||||
## Avoids one body with floor + cylinder (compound internal edges caused idle jitter beside bumps).
|
||||
## Bump mesh group and collision fudge: random_floor_bump_collision_constants.gd.
|
||||
## Spawner called from main.gd before nav bake.
|
||||
## Collision radius > mesh radius; spawn before `NavigationRegion3D.bake_navigation_mesh()`.
|
||||
|
||||
const _random_floor_bump_collision: Script = preload(
|
||||
const BUMP_COLLISION_CONSTS_SCRIPT: Script = preload(
|
||||
"res://scripts/random_floor_bump_collision_constants.gd"
|
||||
)
|
||||
|
||||
|
|
@ -20,6 +21,7 @@ const MIN_PAIR_SEPARATION: float = 2.85
|
|||
const MAX_PLACE_ATTEMPTS: int = 64
|
||||
const EXCLUSION_MARGIN: float = 0.72
|
||||
|
||||
|
||||
static func spawn_short_random_bumps(floor_node: StaticBody3D) -> void:
|
||||
var rng := RandomNumberGenerator.new()
|
||||
rng.randomize()
|
||||
|
|
@ -34,10 +36,7 @@ static func spawn_short_random_bumps(floor_node: StaticBody3D) -> void:
|
|||
var xz: Vector2 = Vector2.ZERO
|
||||
var ok := false
|
||||
for _a: int in MAX_PLACE_ATTEMPTS:
|
||||
xz = Vector2(
|
||||
rng.randf_range(-XZ_RANGE, XZ_RANGE),
|
||||
rng.randf_range(-XZ_RANGE, XZ_RANGE)
|
||||
)
|
||||
xz = Vector2(rng.randf_range(-XZ_RANGE, XZ_RANGE), rng.randf_range(-XZ_RANGE, XZ_RANGE))
|
||||
if _xz_in_exclusion(xz):
|
||||
continue
|
||||
var far_enough := true
|
||||
|
|
@ -50,7 +49,12 @@ static func spawn_short_random_bumps(floor_node: StaticBody3D) -> void:
|
|||
ok = true
|
||||
break
|
||||
if not ok:
|
||||
push_warning("RandomFloorBumps: could not place bump %d after %d tries" % [idx, MAX_PLACE_ATTEMPTS])
|
||||
push_warning(
|
||||
(
|
||||
"RandomFloorBumps: could not place bump %d after %d tries"
|
||||
% [idx, MAX_PLACE_ATTEMPTS]
|
||||
)
|
||||
)
|
||||
continue
|
||||
placed_xz.append(xz)
|
||||
var h: float = rng.randf_range(HEIGHT_MIN, HEIGHT_MAX)
|
||||
|
|
@ -99,7 +103,7 @@ static func _add_cylinder_bump(
|
|||
|
||||
var mesh_inst := MeshInstance3D.new()
|
||||
mesh_inst.name = "RandomTestBump%d_mesh" % idx
|
||||
mesh_inst.add_to_group(_random_floor_bump_collision.RANDOM_FLOOR_BUMP_MESH_GROUP)
|
||||
mesh_inst.add_to_group(BUMP_COLLISION_CONSTS_SCRIPT.RANDOM_FLOOR_BUMP_MESH_GROUP)
|
||||
var cm := CylinderMesh.new()
|
||||
cm.height = height
|
||||
cm.top_radius = radius
|
||||
|
|
@ -115,8 +119,8 @@ static func _add_cylinder_bump(
|
|||
var csh := CylinderShape3D.new()
|
||||
csh.height = height
|
||||
csh.radius = minf(
|
||||
radius + _random_floor_bump_collision.COLLISION_RADIUS_EXTRA,
|
||||
_random_floor_bump_collision.COLLISION_RADIUS_MAX
|
||||
radius + BUMP_COLLISION_CONSTS_SCRIPT.COLLISION_RADIUS_EXTRA,
|
||||
BUMP_COLLISION_CONSTS_SCRIPT.COLLISION_RADIUS_MAX
|
||||
)
|
||||
col.shape = csh
|
||||
col.position = Vector3.ZERO
|
||||
|
|
|
|||
Loading…
Reference in New Issue