godot-plateformer/addons/reedcomponent/grap_hook/grapping_hook.gd

104 lines
3.0 KiB
GDScript3
Raw Permalink Normal View History

2025-12-29 11:54:31 +08:00
class_name GrappingHook extends Node2D
@export var min_rope_length := 20
@export var max_rope_length := 200
@onready var anchor: StaticBody2D = %Anchor
@onready var pin_joint_2d: PinJoint2D = %PinJoint2D
@onready var player_anchor: RigidBody2D = %PlayerAnchor
@onready var line_2d: Line2D = %Line2D
const speed = 30
var _binded_hook_comp:SpawnHookComponet
var m_update_rope_with_nodes: bool = false
func init(hook_comp:SpawnHookComponet):
_binded_hook_comp = hook_comp
##默认以PLAYER类开始Hook
func start_hook(hookPosition):
anchor.global_position = hookPosition
var player = get_tree().get_first_node_in_group("PLAYER") as CharacterBody2D
player_anchor.global_position = player.global_position
player.reparent(player_anchor)
##以注册者开始Hook
func start_hook_with_instigator(hookPosition:Vector2,instigator:Node2D):
anchor.global_position = hookPosition
var i = instigator
if not i: return
player_anchor.global_position = i.global_position
i.reparent(player_anchor)
##离开Hook
func _leave_rope():
await get_tree().create_timer(.1).timeout
var player: Node2D
if _binded_hook_comp:
player = _binded_hook_comp.component_owner
player.reparent(get_tree().current_scene)
#player.set_active(true)
player.rotation = 0
queue_free()
##此函數通過外部的修改可以驅動物體在繩子上移動。
func move_hook(input_dir: Vector2, delta: float) -> void:
if input_dir == Vector2.ZERO:
return
var distance_to_anchor := player_anchor.global_position.distance_to(anchor.global_position)
# === 左右摆动(切向力)===
if input_dir.x != 0.0:
var tangent := player_anchor.global_transform.x
player_anchor.apply_central_impulse(
tangent * input_dir.x * speed * delta
)
# === 上下:改变绳长 ===
if input_dir.y != 0.0:
# y < 0 → 上(收绳)
# y > 0 → 下(放绳)
var rope_dir := player_anchor.global_transform.y as Vector2
var rope_delta := rope_dir * input_dir.y * speed * delta * 0.5 as Vector2
if input_dir.y > 0.0 and distance_to_anchor >= max_rope_length:
return
if input_dir.y < 0.0 and distance_to_anchor <= min_rope_length:
return
# 暂时解绑 joint手动移动 anchor
pin_joint_2d.node_b = NodePath("")
player_anchor.global_position += rope_delta
pin_joint_2d.node_b = player_anchor.get_path()
##更新特定点的位置
func update_line_target_pos_with_index(point_index: int, target_pos: Vector2) -> void:
line_2d.set_point_position(
point_index,
target_pos - global_position
)
##更新锚点的位置
func update_line_anchor_pos(target_pos: Vector2) -> void:
update_line_target_pos_with_index(0,target_pos)
##重置所有点的位置到指定的位置
func reset_line_points_to_target(target_pos: Vector2)-> void:
for i in range(line_2d.points.size()):
update_line_target_pos_with_index(i, target_pos)
func _process(delta: float) -> void:
##如果不更新,直接返回。
if not m_update_rope_with_nodes: return
update_line_target_pos_with_index(0,player_anchor.global_position)
update_line_target_pos_with_index(1,anchor.global_position)