feat: added grapple mechanic
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
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
|
||||
Reference in New Issue
Block a user