How to create a "zip to point" ability for the player (2D)

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

Hi everyone.
I have just started learning Godot, and I’m trying to implement a “zip to point” ability in my 2D platformer, that when the mouse is clicked, the player shoots a grappling hook towards the direction of the mouse, pulls themselves towards it, and once the player reaches the hook, you regain control. (Like something from Spider-Man games but in 2D?)
Currently, I have it so a Raycast2D is cast from the player, and if it collides with something, the player is teleported to the collision point. However, with this, the player teleports into the floor and through walls (I’m not sure why) and can teleport through small gaps.
How would I better implement this mechanic?
Here is my code:

extends KinematicBody2D
# physics
const speed = 150
const acc = 13
var jumpForce : int = 300
var gravity : int = 800
onready var sprite = $Sprite
onready var animation_tree = $AnimationTree
onready var state_machine = animation_tree.get("parameters/playback")
#zip to point 
onready var raycast2d = $RayCast2D
const MAX_LENGTH = 200
onready var end = $Position2D
onready var player = $Player

var vel = Vector2()

const UP = Vector2(0, -1)


func _physics_process(delta):
	
	# movement inputs
	if Input.is_action_pressed("move_left"):
		state_machine.travel("run")
		vel.x = max(vel.x - acc, -speed)
		print(vel.x)
	elif Input.is_action_pressed("move_right"):
		state_machine.travel("run")
		vel.x = min(vel.x + acc, speed)
		print(vel.x)
	else:
		vel.x = lerp(vel.x, 0, 0.2)
		state_machine.travel("idle")
	#zip to point
	if Input.is_action_pressed("right_click"):
		var mouse_position = get_local_mouse_position()
		var max_cast_to = mouse_position.normalized() * MAX_LENGTH
		raycast2d.cast_to = max_cast_to
		if raycast2d.is_colliding():
			end.global_position = raycast2d.get_collision_point()
			print(end.global_position - position)
			var direction = mouse_position.normalized() 
			self.position = end.global_position
			
			
		else:
			end.global_position = raycast2d.cast_to
			
		
	# applying the velocity
	vel = move_and_slide(vel, UP)
	
	
	#terminal velocity
	if vel.y > 300:
		vel.y =300
	
	# gravity
	vel.y += gravity * delta
	# jump input
	if Input.is_action_pressed("jump") and is_on_floor():
		vel.y -= jumpForce
	
	if !is_on_floor():
		if vel.y < 0:
			state_machine.travel("jump")
		elif vel.y > 0:
			state_machine.travel("fall")
		
	# sprite direction
	if vel.x < 0:
		sprite.flip_h = false
	elif vel.x > 0:
		sprite.flip_h = true

I am still very new to Godot, so detailed explanations would be super helpful.
Thanks

I don’t know how I can help, but here’s a little demo that someone put together for a grappling hook demo. There’s also one that was made by GDQuest, but I can’t find that ATM.

Ertain | 2022-03-08 00:30

:bust_in_silhouette: Reply From: aXu_AP

I think you’re onto something when you save the target point in end variable. You could then apply movement each frame towards end position. Something along these lines should do:

vel += to_local(end.global_position) * 0.01 # Greater speed at bigger distances

Of course there needs also be a check if hook has been used successfully.