Godot Version
4.2.2
Question
I am new to Godot so please bear with me
What I am trying to do:
I am modifying this grapple hook addon: Grappling Hook 3D - Godot Asset Library
I am trying to make a grapple hook that works with moving objects
Currently the grapple hook attaches itself to an object and pulls the player forward by shooting a ray cast and getting the position of the object.
var pull_vector = (hook_target_position - player_body.global_position).normalized()
This works great for objects that never move. However when I try to hook onto an object that is moving, the position never gets updated. This causes the player to hook into the last spot
the object was.
What I have tried:
Instead of giving the position to the player I just gave the position of the collider. The problem with this method is that the grapple hook just hooks into the center of the object.
I want it to hit at a specific point where the player looks and pulls them towards that point. I don’t want the player to be pulled constantly towards the center of the object.
func _attach_hook() -> void:
is_hook_launched = true
var hit_node = hook_raycast.get_collider()
if hit_node:
if hit_node.is_in_group("MoveBox"): # Check if the hit node is in the "Boxes" group
print("Hit a box:", hit_node.name)
hit_node.announce_hit()
#Makes it so that the player is pulled in the center of a moving object
hook_target = hook_raycast.get_collider() as Node3D
hook_target_position = hook_raycast.get_collision_point()
_hook_target_normal = hook_raycast.get_collision_normal()
_hook_model = hook_scene.instantiate()
add_child(_hook_model)
hook_attached.emit()
Another approach I tried was instead of getting the collider I would get the position of the moving object itself and give that as the position. However upon doing this I am still being pulled into the center.
#Pulls only to the center
var pull_vector = (moving_point- player_body.global_position).normalized()
I’m not sure what else to do. If anyone could give me some ideas or point me in the right direction I would really appreciate it.
For reference here is the entire script
extends Node
class_name HookController
@export_category("Hook Controller")
@export_group("Required Settings")
@export var hook_raycast: RayCast3D
@export var player_body: CharacterBody3D
@export var launch_action_name: String
@export var retract_action_name: String
@export_group("Optional Settings")
@export var pull_speed: float = 1
@export var hook_source: Node3D
@export_group("Advanced Settings")
@export var hook_scene: PackedScene = preload("res://addons/grappling_hook_3d/src/hook.tscn")
var _hook_model: Node3D
var _hook_target_normal: Vector3
var is_hook_launched: bool = false
var hook_target: Node3D
var hook_target_position: Vector3
var anchor_offset: Vector3
var moving_point:Vector3
signal hook_launched()
signal hook_attached()
signal hook_detached()
func _ready():
# Connect the 'boxposSignal' signal from all MoveBox nodes
for move_box in get_tree().get_nodes_in_group("MoveBox"):
# print("Connecting boxposSignal signal for", move_box) # Debug print
move_box.connect("boxposSignal", Callable(self, "_on_boxpos_received"))
func _physics_process(delta: float) -> void:
if Input.is_action_just_pressed(launch_action_name):
hook_launched.emit()
if not is_hook_launched and hook_raycast.is_colliding():
_attach_hook()
elif is_hook_launched:
_retract_hook()
if is_hook_launched:
_handle_hook(delta)
func _attach_hook() -> void:
is_hook_launched = true
var hit_node = hook_raycast.get_collider()
if hit_node:
if hit_node.is_in_group("MoveBox"): # Check if the hit node is in the "Boxes" group
print("Hit a box:", hit_node.name)
hit_node.announce_hit()
#Makes it so that the player is pulled in the center of a moving object
#hook_target = hook_raycast.get_collider() as Node3D
hook_target_position = hook_raycast.get_collision_point()
_hook_target_normal = hook_raycast.get_collision_normal()
_hook_model = hook_scene.instantiate()
add_child(_hook_model)
hook_attached.emit()
func _on_boxpos_received(thepoint: Vector3) -> void:
#print("Received 'boxpos' signal with the point:", thepoint)
moving_point=thepoint
func _retract_hook() -> void:
is_hook_launched = false
_hook_model.queue_free()
hook_target = null
hook_detached.emit()
func _handle_hook(delta: float) -> void:
if hook_target:
hook_target_position = hook_target.global_position
#print("hook target pos:", hook_target_position)
# Hook pull math
var pull_vector = (hook_target_position - player_body.global_position).normalized()
#print("Pull vector is: ", pull_vector)
player_body.velocity += pull_vector * pull_speed * delta * 60
# Hook model
var source_position: Vector3
match true if hook_source else false:
true: source_position = hook_source.global_position
false: source_position = player_body.global_position
_hook_model.extend_from_to(source_position, hook_target_position, _hook_target_normal)
Here is the moving box script
extends Node3D
signal box_hit
signal boxposSignal
var thepoint = Vector3()
var ishit=false
func _ready():
pass
func _process(delta):
#pass
#print("Global position is: ", self.global_position)
if ishit:
thepoint=self.global_position
#print("Emitting pleasework signal with point:", thepoint)
emit_signal("boxposSignal",thepoint)
func announce_hit():
print("I'M HIT! The postion is", self.global_position)
ishit=true
emit_signal("box_hit", self)