diff --git a/_player/Avatar.tscn b/_player/Avatar.tscn index e033be9..bec8c76 100644 --- a/_player/Avatar.tscn +++ b/_player/Avatar.tscn @@ -139,6 +139,7 @@ grap_hook_shooting_time = 0.2 [node name="Grapping" type="LimboState" parent="PlayerHSM/Normal/GrapHook"] unique_name_in_owner = true script = ExtResource("19_u7cua") +release_distance = 20.0 [node name="Dash" type="LimboState" parent="PlayerHSM/Normal"] unique_name_in_owner = true @@ -184,11 +185,13 @@ metadata/_custom_type_script = "uid://bkkkyugppu7sl" [node name="ReedSFXMananger" type="Node" parent="."] script = ExtResource("24_x5g5e") bindings = Array[ExtResource("25_rjd7i")]([ExtResource("26_256x0")]) +enable_debug = false metadata/_custom_type_script = "uid://lp1ge1qbyfr3" [node name="ReedVFXManager" type="Node" parent="."] script = ExtResource("24_mwlgv") bindings = Array[ExtResource("25_s5egm")]([ExtResource("26_s5egm"), ExtResource("30_hquoe")]) +enable_debug = false metadata/_custom_type_script = "uid://ta2r2bc1nrwe" [node name="HitBox" type="Area2D" parent="."] diff --git a/_player/bbp_player.tres b/_player/bbp_player.tres index 559adde..b0b25a9 100644 --- a/_player/bbp_player.tres +++ b/_player/bbp_player.tres @@ -11,6 +11,11 @@ var/had_jump/type = 1 var/had_jump/value = false var/had_jump/hint = 0 var/had_jump/hint_string = "" +var/force_reset_jump/name = &"force_reset_jump" +var/force_reset_jump/type = 1 +var/force_reset_jump/value = false +var/force_reset_jump/hint = 0 +var/force_reset_jump/hint_string = "" var/is_dashing/name = &"is_dashing" var/is_dashing/type = 1 var/is_dashing/value = false diff --git a/_player/states/grapping.gd b/_player/states/grapping.gd index 42e7d99..c7c07fe 100644 --- a/_player/states/grapping.gd +++ b/_player/states/grapping.gd @@ -3,9 +3,14 @@ extends LimboState @onready var root: Normal = %Normal @export_category("Hook Pull Release") +##如果和目标点小于此距离,则会自动松开 @export var release_distance: float = 12.0 +##如果钩爪方向和角色速度方向小于此,则中断 @export var release_dot_threshold: float = 0.0 +##最短pull时间,即使距离非常近,也会判断至少此时间 @export var min_pull_timer: float = 0.08 +##如果钩爪跳时速度低于这个值,则会强制重置跳跃 +@export var force_jump_reset_maxinum_speed: float = 230 var _pull_timer := 0.0 var _anchor @@ -75,9 +80,7 @@ func _update(delta: float) -> void: return func _exit() -> void: - agent.locomotion_comp.stop_custom_move(false) - _anchor = null - + agent.locomotion_comp._release_hook_keep_momentum() agent.spawn_hook_comp.release_cached_hook() func _handle_trigger_jump() -> bool: @@ -85,6 +88,9 @@ func _handle_trigger_jump() -> bool: return false func _hook_to_jump() -> void: + var v : float = agent.velocity.length() + if v <= force_jump_reset_maxinum_speed: + get_root().blackboard.set_var(&"force_reset_jump",true) get_root().blackboard.set_var(&"want_to_jump",true) self.dispatch(&"hook_to_jump") diff --git a/_player/states/jump.gd b/_player/states/jump.gd index 228d0c5..7708994 100644 --- a/_player/states/jump.gd +++ b/_player/states/jump.gd @@ -10,8 +10,12 @@ func _setup() -> void: func _enter() -> void: _jump_from_land_check() - var _j = agent.locomotion_comp.jump() as bool + ##是否要强制重置水平速度。 + var f = blackboard.get_var(&"force_reset_jump",false) as bool + var _j = agent.locomotion_comp.jump(f) as bool + get_root().blackboard.set_var(&"is_jumping",true) #标记jump + get_root().blackboard.set_var(&"force_reset_jump",false)#重置强制重置位 func _exit() -> void: #这里强制重置一下 diff --git a/addons/limboai/bin/~liblimboai.windows.editor.x86_64.dll b/addons/limboai/bin/~liblimboai.windows.editor.x86_64.dll deleted file mode 100644 index 7131bab..0000000 Binary files a/addons/limboai/bin/~liblimboai.windows.editor.x86_64.dll and /dev/null differ diff --git a/addons/reedcomponent/grap_hook/garpping_hook_v_2.gd b/addons/reedcomponent/grap_hook/garpping_hook_v_2.gd index 1f81dbe..a9746dd 100644 --- a/addons/reedcomponent/grap_hook/garpping_hook_v_2.gd +++ b/addons/reedcomponent/grap_hook/garpping_hook_v_2.gd @@ -8,9 +8,14 @@ extends Node2D @export var max_length := 200.0 @export var stretching_speed: float = 1400.0 +@export_category("Hook Retract") +@export var retract_speed: float = 1800.0 + @onready var line_2d: Line2D = %Line2D @onready var ray: RayCast2D = %RayCast2D +var _tween: Tween + const GRAPABLE_GROUP = &"GRAPABLE" signal stretching_finished(reach_limit: bool, anchor_node: Node2D) @@ -127,7 +132,7 @@ func _handle_hit(target: Node2D, hit_pos: Vector2) -> void: stretching_finished.emit(reach_max, anchor) ## 釋放鉤爪(清理 Anchor 與狀態) -func release_hook() -> void: +func _release_hook() -> void: # 1. 停止拉伸(保險) _is_stretching = false _stretching_dir = Vector2.ZERO @@ -145,8 +150,59 @@ func release_hook() -> void: ray.target_position = Vector2.ZERO _update_line() +func release_hook_with_transition(has_trans: bool) -> void: + # 先停止一切拉伸逻辑 + _is_stretching = false + _stretching_dir = Vector2.ZERO + _cached_cancel = false + + # 如果不需要动画,直接释放 + if not has_trans: + _release_hook() + queue_free() + return + + # ===== 需要回收动画 ===== + # 先清 Anchor(但不影响末端视觉) + if _anchor and is_instance_valid(_anchor): + _anchor.get_parent().remove_child(_anchor) + _anchor.queue_free() + _anchor = null + + # 当前末端位置(本地坐标) + var start_pos: Vector2 = ray.target_position + var distance := start_pos.length() + + if distance <= 0.001: + queue_free() + return + + # 根据速度算 tween 时间 + var duration := distance / retract_speed + + if _tween and _tween.is_valid(): + _tween.kill() + + _tween = get_tree().create_tween() + _tween.set_trans(Tween.TRANS_SINE) + _tween.set_ease(Tween.EASE_IN) + + _tween.tween_property( + ray, + "target_position", + Vector2.ZERO, + duration + ) + + _tween.finished.connect(func(): + queue_free() + ) + func _update_line() -> void: - line_2d.set_point_position(0, Vector2.ZERO) + if _anchor and is_instance_valid(_anchor): + # 关键:锚点是世界坐标固定的,把它换算到 Hook 的本地坐标 + ray.target_position = to_local(_anchor.global_position) + line_2d.set_point_position(1, ray.target_position) func _create_anchor_on_node(target: Node2D, hit_global_pos: Vector2) -> Node2D: diff --git a/addons/reedcomponent/grap_hook/spawn_hook_component.gd b/addons/reedcomponent/grap_hook/spawn_hook_component.gd index 2594dfc..a3abe1d 100644 --- a/addons/reedcomponent/grap_hook/spawn_hook_component.gd +++ b/addons/reedcomponent/grap_hook/spawn_hook_component.gd @@ -15,8 +15,8 @@ signal hook_reach_finished(reach_limit: float, anchor: Node2D) func spawn_grap_hook_inst(dir: Vector2) -> Hook: var i = GRAPPING_HOOK.instantiate() as Hook + owner.add_child(i) i.init(self,true) - get_tree().current_scene.add_child(i) i.start_stretching(dir) _current_grap_hook_inst = i @@ -25,7 +25,7 @@ func spawn_grap_hook_inst(dir: Vector2) -> Hook: func release_cached_hook() -> void: if _current_grap_hook_inst: - _current_grap_hook_inst.release_hook() + _current_grap_hook_inst.release_hook_with_transition(true) func get_current_hook_inst() -> Hook: return _current_grap_hook_inst diff --git a/addons/reedcomponent/locomotion/jump_locomotion.gd b/addons/reedcomponent/locomotion/jump_locomotion.gd index 8b17bc9..7abfb2c 100644 --- a/addons/reedcomponent/locomotion/jump_locomotion.gd +++ b/addons/reedcomponent/locomotion/jump_locomotion.gd @@ -45,28 +45,33 @@ var _h_boost_timer: float ##跳跃 -func jump() -> bool: +func jump(force_reset_x: bool = false) -> bool: if _is_jumping : return false var input_dir = sign(_movement_input) as float - if input_dir != 0 : - var vel_dir := sign(characterbody.velocity.x) - var accel_dir := sign(_current_acceleration.x) - - # ---------- 情况 1:角色在起步 ---------- - # velocity 还没起来,但已经在往某方向加速 - if vel_dir == 0 and accel_dir == input_dir: - characterbody.velocity.x += input_dir * jump_horizontal_Boost - - # ---------- 情况 2:角色稳定同向移动 ---------- - elif vel_dir == input_dir and accel_dir == 0: - characterbody.velocity.x += input_dir * jump_horizontal_Boost - - # ---------- 情况 3:角色正在反向 / pivot ---------- - elif vel_dir == -input_dir: - characterbody.velocity.x = input_dir * jump_horizontal_Boost + if not force_reset_x: + if input_dir != 0 : + var vel_dir := sign(characterbody.velocity.x) + var accel_dir := sign(_current_acceleration.x) - apply_jump_horizontal_boost(input_dir) + # ---------- 情况 1:角色在起步 ---------- + # velocity 还没起来,但已经在往某方向加速 + if vel_dir == 0 and accel_dir == input_dir: + characterbody.velocity.x += input_dir * jump_horizontal_Boost + + # ---------- 情况 2:角色稳定同向移动 ---------- + elif vel_dir == input_dir and accel_dir == 0: + characterbody.velocity.x += input_dir * jump_horizontal_Boost + + # ---------- 情况 3:角色正在反向 / pivot ---------- + elif vel_dir == -input_dir: + characterbody.velocity.x = input_dir * jump_horizontal_Boost + + apply_jump_horizontal_boost(input_dir) + else: + ##如果强制重置,我们会让水平速度直接等于输入加水平补正 + characterbody.velocity.x = input_dir * jump_horizontal_Boost + print("强制重置") _jump_timer = jump_hold_maxium_time _h_boost_timer = jump_horizontal_Boost_last_time diff --git a/addons/reedfx/sfx/SFXManager.gd b/addons/reedfx/sfx/SFXManager.gd index 128c33e..8d60b20 100644 --- a/addons/reedfx/sfx/SFXManager.gd +++ b/addons/reedfx/sfx/SFXManager.gd @@ -12,33 +12,43 @@ func _ready() -> void: _bind_all() func _bind_all() -> void: - print("[SFX] binding count =", bindings.size(), " manager path=", get_path()) + _dbg_fmt("binding count=%d manager=%s", [bindings.size(), get_path()]) for binding in bindings: - print("[SFX] try bind: target_node=", binding.target_node, " signal=", binding.signal_name) + _dbg_fmt( + "try bind: target_node=%s signal=%s", + [binding.target_node, binding.signal_name] + ) if not has_node(binding.target_node): - push_warning("[SFX] target node not found: %s (manager=%s)" % [binding.target_node, get_path()]) + push_warning( + "[SFX] target node not found: %s (manager=%s)" + % [binding.target_node, get_path()] + ) continue var target := get_node(binding.target_node) - print("[SFX] target resolved:", target, " path=", target.get_path()) + _dbg_fmt("target resolved: %s path=%s", [target, target.get_path()]) if not target.has_signal(binding.signal_name): - push_warning("[SFX] signal not found: %s on %s" % [binding.signal_name, target.get_path()]) + push_warning( + "[SFX] signal not found: %s on %s" + % [binding.signal_name, target.get_path()] + ) continue - # 🔥 关键:lambda 包一层 + 打印确认 var cb := func(ctx = null): - print("[SFX] callback fired! binding=", binding, " ctx=", ctx) + _dbg_fmt( + "callback fired: binding=%s ctx=%s", + [binding, ctx] + ) _on_sfx_signal(binding, ctx) - # 防止重复连接 if target.is_connected(binding.signal_name, cb): - print("[SFX] already connected, skip:", binding.signal_name) + _dbg_fmt("already connected: %s", [binding.signal_name]) else: var err := target.connect(binding.signal_name, cb) - print("[SFX] connect result =", err, " (OK=0)") + _dbg_fmt("connect result=%d (OK=0)", [err]) func _on_sfx_signal(binding: SFXSignalBinding, args: Variant) -> void: if enable_debug and binding.debug_print: @@ -52,6 +62,16 @@ func _on_sfx_signal(binding: SFXSignalBinding, args: Variant) -> void: if args is Dictionary and args.has("world_pos"): _play_at_position(binding, args["world_pos"]) +func _dbg(msg: String) -> void: + if not enable_debug: + return + print("[SFX]", msg) + +func _dbg_fmt(fmt: String, args: Array = []) -> void: + if not enable_debug: + return + print("[SFX]", fmt % args) + # ----------------------------- # 播放逻辑 # -----------------------------