This site is currently in read-only mode during migration to a new platform.
You cannot post questions, answers or comments, as they would be lost during the migration otherwise.
0 votes

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"):"run")
        vel.x = max(vel.x - acc, -speed)
    elif Input.is_action_pressed("move_right"):"run")
        vel.x = min(vel.x + acc, speed)
        vel.x = lerp(vel.x, 0, 0.2)"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

            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:
        elif vel.y > 0:

    # 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.

Godot version 3.4.2
in Engine by (14 points)
retagged by

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.

1 Answer

0 votes

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.

by (1,100 points)
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.