Is there a way to force a Joint to pull objects towards them, but not push them away

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By glair-view

I’m in the process of trying to make a grapple hook, that player will rotate around if they try to go to far, but I want motion to be free otherwise. Problem is that I can’t get the joint to only limit motion away from a maximum distance. Instead it tries to maintain the distance.

:bust_in_silhouette: Reply From: daniklad

I think it would be easier to solve using apply_central_impulse() on RigidBody. Make sure your RigidBody mode is set to MODE_RIGID or MODE_CHARACTER. If it is MODE_STATIC or MODE_KINEMATIC this will not work.
Godot docs on apply_central_impulse()

Do a raycast or whatever you need to find the spot where the grapple hook landed and save the position.

var hook_position = $GrappleHook.global_transform.origin
var hook_direction = hook_position - $Player.global_transform.origin
var hook_start_distance = hook_direction.length()

Now , inside func _physics_process(delta):, do (assuming $Player is a RigidBody):

var hook_direction = hook_position - $Player.global_transform.origin
var hook_distance = hook_direction.length()
var grapple_tension = hook_distance / hook_start_distance
hook_direction = hook_direction.normalized()

var grapple_force = 5.0 # play with this value to find the right one for you
var grapple_pull_force = grapple_tension * grapple_force * hook_direction
$Player.apply_central_impulse(grapple_pull_force)

Your player character should now be pulled towards the grapple hook. Play with the way you calculate grapple_tension to adjust the “springiness” of the “grapple rope”.