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