创建新工程
This commit is contained in:
267
scripts/InputHandler.gd
Normal file
267
scripts/InputHandler.gd
Normal file
@@ -0,0 +1,267 @@
|
||||
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")
|
||||
Reference in New Issue
Block a user