This commit is contained in:
RedisTKey 2025-12-31 16:24:11 +08:00
parent 745342c35c
commit 3f3bf3331f
10 changed files with 284 additions and 162 deletions

View File

@ -1,9 +1,8 @@
[gd_scene load_steps=5 format=4 uid="uid://3vc8ojbiyy5w"] [gd_scene load_steps=4 format=4 uid="uid://3vc8ojbiyy5w"]
[ext_resource type="PackedScene" uid="uid://gwhff4qaouxy" path="res://_player/Avatar.tscn" id="1_fdx6o"] [ext_resource type="PackedScene" uid="uid://gwhff4qaouxy" path="res://_player/Avatar.tscn" id="1_fdx6o"]
[ext_resource type="PackedScene" uid="uid://1l06de041i40" path="res://_levels/l_level_1.tscn" id="1_pvnxo"] [ext_resource type="PackedScene" uid="uid://1l06de041i40" path="res://_levels/l_level_1.tscn" id="1_pvnxo"]
[ext_resource type="PackedScene" uid="uid://cvqehvdjpoar4" path="res://_player/player_controller.tscn" id="2_j2xwq"] [ext_resource type="PackedScene" uid="uid://cvqehvdjpoar4" path="res://_player/player_controller.tscn" id="2_j2xwq"]
[ext_resource type="PackedScene" uid="uid://knrcnoedxvm6" path="res://_props/trigger_fall_rock/trigger_fall_rock.tscn" id="3_lvu1v"]
[node name="Game" type="Node2D"] [node name="Game" type="Node2D"]
@ -14,8 +13,5 @@ tile_map_data = PackedByteArray("AAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAIAAAAAAAA
auto_controlled_avatar = NodePath("../Avatar") auto_controlled_avatar = NodePath("../Avatar")
[node name="Avatar" parent="." instance=ExtResource("1_fdx6o")] [node name="Avatar" parent="." instance=ExtResource("1_fdx6o")]
position = Vector2(217, -276) position = Vector2(312, 195)
collision_mask = 4 collision_mask = 4
[node name="TriggerFallRock" parent="." instance=ExtResource("3_lvu1v")]
position = Vector2(317, 213)

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=38 format=3 uid="uid://gwhff4qaouxy"] [gd_scene load_steps=39 format=3 uid="uid://gwhff4qaouxy"]
[ext_resource type="Script" uid="uid://dq1g1qp66chwy" path="res://_player/avatar.gd" id="1_rkqpu"] [ext_resource type="Script" uid="uid://dq1g1qp66chwy" path="res://_player/avatar.gd" id="1_rkqpu"]
[ext_resource type="Script" uid="uid://isu8onknb75o" path="res://_player/states/character_state_machine.gd" id="1_wvs5h"] [ext_resource type="Script" uid="uid://isu8onknb75o" path="res://_player/states/character_state_machine.gd" id="1_wvs5h"]
@ -21,6 +21,7 @@
[ext_resource type="Script" uid="uid://d0mw2e4u5u8g" path="res://_player/states/grap_hook.gd" id="16_f07it"] [ext_resource type="Script" uid="uid://d0mw2e4u5u8g" path="res://_player/states/grap_hook.gd" id="16_f07it"]
[ext_resource type="Script" uid="uid://diq7vk63exae7" path="res://_player/states/hook_shooting.gd" id="16_xcbik"] [ext_resource type="Script" uid="uid://diq7vk63exae7" path="res://_player/states/hook_shooting.gd" id="16_xcbik"]
[ext_resource type="Script" uid="uid://ca88urm45gx2c" path="res://_player/states/dead.gd" id="17_5r2pj"] [ext_resource type="Script" uid="uid://ca88urm45gx2c" path="res://_player/states/dead.gd" id="17_5r2pj"]
[ext_resource type="Script" uid="uid://bqrel2r5hcmxk" path="res://_player/states/grapping.gd" id="19_u7cua"]
[ext_resource type="PackedScene" uid="uid://blm8q46h3v2im" path="res://addons/reedcomponent/locomotion/wall_detector.tscn" id="20_air0b"] [ext_resource type="PackedScene" uid="uid://blm8q46h3v2im" path="res://addons/reedcomponent/locomotion/wall_detector.tscn" id="20_air0b"]
[ext_resource type="Script" uid="uid://bhexx6mj1xv3q" path="res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_2d.gd" id="20_ogl63"] [ext_resource type="Script" uid="uid://bhexx6mj1xv3q" path="res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_2d.gd" id="20_ogl63"]
[ext_resource type="Script" uid="uid://8umksf8e80fw" path="res://addons/phantom_camera/scripts/resources/tween_resource.gd" id="21_5r2pj"] [ext_resource type="Script" uid="uid://8umksf8e80fw" path="res://addons/phantom_camera/scripts/resources/tween_resource.gd" id="21_5r2pj"]
@ -126,6 +127,7 @@ grap_hook_shooting_time = 0.2
[node name="Grapping" type="LimboState" parent="PlayerHSM/Normal/GrapHook"] [node name="Grapping" type="LimboState" parent="PlayerHSM/Normal/GrapHook"]
unique_name_in_owner = true unique_name_in_owner = true
script = ExtResource("19_u7cua")
[node name="Dash" type="LimboState" parent="PlayerHSM/Normal"] [node name="Dash" type="LimboState" parent="PlayerHSM/Normal"]
unique_name_in_owner = true unique_name_in_owner = true
@ -142,13 +144,15 @@ dash_speed = 400.0
end_dash_speed = 190.0 end_dash_speed = 190.0
climb_hop_velocity_x = 180.0 climb_hop_velocity_x = 180.0
climb_hop_velocity_y = 334.0 climb_hop_velocity_y = 334.0
jump_force = 270.0
jump_horizontal_Boost = 235.0
wall_jump_base_force_x = 260.0 wall_jump_base_force_x = 260.0
wall_jump_base_force_y = 220.0 wall_jump_base_force_y = 220.0
fall_maxium_speed = 430.0 fall_maxium_speed = 430.0
air_control_mult = 0.7 air_control_mult = 0.85
run_accel = 2100.0 run_accel = 2100.0
run_reduce = 420.0 run_reduce = 420.0
move_speed_max = 157.0 move_speed_max = 192.0
[node name="WallDetector" parent="LocomotionComponent" instance=ExtResource("20_air0b")] [node name="WallDetector" parent="LocomotionComponent" instance=ExtResource("20_air0b")]
unique_name_in_owner = true unique_name_in_owner = true

View File

@ -115,24 +115,35 @@ func get_move_input() -> Vector2:
''' '''
func press_jump() -> void: func press_jump() -> void:
m_jump_press = true
hsm.dispatch(&"trigger_jump") hsm.dispatch(&"trigger_jump")
func release_jump() -> void: func release_jump() -> void:
m_jump_press = false
hsm.dispatch(&"completed_jump") hsm.dispatch(&"completed_jump")
func press_dash() -> void: func press_dash() -> void:
m_dash_press = true
hsm.dispatch(&"trigger_dash") hsm.dispatch(&"trigger_dash")
func release_dash() -> void:
m_dash_press = false
hsm.dispatch(&"completed_dash")
func press_climb() -> void: func press_climb() -> void:
m_climb_press = true
hsm.dispatch(&"trigger_climb") hsm.dispatch(&"trigger_climb")
func release_climb() -> void: func release_climb() -> void:
m_climb_press = false
hsm.dispatch(&"completed_climb") hsm.dispatch(&"completed_climb")
func press_grap_hook() -> void: func press_grap_hook() -> void:
m_grap_hook_press = true
hsm.dispatch(&"trigger_grap_hook") hsm.dispatch(&"trigger_grap_hook")
func release_grap_hook() -> void: func release_grap_hook() -> void:
m_grap_hook_press = true
hsm.dispatch(&"completed_grap_hook") hsm.dispatch(&"completed_grap_hook")
#endregion #endregion

View File

@ -36,6 +36,17 @@ class_name CelesteLocomotionComponent extends JumpLocomotionComponent
@export var climb_jump_time: float = .14 @export var climb_jump_time: float = .14
#endregion #endregion
#region Custom Move (拉扯移動)
@export_category("Custom Move")
@export var custom_move_force: float = 25.0
@export var custom_move_max_speed: float = 420.0
@export var custom_move_stop_distance: float = 4.0
var _custom_move_target_node: Node = null
var _is_custom_moving: bool = false
signal hook_released
#endregion
#region 冲刺field #region 冲刺field
var last_dash_count: int var last_dash_count: int
##此变量为总开关如果关闭则在物理更新里无论如何也是不会更新Dash的这里默认为false因为Dash需要手动触发最好不要常开 ##此变量为总开关如果关闭则在物理更新里无论如何也是不会更新Dash的这里默认为false因为Dash需要手动触发最好不要常开
@ -54,6 +65,7 @@ var _climb_hop_flag: bool = false
var _is_climb_jumping: bool = false var _is_climb_jumping: bool = false
#endregion #endregion
func _init_component() -> void: func _init_component() -> void:
super._init_component() super._init_component()
@ -64,8 +76,12 @@ func _physics_process(delta: float) -> void:
if Engine.is_editor_hint(): if Engine.is_editor_hint():
return return
if _is_custom_moving:
_update_custom_move(delta)
characterbody.move_and_slide()
return
if can_climb: if can_climb:
print("攀爬更新中")
_update_climb(delta) _update_climb(delta)
characterbody.move_and_slide() #移动更新 characterbody.move_and_slide() #移动更新
return return
@ -93,6 +109,78 @@ func _update_climb(delta) -> void:
func _update_dash(delta) -> void: func _update_dash(delta) -> void:
return return
##特殊移動
func _custom_move_to(target_node: Node) -> bool:
if target_node == null:
return false
# 要求目標至少能提供 global_position2D 常見)
if not ("global_position" in target_node):
push_warning("custom_move target_node has no global_position.")
return false
_custom_move_target_node = target_node
_is_custom_moving = true
# 進入自定義移動時,關掉其他行為(按你需求可調)
can_dash = false
can_climb = false
return true
## 停止特殊移動Custom Move
func stop_custom_move(
force_stop_velocity: bool = true,
clear_target: bool = true
) -> void:
if not _is_custom_moving:
return
_is_custom_moving = false
if clear_target:
_custom_move_target_node = null
if force_stop_velocity:
characterbody.velocity = Vector2.ZERO
##預製的保留速度的hook stop
func _release_hook_keep_momentum() -> void:
stop_custom_move(false)
hook_released.emit()
##特殊移動更新函數
func _update_custom_move(delta: float) -> void:
if not _is_custom_moving:
return
# 目標被刪掉/釋放了
if _custom_move_target_node == null or not is_instance_valid(_custom_move_target_node):
_is_custom_moving = false
_custom_move_target_node = null
return
var target_pos: Vector2 = _custom_move_target_node.global_position
var pos: Vector2 = characterbody.global_position
var to_target := target_pos - pos
var distance := to_target.length()
if distance <= custom_move_stop_distance:
_is_custom_moving = false
_custom_move_target_node = null
characterbody.velocity = Vector2.ZERO
return
var dir := to_target / distance
# 拉扯加速度:距離越遠越快(“被拉過去”的感覺)
var acceleration := dir * distance * custom_move_force
characterbody.velocity += acceleration * delta
# 限制最大速度
var v_len := characterbody.velocity.length()
if v_len > custom_move_max_speed:
characterbody.velocity = characterbody.velocity / v_len * custom_move_max_speed
##整合之后的函数如果不需要额外的逻辑可以直接通过这个触发Dash ##整合之后的函数如果不需要额外的逻辑可以直接通过这个触发Dash
func integrate_dash(dash_dir: Vector2) -> bool: func integrate_dash(dash_dir: Vector2) -> bool:
if not predash(dash_dir): if not predash(dash_dir):

View File

@ -0,0 +1,60 @@
extends LimboState
@export_category("Hook Pull Release")
@export var release_distance: float = 12.0
@export var release_dot_threshold: float = 0.0
@export var min_pull_time: float = 0.08
var _pull_time := 0.0
var _anchor
func _enter() -> void:
_pull_time = 0.0
_anchor = agent.spawn_hook_comp.get_current_hook_anchor()
if _anchor and is_instance_valid(_anchor):
agent.locomotion_comp._custom_move_to(_anchor)
func _update(delta: float) -> void:
_pull_time += delta
if _pull_time < min_pull_time:
return
if not _anchor or not is_instance_valid(_anchor):
_force_release()
return
var character : CharacterBody2D = agent
var pos: Vector2 = character.global_position
var target_pos: Vector2 = _anchor.global_position
var to_target := target_pos - pos
var distance := to_target.length()
if distance <= release_distance:
_force_release()
return
if distance > 0.001:
var dir := to_target / distance
if character.velocity.dot(dir) <= release_dot_threshold:
_force_release()
return
func _exit() -> void:
agent.locomotion_comp.stop_custom_move(false)
_anchor = null
func _force_release() -> void:
agent.locomotion_comp.stop_custom_move(false)
if agent.spawn_hook_comp.has_method("release_hook"):
agent.spawn_hook_comp.release_hook()
##解除hook
if agent.is_on_floor():
self.dispatch(&"exit_on_ground")
else:
self.dispatch(&"exit_on_air")
return

View File

@ -0,0 +1 @@
uid://bqrel2r5hcmxk

View File

@ -23,7 +23,6 @@ func _exit() -> void:
pass pass
func _handle_hook_input_completed() -> bool: func _handle_hook_input_completed() -> bool:
return true
agent.spawn_hook_comp.suspend_hook_stretching(false) agent.spawn_hook_comp.suspend_hook_stretching(false)
return true return true
@ -36,3 +35,5 @@ func _handle_hook_stretching_end(reach_end: bool,Anchor:Node2D) -> void:
else: else:
self.dispatch(&"exit_on_air") self.dispatch(&"exit_on_air")
return return
self.dispatch(self.EVENT_FINISHED)

View File

@ -1,9 +1,7 @@
[gd_scene load_steps=3 format=3 uid="uid://ddwoxlqluxiq5"] [gd_scene load_steps=2 format=3 uid="uid://ddwoxlqluxiq5"]
[ext_resource type="Script" uid="uid://bvxgviq7l64ck" path="res://addons/reedcomponent/grap_hook/garpping_hook_v_2.gd" id="1_jrg4x"] [ext_resource type="Script" uid="uid://bvxgviq7l64ck" path="res://addons/reedcomponent/grap_hook/garpping_hook_v_2.gd" id="1_jrg4x"]
[sub_resource type="CircleShape2D" id="CircleShape2D_jrg4x"]
[node name="GarppingHookV2" type="Node2D"] [node name="GarppingHookV2" type="Node2D"]
script = ExtResource("1_jrg4x") script = ExtResource("1_jrg4x")
@ -12,12 +10,8 @@ unique_name_in_owner = true
points = PackedVector2Array(0, 0, 80, 0) points = PackedVector2Array(0, 0, 80, 0)
width = 8.0 width = 8.0
[node name="Area2D" type="Area2D" parent="."] [node name="RayCast2D" type="RayCast2D" parent="."]
unique_name_in_owner = true unique_name_in_owner = true
position = Vector2(80, 0) target_position = Vector2(80, 0)
collision_layer = 0
collision_mask = 4 collision_mask = 4
collide_with_areas = true
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"]
shape = SubResource("CircleShape2D_jrg4x")
debug_color = Color(0, 0.6399631, 0.3615963, 0.41960785)

View File

@ -1,59 +1,57 @@
class_name Hook extends Node2D class_name Hook
extends Node2D
## ================ ## ================
## Export Field ## Export Field
## ================ ## ================
@export var min_length := 140 @export var min_length := 140.0
@export var max_length := 200 @export var max_length := 200.0
@export var streching_speed:float = 1400 @export var stretching_speed: float = 1400.0
## 线段
@onready var line_2d: Line2D = %Line2D @onready var line_2d: Line2D = %Line2D
## 检测碰撞的区域 @onready var ray: RayCast2D = %RayCast2D
@onready var area_2d: Area2D = %Area2D
const GRAPABLE_GROUP = &"GRAPABLE" const GRAPABLE_GROUP = &"GRAPABLE"
const ANCHOR_NODE = preload("uid://dfm5wy1rmci68")
signal stretching_finished(reach_limit:bool, anchor_node: Node2D) signal stretching_finished(reach_limit: bool, anchor_node: Node2D)
## ================ ## ================
## Private Field ## Private Field
## ================ ## ================
var _binded_hook_comp var _binded_hook_comp
var _is_stretching: bool = false var _is_stretching := false
var _stretching_dir: Vector2 = Vector2.ZERO var _stretching_dir := Vector2.ZERO
var _cached_cancel: bool = false var _cached_cancel := false
var _current_length := 0.0
var _anchor: Node2D var _anchor: Node2D
# =================
# Life Cycle
# =================
func _ready() -> void: func _ready() -> void:
area_2d.position = Vector2.ZERO ray.enabled = true
ray.target_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):
## 初始化
func init(hook_comp: SpawnHookComponet, reset_to_target: bool) -> void:
_binded_hook_comp = hook_comp _binded_hook_comp = hook_comp
if reset_to_target: if reset_to_target:
var p : Vector2= hook_comp.owner.global_position global_position = hook_comp.owner.global_position
self.global_position = p
# =================
# Stretch Control
# =================
##开始stretching
func start_stretching(direction: Vector2) -> void: func start_stretching(direction: Vector2) -> void:
_is_stretching = true _is_stretching = true
_cached_cancel = false _cached_cancel = false
_stretching_dir = direction _stretching_dir = direction.normalized()
_current_length = 0.0
##结束stretching
func end_stretching(force_end: bool = false) -> bool: func end_stretching(force_end: bool = false) -> bool:
##如果还没有达到最短的stretching length则继续
if not force_end and _is_stretching: if not force_end and _is_stretching:
var d = self.global_position.distance_to(area_2d.global_position) if _current_length < min_length:
if d < min_length:
_cached_cancel = true _cached_cancel = true
return false return false
@ -61,84 +59,101 @@ func end_stretching(force_end: bool = false) -> bool:
_stretching_dir = Vector2.ZERO _stretching_dir = Vector2.ZERO
return true return true
##是否正在stretching
func is_stretching() -> bool: func is_stretching() -> bool:
return _is_stretching return _is_stretching
##物理更新 # =================
# Update
# =================
func _physics_process(delta: float) -> void: func _physics_process(delta: float) -> void:
if _is_stretching: if _is_stretching:
_update_stretching(delta) _update_stretching(delta)
##更新绳索的动画表现 func _process(_delta: float) -> void:
func _process(delta: float) -> void: _update_line()
update_line_target_pos_with_index(0,self.global_position)
update_line_target_pos_with_index(1,area_2d.global_position) # =================
# Core Logic
# =================
##更新钩爪爪手的位置
func _update_stretching(delta: float) -> void: func _update_stretching(delta: float) -> void:
var d = self.global_position.distance_to(area_2d.global_position) # 先嘗試推進
var next_length := _current_length + stretching_speed * delta
next_length = min(next_length, max_length)
#如果已经存在一个缓存的取消,且当前的长度小于最小长度,则直接取消 # 先用「下一幀長度」做 Ray
if _cached_cancel: ray.target_position = _stretching_dir * next_length
if d >= min_length: ray.force_raycast_update()
stretching_finished.emit(true,null)
# ===== 命中檢測(最高優先)=====
if ray.is_colliding():
var collider := ray.get_collider()
if collider is Node2D and collider.is_in_group(GRAPABLE_GROUP):
var hit_pos := ray.get_collision_point()
_current_length = global_position.distance_to(hit_pos)
ray.target_position = _stretching_dir * _current_length
_handle_hit(collider as Node2D, hit_pos)
return
# ===== 沒命中,才正式推進 =====
_current_length = next_length
# 取消邏輯
if _cached_cancel and _current_length >= min_length:
stretching_finished.emit(true, null)
end_stretching(true) end_stretching(true)
return return
#如果达到的最大的长度,直接取消 # 超過最大距離
if d > max_length: if _current_length >= max_length:
stretching_finished.emit(true,null) stretching_finished.emit(true, null)
end_stretching(true) end_stretching(true)
return
area_2d.global_position += delta * streching_speed * _stretching_dir func _handle_hit(target: Node2D, hit_pos: Vector2) -> void:
_is_stretching = false
_stretching_dir = Vector2.ZERO
## ================ ray.target_position = to_local(hit_pos)
## Tool Func
## ================
##更新特定点的位置 var reach_max := is_equal_approx(_current_length, max_length)
func update_line_target_pos_with_index(point_index: int, target_pos: Vector2) -> void: var anchor := _create_anchor_on_node(target, hit_pos)
line_2d.set_point_position(
point_index,
target_pos - global_position
)
##当触碰到可以被抓握的Area后自动在当前位置生成一个钩爪锚点后续的移动交给其他系统 stretching_finished.emit(reach_max, anchor)
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) ## 釋放鉤爪(清理 Anchor 與狀態)
if anchor: func release_hook() -> void:
stretching_finished.emit(b,anchor) # 1. 停止拉伸(保險)
_is_stretching = false
_stretching_dir = Vector2.ZERO
_cached_cancel = false
_current_length = 0.0
##创建钩爪锚点 # 2. 清掉 Anchor
func _create_anchor_on_node(area: Node2D) -> Node2D: if _anchor and is_instance_valid(_anchor):
# 如果之前有锚点,先清掉 # 先脫離父節點,避免殘留引用問題
_anchor.get_parent().remove_child(_anchor)
_anchor.queue_free()
_anchor = null
# 3. 重置 Ray 與 Line視覺清乾淨
ray.target_position = Vector2.ZERO
_update_line()
func _update_line() -> void:
line_2d.set_point_position(0, Vector2.ZERO)
line_2d.set_point_position(1, ray.target_position)
func _create_anchor_on_node(target: Node2D, hit_global_pos: Vector2) -> Node2D:
if _anchor and is_instance_valid(_anchor): if _anchor and is_instance_valid(_anchor):
_anchor.queue_free() _anchor.queue_free()
# 1. 创建 Anchor
_anchor = Node2D.new() _anchor = Node2D.new()
_anchor.name = "Anchor" _anchor.name = "Anchor"
add_child(_anchor) target.add_child(_anchor)
# 2. Anchor 初始位置 = Area 当前世界位置 # 關鍵:固定命中點偏移
_anchor.global_position = area.global_position _anchor.position = target.to_local(hit_global_pos)
# 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 return _anchor

View File

@ -7,11 +7,6 @@ class_name SpawnHookComponet extends ComponentBase
##用於Grapping Hook的基本Instance ##用於Grapping Hook的基本Instance
const GRAPPING_HOOK = preload("uid://ddwoxlqluxiq5") const GRAPPING_HOOK = preload("uid://ddwoxlqluxiq5")
var _ray_direction: Vector2
var _ray_reference: RayCast2D
var _ray_length: float = 100
##當前的Graphook的實例 ##當前的Graphook的實例
var _current_grap_hook_inst: Hook var _current_grap_hook_inst: Hook
@ -30,6 +25,9 @@ func spawn_grap_hook_inst(dir: Vector2) -> Hook:
i.stretching_finished.connect(_on_hook_stretching_end) i.stretching_finished.connect(_on_hook_stretching_end)
return _current_grap_hook_inst return _current_grap_hook_inst
func release_cached_hook() -> void:
_current_grap_hook_inst.release_hook()
##尝试关闭hook的延长 ##尝试关闭hook的延长
func suspend_hook_stretching(force_suspend: bool = false) -> bool: func suspend_hook_stretching(force_suspend: bool = false) -> bool:
if not _current_grap_hook_inst: return false if not _current_grap_hook_inst: return false
@ -43,52 +41,6 @@ func _on_hook_stretching_end(reach_limit,anchor:Node2D) -> void:
func get_current_hook_anchor() -> Node2D: func get_current_hook_anchor() -> Node2D:
return _current_grap_hook_inst._anchor return _current_grap_hook_inst._anchor
#func grap_reach_target(duration: float) -> bool: ##初始化組件
#if not _ray_reference or not _current_grap_hook_inst:return false
#
###重置所有Points的坐标点位置。
#_current_grap_hook_inst.reset_line_points_to_target(component_owner.global_position)
#
#var start_pos: Vector2 = component_owner.global_position
#var target_pos: Vector2 = _ray_reference.get_collision_point()
#
#var t := get_tree().create_tween()
#t.set_trans(Tween.TRANS_SINE)
#t.set_ease(Tween.EASE_OUT)
#
#t.tween_method(
#_current_grap_hook_inst.update_line_anchor_pos,
#start_pos,
#target_pos,
#duration
#)
#
###结束时会发送广播
#t.finished.connect(_on_hook_reach_finished)
#
#return true
#
###更新GrapHook的物理
#func update_grap_physics(input: Vector2,delta: float) -> void:
#if input.is_zero_approx(): return
#if not _current_grap_hook_inst: return
#
#var i = input.normalized()
#_current_grap_hook_inst.move_hook(input,delta)
#
###此函數默認為Vector.Zeor,子類可以重寫以得到一個全新的結果,也可以通過綁定的方式獲得一個結果。
#func get_grap_move_input() -> Vector2:
#
##如果我們在組件裏綁定了Component上的一個字段也可以直接獲取。
#if binded_hook_move_input_property_name in component_owner:
#return component_owner.get(binded_hook_move_input_property_name)
#
#return Vector2.ZERO
#
#func _on_hook_reach_finished() -> void:
#_current_grap_hook_inst.m_update_rope_with_nodes = true
#hook_reach_finished.emit()
#
func _init_component() -> void: func _init_component() -> void:
pass pass