140 lines
4.7 KiB
GDScript
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
|