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
@@ -1,28 +1,22 @@
|
||||
extends Node
|
||||
class_name StateDash
|
||||
|
||||
## Short burst dash. Cooldown lives on the machine (per-player instance) and is
|
||||
## checked by the states that enter dash, so entering this state always dashes.
|
||||
## Momentum is fully preserved on exit — the dash ADDS speed to your run.
|
||||
|
||||
var machine: MovementStateMachine
|
||||
var params: MovementParams:
|
||||
get: return machine.params
|
||||
|
||||
var elapsed: float = 0.0
|
||||
var direction: Vector3 = Vector3.ZERO
|
||||
var _exit_speed: float = 0.0
|
||||
var _last_vel: Vector3 = Vector3.ZERO
|
||||
|
||||
# Cooldown tracked across dash instances
|
||||
static var _last_dash_time: float = -999.0
|
||||
var _dash_speed: float = 0.0
|
||||
|
||||
|
||||
func enter(_data: Dictionary = {}) -> void:
|
||||
# Check cooldown
|
||||
var now := Time.get_ticks_msec() / 1000.0
|
||||
if now - _last_dash_time < params.dash_cooldown:
|
||||
machine.switch_to("air")
|
||||
return
|
||||
|
||||
elapsed = 0.0
|
||||
_last_dash_time = now
|
||||
machine.dash_cooldown_timer = params.dash_cooldown
|
||||
|
||||
var player := machine.player
|
||||
if player.dash_player:
|
||||
@@ -38,55 +32,49 @@ func enter(_data: Dictionary = {}) -> void:
|
||||
direction = direction.normalized()
|
||||
|
||||
machine.register_chain_mechanic("dash")
|
||||
|
||||
machine.movement_event.emit("dash", {})
|
||||
|
||||
var current_hvel := Vector3(machine.player.velocity.x, 0.0, machine.player.velocity.z)
|
||||
var current_speed := current_hvel.length()
|
||||
var proj := current_hvel.dot(direction)
|
||||
|
||||
|
||||
var base_dash_speed = machine.get_effective_speed(params.dash_speed)
|
||||
|
||||
|
||||
if proj >= 0.0:
|
||||
# Dashing forward or diagonally forward: add base dash speed to the projected speed
|
||||
_exit_speed = proj + base_dash_speed
|
||||
_dash_speed = proj + base_dash_speed
|
||||
else:
|
||||
# Dashing backward or diagonally backward:
|
||||
# Reflect current momentum into the new direction, smoothly scaling from base_dash_speed (at sideways) to current_speed (at exactly backward).
|
||||
# Reflect current momentum into the new direction, smoothly scaling from
|
||||
# base_dash_speed (at sideways) to current_speed (at exactly backward).
|
||||
var backward_factor = -proj / current_speed if current_speed > 0.001 else 0.0
|
||||
_exit_speed = lerpf(base_dash_speed, maxf(current_speed, base_dash_speed), backward_factor)
|
||||
|
||||
machine.player.velocity = direction * _exit_speed
|
||||
_dash_speed = lerpf(base_dash_speed, maxf(current_speed, base_dash_speed), backward_factor)
|
||||
|
||||
machine.player.velocity = direction * _dash_speed
|
||||
machine.on_ground = false
|
||||
_last_vel = machine.player.velocity
|
||||
|
||||
|
||||
func exit() -> void:
|
||||
# Preserve dash velocity on exit (don't cut speed abruptly)
|
||||
pass
|
||||
|
||||
|
||||
func update(delta: float) -> void:
|
||||
elapsed += delta
|
||||
var player := machine.player
|
||||
|
||||
if elapsed > params.dash_duration:
|
||||
machine.player.velocity = direction * _exit_speed * 0.85
|
||||
if machine.player.is_on_floor():
|
||||
# Keep the full dash velocity — the dash is a speed investment
|
||||
player.velocity = direction * _dash_speed
|
||||
if player.is_on_floor():
|
||||
machine.on_ground = true
|
||||
machine.switch_to("ground")
|
||||
else:
|
||||
machine.switch_to("air")
|
||||
return
|
||||
|
||||
# Maintain dash velocity
|
||||
var player := machine.player
|
||||
var vel: Vector3 = player.velocity
|
||||
|
||||
if vel.distance_squared_to(_last_vel) > 100.0:
|
||||
machine.switch_to("air")
|
||||
return
|
||||
|
||||
vel = direction * _exit_speed
|
||||
# Maintain dash velocity, flat trajectory
|
||||
var vel := direction * _dash_speed
|
||||
if player.is_on_floor():
|
||||
vel.y = -0.5 # Snap to floor to handle ramps
|
||||
|
||||
player.velocity = vel
|
||||
player.move_and_slide()
|
||||
_last_vel = player.velocity
|
||||
|
||||
Reference in New Issue
Block a user