@tool extends Marker2D class_name SignSnapper signal arrived @export var enabled := true @export var release_player_on_arrived := true # 仅使用 x 坐标;否则也用 y 进行 walk to @export var use_x_only := true # x 左右有效范围 @export_range(0.0, 20.0, 0.1) var radius := 0.0 # 让玩家走到边缘,特别适用于 npc 对话等情景 @export var walk_to_edge := false # arrived 延时 @export_range(0.0, 10.0, 0.1) var delay_arrived := 0.0 @export var action_on_arrived := 3 @export_range(0.0, 10.0, 0.1) var delay_after_action := 0.0 @export_tool_button("debug 检查玩家触发位置") var debug_check_player_pos = _debug_check_player_pos var detacted_sign: Sign # 玩家在和 sign 交互时,如果读到节点中有 SignSnapper,则移动到该位置(x 对齐) func _ready(): if not get_parent(): return for c in get_parent().get_children(): if c is Sign: detacted_sign = c break if not detacted_sign and Engine.is_editor_hint(): printerr("SignSnapper must have a Sign sibling node!") if not Engine.is_editor_hint(): detacted_sign.interacted.connect(_on_interacted) func _on_interacted(): if not detacted_sign or not enabled: return var player = SceneManager.get_player() var target_pos = global_position if use_x_only: target_pos.y = player.global_position.y var player_x = player.global_position.x if (radius > 0 and absf(target_pos.x - player_x) > radius) or walk_to_edge: # clamp in range if target_pos.x > player_x: target_pos.x -= radius else: target_pos.x += radius var tween = player.walk_to(target_pos, release_player_on_arrived) if delay_arrived > 0: tween.tween_interval(delay_arrived) if action_on_arrived != 3: tween.tween_callback(SceneManager.player_action.bind(action_on_arrived)) if delay_after_action > 0: tween.tween_interval(delay_after_action) tween.tween_callback(arrived.emit) func _debug_check_player_pos(): if not Engine.is_editor_hint(): return var grounds = get_tree().get_nodes_in_group("ground") if not grounds: printerr("no ground") return var ground = grounds[0] if use_x_only: ground.replace_player_to_portal = true var player = ground.player if radius > 0: var player_x = player.global_position.x if absf(player_x - global_position.x) > radius: # clamp in range if player_x < global_position.x: player.global_position.x = global_position.x - radius else: player.global_position.x = global_position.x + radius else: player.global_position.x = global_position.x if not use_x_only: player.global_position.y = global_position.y