Files
Papay-Shooter/movement/states/state_slide.gd
T

140 lines
4.7 KiB
GDScript

extends Node
class_name StateSlide
var machine: MovementStateMachine
var params: MovementParams:
get: return machine.params
var elapsed: float = 0.0
var _saved_capsule_height: float = 0.0
var _slide_direction: Vector3 = Vector3.ZERO
func enter(_data: Dictionary = {}) -> void:
elapsed = 0.0
machine.register_chain_mechanic("slide")
if machine.player.slide_player and not machine.player.slide_player.playing:
machine.player.slide_player.play()
# Save original capsule height and halve it
var shape: CapsuleShape3D = _get_capsule()
if shape:
_saved_capsule_height = shape.height
shape.height = _saved_capsule_height * 0.5
# Slide in the direction of current velocity (momentum-based)
var hvel := Vector3(machine.player.velocity.x, 0.0, machine.player.velocity.z)
if hvel.length_squared() > 0.01:
_slide_direction = hvel.normalized()
else:
# Fallback: player forward
_slide_direction = -machine.player.global_transform.basis.z
_slide_direction.y = 0.0
_slide_direction = _slide_direction.normalized()
# Set initial slide velocity
var slide_speed := maxf(hvel.length(), params.slide_speed)
machine.player.velocity.x = _slide_direction.x * machine.get_effective_speed(slide_speed)
machine.player.velocity.z = _slide_direction.z * machine.get_effective_speed(slide_speed)
func exit() -> void:
machine.slide_cooldown_timer = params.slide_cooldown
if machine.player.slide_player:
machine.player.slide_player.stop()
# Restore original capsule height
var shape: CapsuleShape3D = _get_capsule()
if shape and _saved_capsule_height > 0.0:
shape.height = _saved_capsule_height
func update(delta: float) -> void:
elapsed += delta
var player := machine.player
if player.slide_player and not player.slide_player.playing:
player.slide_player.play()
var vel: Vector3 = player.velocity
# ── Apply friction to horizontal velocity ─────────────────────────────
vel.x *= pow(params.slide_friction, delta * 10.0)
vel.z *= pow(params.slide_friction, delta * 10.0)
# ── Allow slight steering ─────────────────────────────────────────────
var wish_dir := machine.wish_dir_world
if wish_dir.length_squared() > 0.01:
wish_dir = wish_dir.normalized()
var hvel := Vector3(vel.x, 0.0, vel.z)
var current_speed := hvel.length()
# Slowly bend velocity towards wish_dir
var steer_speed = 3.0 * delta
var new_hvel = hvel.lerp(wish_dir * current_speed, steer_speed)
vel.x = new_hvel.x
vel.z = new_hvel.z
if new_hvel.length_squared() > 0.01:
_slide_direction = new_hvel.normalized()
# ── Gravity (for slopes) ──────────────────────────────────────────────
if not player.is_on_floor():
vel.y -= params.gravity * delta
else:
vel.y = -2.0 # Strong floor snap
player.velocity = vel
player.move_and_slide()
# ── Update ground status ──────────────────────────────────────────────
if player.is_on_floor():
machine.on_ground = true
machine.current_jump_count = 0
else:
machine.on_ground = false
# ── End conditions ────────────────────────────────────────────────────
var hspeed := Vector3(player.velocity.x, 0.0, player.velocity.z).length()
# Slide ended: too slow
if hspeed < params.slide_min_speed:
machine.switch_to("ground")
return
# Player released crouch
if not machine.input_crouch:
machine.switch_to("ground")
return
# Fell off edge
if not machine.on_ground and machine.coyote_timer <= 0.0:
machine.switch_to("air")
return
# Jump out of slide
if machine.input_jump_just_pressed and machine.jump_cooldown_timer <= 0.0:
player.velocity.y = params.jump_velocity
var hvel := Vector3(player.velocity.x, 0.0, player.velocity.z)
if hvel.length_squared() > 0.01:
var dir := hvel.normalized()
var current_speed := hvel.length()
var jump_speed := maxf(current_speed, minf(current_speed + params.slide_jump_speed_boost, params.bunny_hop_speed_cap))
player.velocity.x = dir.x * jump_speed
player.velocity.z = dir.z * jump_speed
machine.current_jump_count = 1
machine.jump_cooldown_timer = params.jump_cooldown
machine.on_ground = false
machine.register_chain_mechanic("slide_jump")
machine.switch_to("air")
return
func _get_capsule() -> CapsuleShape3D:
for child in machine.player.get_children():
if child is CollisionShape3D and child.shape is CapsuleShape3D:
return child.shape as CapsuleShape3D
return null