feat: added grapple mechanic

This commit is contained in:
DottsGit
2026-06-05 02:05:07 -04:00
parent 0912669759
commit ecefeb9f7e
8 changed files with 232 additions and 0 deletions
+86
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
uid://8uc46pvajxdf