145 lines
3.8 KiB
GDScript
145 lines
3.8 KiB
GDScript
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
|