Reputation: 33
I am fairly new to Godot, but have a little experience with Unity and Python. My goal is to have a grappling system like the one used in the game Karlson, where you can swing back and fourth/side to side, but still with gravity/momentum applied. I have spent quite a few hours trying different things - I started by following a tutorial for a pulling style grappling system by Garbaj, then started looking through different tutorials, Godot Documentation, and trying stuff on my own. At first I thought that using a Pinjoint would work, but it seems you cant change the connection node value within code. So now I think that the solution could be to lock the raycast to the position where it collides when the player left clicks ("shoot"), and then somehow calculate swinging based off of the player position and the raycast collision position, but I have no clue how to go about doing that.
Here is my current code, right now it just pulls me towards the collision point. Variables:
@onready var ray_cast_3d = $RayCast3D
@onready var camera_3d = $Neck/Head/Camera3D
@onready var grapplecast = $Neck/Head/grapplecast
var grappling = false
var grapple_point = Vector3.ZERO
var grapple_point_get = false
Grapple Function
func grapple(delta):
if Input.is_action_pressed("shoot"):
if grapplecast.is_colliding():
if not grappling:
grappling = true
else:
grappling = false
if grappling:
if not grapple_point_get:
grapple_point = grapplecast.get_collision_point()
grapple_point_get = true
if grapple_point.distance_to(transform.origin) > 1:
if grapple_point_get:
transform.origin = lerp(transform.origin, grapple_point, delta * 1.5)
else:
grappling = false
grapple_point_get = false
if Input.is_action_just_released("shoot"):
velocity.y += 5
Any idea how to change this to allow for swinging, or am I going in a completely wrong direction here?
Upvotes: 0
Views: 668
Reputation: 11
I had the same question. I did a little digging, and found a tutorial for a pull grappling hook, but that's not what you're asking for. I found this tutorial and GitHub page by Calvin Wong and copied the code. The code uses a 'rest_length' to know where to pull to. After even more digging, I realized we're if you graph the motion of the player while swinging, we get a sphere, meaning we want the radius to stay the same throughout. We can accomplish this by setting the rest length when we first grapple to the distance to the grapple point (minus 1 or 2 for a little pull) so that it stays roughly the same distance from the point at all times. I got this to happen by changing the 'check_hook_activation' function to
func check_hook_activation():
# Activate hook
if Input.is_action_just_pressed("pull") and $RayCast3D.is_colliding():
hooked = true
gPoint = $RayCast3D.get_collision_point() #point of rotation
rest_length = (gPoint - global_position).length() - 2 #what makes this work
# Stop grappling
elif Input.is_action_just_released("pull"):
hooked = false
rest_length = 2 #this is probably not necessary, but oh well
I renamed the variables a little, but this works. You can change the grapple speed for a faster pull.
Upvotes: 1
Reputation: 36
I would do a finite state machine with one state being normal platformer movement and one being pendulum physics like in @cak3_lover 's comment.
Upvotes: 0