创建新工程

This commit is contained in:
moyin
2025-12-05 19:00:14 +08:00
commit ff4fa5fffd
227 changed files with 32804 additions and 0 deletions

267
scripts/InputHandler.gd Normal file
View 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")