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

145 lines
3.8 KiB
GDScript3
Raw Normal View History

2025-12-31 13:07:31 +08:00
class_name Hook extends Node2D
## ================
## Export Field
## ================
@export var min_length := 140
@export var max_length := 200
@export var streching_speed:float = 1400
## 线段
@onready var line_2d: Line2D = %Line2D
## 检测碰撞的区域
@onready var area_2d: Area2D = %Area2D
const GRAPABLE_GROUP = &"GRAPABLE"
const ANCHOR_NODE = preload("uid://dfm5wy1rmci68")
signal stretching_finished(reach_limit:bool, anchor_node: Node2D)
## ================
## Private Field
## ================
var _binded_hook_comp
var _is_stretching: bool = false
var _stretching_dir: Vector2 = Vector2.ZERO
var _cached_cancel: bool = false
var _anchor: Node2D
func _ready() -> void:
area_2d.position = Vector2.ZERO
area_2d.area_entered.connect(grap_detected)
area_2d.body_entered.connect(grap_detected)
##初始化
func init(hook_comp:SpawnHookComponet,reset_to_target: bool):
_binded_hook_comp = hook_comp
if reset_to_target:
var p : Vector2= hook_comp.owner.global_position
self.global_position = p
##开始stretching
func start_stretching(direction: Vector2) -> void:
_is_stretching = true
_cached_cancel = false
_stretching_dir = direction
##结束stretching
func end_stretching(force_end: bool = false) -> bool:
##如果还没有达到最短的stretching length则继续
if not force_end and _is_stretching:
var d = self.global_position.distance_to(area_2d.global_position)
if d < min_length:
_cached_cancel = true
return false
_is_stretching = false
_stretching_dir = Vector2.ZERO
return true
##是否正在stretching
func is_stretching() -> bool:
return _is_stretching
##物理更新
func _physics_process(delta: float) -> void:
if _is_stretching:
_update_stretching(delta)
##更新绳索的动画表现
func _process(delta: float) -> void:
update_line_target_pos_with_index(0,self.global_position)
update_line_target_pos_with_index(1,area_2d.global_position)
##更新钩爪爪手的位置
func _update_stretching(delta: float) -> void:
var d = self.global_position.distance_to(area_2d.global_position)
#如果已经存在一个缓存的取消,且当前的长度小于最小长度,则直接取消
if _cached_cancel:
if d >= min_length:
stretching_finished.emit(true,null)
end_stretching(true)
return
#如果达到的最大的长度,直接取消
if d > max_length:
stretching_finished.emit(true,null)
end_stretching(true)
return
area_2d.global_position += delta * streching_speed * _stretching_dir
## ================
## Tool Func
## ================
##更新特定点的位置
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
)
##当触碰到可以被抓握的Area后自动在当前位置生成一个钩爪锚点后续的移动交给其他系统
func grap_detected(node: Node2D) -> void:
if node.is_in_group(GRAPABLE_GROUP):
end_stretching(true)
var d : float= self.global_position.distance_to(area_2d.global_position)
var b = d == max_length
var anchor := _create_anchor_on_node(node)
if anchor:
stretching_finished.emit(b,anchor)
##创建钩爪锚点
func _create_anchor_on_node(area: Node2D) -> Node2D:
# 如果之前有锚点,先清掉
if _anchor and is_instance_valid(_anchor):
_anchor.queue_free()
# 1. 创建 Anchor
_anchor = Node2D.new()
_anchor.name = "Anchor"
add_child(_anchor)
# 2. Anchor 初始位置 = Area 当前世界位置
_anchor.global_position = area.global_position
# 3. 在 Area 上挂 RemoteTransform2D
var remote := RemoteTransform2D.new()
remote.name = "AnchorRemote"
area.add_child(remote)
remote.remote_path = _anchor.get_path()
# 4. 只同步位置(锚点一般不需要跟旋转/缩放)
remote.update_rotation = false
remote.update_scale = false
return _anchor