87 lines
2.8 KiB
GDScript
87 lines
2.8 KiB
GDScript
extends Node
|
|
class_name StateGrapple
|
|
|
|
var machine: MovementStateMachine
|
|
var params: MovementParams:
|
|
get: return machine.params
|
|
|
|
func enter(_data: Dictionary = {}) -> void:
|
|
machine.on_ground = false
|
|
machine.wall_normal = Vector3.ZERO
|
|
machine.wall_side = 0.0
|
|
machine.register_chain_mechanic("grapple")
|
|
|
|
func exit() -> void:
|
|
pass
|
|
|
|
func update(delta: float) -> void:
|
|
var player := machine.player
|
|
var vel: Vector3 = player.velocity
|
|
|
|
# If player releases the button, disconnect
|
|
if not machine.input_grapple:
|
|
machine.switch_to("air")
|
|
return
|
|
|
|
var grapple_pos: Vector3 = machine.grapple_point
|
|
var current_dist: float = player.global_position.distance_to(grapple_pos)
|
|
var dir_to_point: Vector3 = (grapple_pos - player.global_position).normalized()
|
|
|
|
# Jump to detach and get a boost
|
|
if machine.input_jump_just_pressed and machine.jump_cooldown_timer <= 0.0:
|
|
vel.y = params.jump_velocity
|
|
# Add a directional boost if jumping while swinging
|
|
var h_look = machine.wish_dir_world
|
|
if h_look.length_squared() > 0.1:
|
|
var h_boost = h_look.normalized() * params.grapple_jump_boost
|
|
vel.x += h_boost.x
|
|
vel.z += h_boost.z
|
|
|
|
player.velocity = vel
|
|
machine.jump_cooldown_timer = params.jump_cooldown
|
|
machine.register_chain_mechanic("grapple_jump")
|
|
machine.switch_to("air")
|
|
if player.jump_player:
|
|
player.jump_player.play()
|
|
return
|
|
|
|
# Apply gravity
|
|
vel.y -= params.gravity * delta
|
|
|
|
# Apply slight inward pull (reeling in)
|
|
vel += dir_to_point * params.grapple_pull_force * delta
|
|
|
|
# Pendulum / Rope physics
|
|
# If the player tries to go further than the original rope length, pull them back aggressively
|
|
var max_len: float = machine.grapple_length
|
|
if current_dist > max_len:
|
|
# Project velocity onto the tangent of the sphere (prevent moving further away)
|
|
var radial_vel = vel.project(dir_to_point)
|
|
# If radial_vel is pointing AWAY from the grapple point (dot < 0), kill it
|
|
if radial_vel.dot(dir_to_point) < 0:
|
|
vel -= radial_vel
|
|
|
|
# Add a spring force to pull them back to the sphere
|
|
var diff = current_dist - max_len
|
|
var spring_force = dir_to_point * diff * params.grapple_spring_strength
|
|
vel += spring_force * delta
|
|
|
|
# Air control while swinging
|
|
var wish_dir: Vector3 = machine.wish_dir_world
|
|
if wish_dir.length_squared() > 0.01:
|
|
wish_dir = wish_dir.normalized()
|
|
# Add force tangentially to the rope
|
|
# We want to steer, but not pull away from or directly into the rope.
|
|
var tangent_wish = wish_dir - wish_dir.project(dir_to_point)
|
|
if tangent_wish.length_squared() > 0.01:
|
|
vel += tangent_wish.normalized() * params.grapple_air_control * delta
|
|
|
|
player.velocity = vel
|
|
player.move_and_slide()
|
|
|
|
# Remove ground detach so players can grapple along the floor
|
|
# if player.is_on_floor():
|
|
# machine.on_ground = true
|
|
# machine.switch_to("ground")
|
|
# return
|