extends Node class_name StateDash 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 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 var player := machine.player if player.dash_player: player.dash_player.play() # Direction: use wish direction if available, else player forward var wish := machine.wish_dir_world if wish.length_squared() > 0.01: direction = wish.normalized() else: direction = -machine.player.global_transform.basis.z direction.y = 0.0 direction = direction.normalized() machine.register_chain_mechanic("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 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). 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 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 if elapsed > params.dash_duration: machine.player.velocity = direction * _exit_speed * 0.85 if machine.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 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