extends Node class_name InputHandler ## 输入处理器 ## 处理多平台输入(键盘、触摸、虚拟摇杆) # 设备类型枚举 enum DeviceType { DESKTOP, MOBILE, UNKNOWN } var current_device: DeviceType = DeviceType.UNKNOWN # 信号 signal move_input(direction: Vector2) signal interact_input() signal device_detected(device: DeviceType) # signal ui_input(action: String) # 预留用于 UI 导航(暂未使用) # 虚拟控制器引用 var virtual_joystick: Control = null var virtual_interact_button: Control = null # 输入状态控制 var movement_enabled: bool = true var dialogue_box_active: bool = false func _ready(): """初始化输入处理器""" # 检测设备类型 _detect_device() # 根据设备类型设置虚拟控制器 if current_device == DeviceType.MOBILE: setup_virtual_controls() func _process(_delta: float): """每帧处理输入""" # 检查对话框状态 _update_dialogue_box_status() # 获取移动输入(只有在移动启用且对话框未激活时) var direction = Vector2.ZERO if movement_enabled and not dialogue_box_active: direction = get_move_direction() move_input.emit(direction) # 检查交互输入(只有在对话框未激活时才处理) if not dialogue_box_active and is_interact_pressed(): interact_input.emit() ## 获取移动方向 func get_move_direction() -> Vector2: """ 获取当前的移动方向输入 @return: 归一化的方向向量 """ var direction = Vector2.ZERO if current_device == DeviceType.DESKTOP: # 键盘输入 direction = _get_keyboard_direction() elif current_device == DeviceType.MOBILE: # 触摸/虚拟摇杆输入 direction = _get_virtual_joystick_direction() return direction.normalized() if direction.length() > 0 else Vector2.ZERO ## 检查交互键是否按下 func is_interact_pressed() -> bool: """ 检查交互键是否刚被按下 @return: 是否按下 """ if current_device == DeviceType.DESKTOP: return Input.is_action_just_pressed("interact") elif current_device == DeviceType.MOBILE: return _is_virtual_interact_pressed() return false ## 设置虚拟控制器 func setup_virtual_controls() -> void: """ 设置移动端虚拟控制器 创建虚拟摇杆和交互按钮 """ # 查找或创建 UI 容器 var ui_layer = get_tree().root.get_node_or_null("Main/UILayer") if not ui_layer: push_warning("UILayer not found, cannot setup virtual controls") return # 创建虚拟摇杆 if not virtual_joystick: virtual_joystick = VirtualJoystick.new() virtual_joystick.name = "VirtualJoystick" virtual_joystick.position = Vector2(50, get_viewport().get_visible_rect().size.y - 150) ui_layer.add_child(virtual_joystick) # 创建虚拟交互按钮 if not virtual_interact_button: virtual_interact_button = VirtualButton.new() virtual_interact_button.name = "VirtualInteractButton" virtual_interact_button.button_text = "E" virtual_interact_button.position = Vector2( get_viewport().get_visible_rect().size.x - 130, get_viewport().get_visible_rect().size.y - 130 ) ui_layer.add_child(virtual_interact_button) print("Virtual controls setup complete") ## 检测设备类型 func _detect_device() -> void: """ 检测当前设备类型(桌面或移动) """ # 检查是否在移动平台上运行 var os_name = OS.get_name() if os_name in ["Android", "iOS"]: current_device = DeviceType.MOBILE elif os_name in ["Windows", "macOS", "Linux", "FreeBSD", "NetBSD", "OpenBSD", "BSD"]: current_device = DeviceType.DESKTOP else: # 默认为桌面 current_device = DeviceType.DESKTOP # 也可以通过触摸屏检测 if DisplayServer.is_touchscreen_available(): current_device = DeviceType.MOBILE device_detected.emit(current_device) print("Device detected: ", DeviceType.keys()[current_device]) ## 获取键盘方向输入 func _get_keyboard_direction() -> Vector2: """ 从键盘获取方向输入 @return: 方向向量 """ var direction = Vector2.ZERO # 使用独立的移动动作(不影响 UI 输入) if Input.is_action_pressed("move_right"): direction.x += 1 if Input.is_action_pressed("move_left"): direction.x -= 1 if Input.is_action_pressed("move_down"): direction.y += 1 if Input.is_action_pressed("move_up"): direction.y -= 1 return direction ## 获取虚拟摇杆方向 func _get_virtual_joystick_direction() -> Vector2: """ 从虚拟摇杆获取方向输入 @return: 方向向量 """ # 将在子任务 6.3 中实现 # 现在返回零向量 if virtual_joystick and virtual_joystick.has_method("get_direction"): return virtual_joystick.get_direction() return Vector2.ZERO ## 检查虚拟交互按钮 func _is_virtual_interact_pressed() -> bool: """ 检查虚拟交互按钮是否按下 @return: 是否按下 """ # 将在子任务 6.3 中实现 if virtual_interact_button and virtual_interact_button.has_method("is_pressed"): return virtual_interact_button.is_pressed() return false ## 获取当前设备类型 func get_device_type() -> DeviceType: """ 获取当前检测到的设备类型 @return: 设备类型 """ return current_device ## 启用/禁用输入处理 func set_input_enabled(enabled: bool) -> void: """ 启用或禁用输入处理 @param enabled: 是否启用 """ set_process(enabled) # 如果禁用,清除所有输入状态 if not enabled: move_input.emit(Vector2.ZERO) ## 启用/禁用移动输入 func set_movement_enabled(enabled: bool) -> void: """ 启用或禁用移动输入 @param enabled: 是否启用移动 """ movement_enabled = enabled # 如果禁用移动,立即发送零向量停止角色移动 if not enabled: move_input.emit(Vector2.ZERO) ## 更新对话框状态 func _update_dialogue_box_status() -> void: """检测对话框是否处于活动状态""" var was_active = dialogue_box_active # 使用更通用的方法检测UI焦点状态 dialogue_box_active = _is_ui_focused() # 如果对话框状态发生变化,立即停止移动 if was_active != dialogue_box_active: # 无论是激活还是关闭对话框,都强制停止移动并清除输入状态 _clear_all_movement_state() if dialogue_box_active: print("UI focused - movement disabled and cleared") else: print("UI unfocused - movement cleared and reset") ## 检查是否有UI控件获得焦点 func _is_ui_focused() -> bool: """ 检查是否有UI控件获得焦点(如输入框)或对话框是否可见 @return: 是否有UI控件获得焦点 """ # 首先检查对话框是否可见 var main_scene = get_tree().root.get_node_or_null("Main") if main_scene: var ui_layer = main_scene.get_node_or_null("UILayer") if ui_layer: var dialogue_box = ui_layer.get_node_or_null("DialogueBox") if dialogue_box and dialogue_box.visible: return true # 然后检查是否有输入控件获得焦点 var focused_control = get_viewport().gui_get_focus_owner() if focused_control: return focused_control is LineEdit or focused_control is TextEdit return false ## 清除所有移动状态 func _clear_all_movement_state() -> void: """清除所有移动相关的状态和输入""" # 发送零向量停止移动 move_input.emit(Vector2.ZERO) # 清除所有可能的输入状态 Input.action_release("move_up") Input.action_release("move_down") Input.action_release("move_left") Input.action_release("move_right") print("All movement state cleared")