feat: overhaul movement for flow — momentum-preserving states, smooth crouch, landing feel
- Quake-style air-strafe accelerate (real speed gain from strafing; external speed from dash/rockets never clamped) - Wall run: keeps entry momentum (incl. upward carry), accelerates along the wall instead of hard-setting velocity, gravity fades in over the run - Slide: slope physics (gravity projected along floor accelerates downhill), flat-ground decel instead of multiplicative friction, entry boost, direct slide->wallrun and slide->dash transitions - Dash: cooldown 10s -> 2s, per-player (was a static shared across instances), momentum fully kept on exit, FOV punch event - Grapple: taut pendulum with active rope control (W reels in, S pays out), release keeps swing energy - Wall climb: carries upward momentum in, jump-off kick, shared vault helper - Crouch capsule: single owner in the machine, smoothly lerped, ceiling check; camera eye height follows via crouch factor (no more head snapping) - Landing: machine emits 'land' events scaled by impact; camera dip + pitched down thud; footsteps get pitch variation - Camera rig: event-driven (land dip, dash FOV kick, vault pitch impulse), slide roll tilt - Model: Jump vs Fall split by vertical velocity, Land one-shot on heavy landings, wall-run body lean (synced to remotes via synced_wall_side) Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5
parent
c4a538a469
commit
0ba14a9469
@@ -74,6 +74,7 @@ var synced_is_crouching: bool = false
|
||||
var synced_position: Vector3 = Vector3.ZERO
|
||||
var synced_velocity: Vector3 = Vector3.ZERO
|
||||
var synced_is_ads: bool = false
|
||||
var synced_wall_side: float = 0.0 # -1 wall left, +1 wall right (wall-run lean)
|
||||
@export var synced_skin_id: String = ""
|
||||
@export var synced_weapon_path: String = ""
|
||||
|
||||
@@ -876,11 +877,14 @@ func _physics_process(_delta: float) -> void:
|
||||
if visual.has_method("set_locomotion"):
|
||||
var d := _local_move_dir()
|
||||
visual.set_locomotion(d.x, d.y, 1.0 if synced_is_ads else 0.0)
|
||||
if visual.has_method("set_wall_side"):
|
||||
visual.set_wall_side(sm.wall_side)
|
||||
|
||||
# Publish state for remote peers
|
||||
synced_movement_state = sm.current_state
|
||||
synced_movement_speed = Vector2(velocity.x, velocity.z).length()
|
||||
synced_is_crouching = sm.input_crouch
|
||||
synced_wall_side = sm.wall_side
|
||||
synced_position = position
|
||||
synced_velocity = velocity
|
||||
|
||||
@@ -914,6 +918,14 @@ func _on_movement_event(ev: String, data: Dictionary) -> void:
|
||||
grapple_shoot_player.play()
|
||||
elif ev == "grapple_latch":
|
||||
grapple_latch_player.play()
|
||||
elif ev == "land":
|
||||
# Landing thud: reuse the footstep sample, pitched down and louder
|
||||
# with impact. Ground state resets pitch/volume before each step.
|
||||
if footstep_player:
|
||||
var heavy: bool = data.get("heavy", false)
|
||||
footstep_player.pitch_scale = 0.55 if heavy else 0.7
|
||||
footstep_player.volume_db = 2.0 if heavy else -2.0
|
||||
footstep_player.play()
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
# Remote players: interpolate toward the owner's synced transform and
|
||||
@@ -946,6 +958,8 @@ func _process(delta: float) -> void:
|
||||
if visual.has_method("set_locomotion"):
|
||||
var d := _local_move_dir()
|
||||
visual.set_locomotion(d.x, d.y, 1.0 if synced_is_ads else 0.0)
|
||||
if visual.has_method("set_wall_side"):
|
||||
visual.set_wall_side(synced_wall_side)
|
||||
# Check for weapon changes
|
||||
if synced_weapon_path != "" and synced_weapon_path != visual.get_meta("current_weapon_path", ""):
|
||||
visual.set_weapon(synced_weapon_path)
|
||||
|
||||
Reference in New Issue
Block a user