272 lines
7.3 KiB
GDScript
272 lines
7.3 KiB
GDScript
extends Node
|
||
## 触摸反馈管理器
|
||
## 为移动端提供触摸反馈和优化的触摸体验
|
||
|
||
# 触摸反馈配置
|
||
const HAPTIC_LIGHT = 0.3
|
||
const HAPTIC_MEDIUM = 0.6
|
||
const HAPTIC_HEAVY = 1.0
|
||
|
||
const TOUCH_SCALE_FACTOR = 0.95
|
||
const TOUCH_FEEDBACK_DURATION = 0.1
|
||
|
||
# 触摸区域扩展(像素)
|
||
const TOUCH_AREA_EXPANSION = 20
|
||
|
||
## 为按钮添加触摸反馈
|
||
func setup_button_feedback(button: Button) -> void:
|
||
"""
|
||
为按钮设置触摸反馈
|
||
@param button: 按钮节点
|
||
"""
|
||
if not button:
|
||
return
|
||
|
||
# 扩展触摸区域
|
||
_expand_touch_area(button)
|
||
|
||
# 连接触摸事件
|
||
if not button.button_down.is_connected(_on_button_pressed):
|
||
button.button_down.connect(_on_button_pressed.bind(button))
|
||
if not button.button_up.is_connected(_on_button_released):
|
||
button.button_up.connect(_on_button_released.bind(button))
|
||
|
||
## 为输入框添加触摸反馈
|
||
func setup_input_feedback(line_edit: LineEdit) -> void:
|
||
"""
|
||
为输入框设置触摸反馈
|
||
@param line_edit: 输入框节点
|
||
"""
|
||
if not line_edit:
|
||
return
|
||
|
||
# 扩展触摸区域
|
||
_expand_touch_area(line_edit)
|
||
|
||
# 连接焦点事件
|
||
if not line_edit.focus_entered.is_connected(_on_input_focused):
|
||
line_edit.focus_entered.connect(_on_input_focused.bind(line_edit))
|
||
|
||
## 扩展控件的触摸区域
|
||
func _expand_touch_area(control: Control) -> void:
|
||
"""
|
||
扩展控件的触摸区域,使其更容易点击
|
||
@param control: 控件节点
|
||
"""
|
||
if not control:
|
||
return
|
||
|
||
# 只在移动设备上扩展触摸区域
|
||
if not DisplayServer.is_touchscreen_available():
|
||
return
|
||
|
||
# 增加最小尺寸以扩展触摸区域
|
||
var current_size = control.custom_minimum_size
|
||
var expanded_size = Vector2(
|
||
max(current_size.x, control.size.x + TOUCH_AREA_EXPANSION),
|
||
max(current_size.y, control.size.y + TOUCH_AREA_EXPANSION)
|
||
)
|
||
|
||
control.custom_minimum_size = expanded_size
|
||
|
||
## 按钮按下反馈
|
||
func _on_button_pressed(button: Button) -> void:
|
||
"""
|
||
按钮按下时的反馈
|
||
@param button: 按钮节点
|
||
"""
|
||
# 视觉反馈:缩放效果
|
||
UIAnimationManager.button_press_feedback(button, TOUCH_SCALE_FACTOR, TOUCH_FEEDBACK_DURATION)
|
||
|
||
# 触觉反馈(如果支持)
|
||
_trigger_haptic_feedback(HAPTIC_LIGHT)
|
||
|
||
# 音效反馈(可选)
|
||
_play_touch_sound("button_press")
|
||
|
||
## 按钮释放反馈
|
||
func _on_button_released(button: Button) -> void:
|
||
"""
|
||
按钮释放时的反馈
|
||
@param button: 按钮节点
|
||
"""
|
||
# 确保按钮恢复原始大小
|
||
if button:
|
||
var tween = button.create_tween()
|
||
tween.tween_property(button, "scale", Vector2.ONE, TOUCH_FEEDBACK_DURATION)
|
||
|
||
## 输入框获得焦点反馈
|
||
func _on_input_focused(line_edit: LineEdit) -> void:
|
||
"""
|
||
输入框获得焦点时的反馈
|
||
@param line_edit: 输入框节点
|
||
"""
|
||
# 轻微的脉冲效果
|
||
UIAnimationManager.pulse_highlight(line_edit, 1.05, 0.4)
|
||
|
||
# 触觉反馈
|
||
_trigger_haptic_feedback(HAPTIC_LIGHT)
|
||
|
||
# 音效反馈
|
||
_play_touch_sound("input_focus")
|
||
|
||
## 触发触觉反馈
|
||
func _trigger_haptic_feedback(intensity: float) -> void:
|
||
"""
|
||
触发触觉反馈(震动)
|
||
@param intensity: 震动强度
|
||
"""
|
||
# 检查是否支持触觉反馈
|
||
if not DisplayServer.is_touchscreen_available():
|
||
return
|
||
|
||
# 在支持的平台上触发震动
|
||
if OS.get_name() == "Android":
|
||
# Android震动 - 在Godot 4中使用Input.vibrate_handheld
|
||
var duration_ms = int(intensity * 100) # 转换为毫秒
|
||
Input.vibrate_handheld(duration_ms)
|
||
elif OS.get_name() == "iOS":
|
||
# iOS触觉反馈 - 在Godot 4中也使用Input.vibrate_handheld
|
||
var duration_ms = int(intensity * 100)
|
||
Input.vibrate_handheld(duration_ms)
|
||
|
||
## 播放触摸音效
|
||
func _play_touch_sound(_sound_name: String) -> void:
|
||
"""
|
||
播放触摸音效
|
||
@param _sound_name: 音效名称(暂未使用,预留给未来的音效系统)
|
||
"""
|
||
# 检查是否启用音效
|
||
if not preload("res://scripts/GameConfig.gd").get_ui_config().get("enable_sound_effects", true):
|
||
return
|
||
|
||
# 这里可以添加音效播放逻辑
|
||
# 例如:AudioManager.play_ui_sound(_sound_name)
|
||
pass
|
||
|
||
## 创建触摸友好的按钮
|
||
func create_touch_friendly_button(text: String, size: Vector2 = Vector2(200, 60)) -> Button:
|
||
"""
|
||
创建触摸友好的按钮
|
||
@param text: 按钮文本
|
||
@param size: 按钮大小
|
||
@return: 配置好的按钮
|
||
"""
|
||
var button = Button.new()
|
||
button.text = text
|
||
button.custom_minimum_size = size
|
||
|
||
# 设置触摸友好的样式
|
||
_apply_touch_friendly_style(button)
|
||
|
||
# 添加触摸反馈
|
||
setup_button_feedback(button)
|
||
|
||
return button
|
||
|
||
## 创建触摸友好的输入框
|
||
func create_touch_friendly_input(placeholder: String = "", size: Vector2 = Vector2(300, 50)) -> LineEdit:
|
||
"""
|
||
创建触摸友好的输入框
|
||
@param placeholder: 占位符文本
|
||
@param size: 输入框大小
|
||
@return: 配置好的输入框
|
||
"""
|
||
var input = LineEdit.new()
|
||
input.placeholder_text = placeholder
|
||
input.custom_minimum_size = size
|
||
|
||
# 设置触摸友好的样式
|
||
_apply_touch_friendly_style(input)
|
||
|
||
# 添加触摸反馈
|
||
setup_input_feedback(input)
|
||
|
||
return input
|
||
|
||
## 应用触摸友好的样式
|
||
func _apply_touch_friendly_style(control: Control) -> void:
|
||
"""
|
||
为控件应用触摸友好的样式
|
||
@param control: 控件节点
|
||
"""
|
||
if not control:
|
||
return
|
||
|
||
# 只在移动设备上应用特殊样式
|
||
if not DisplayServer.is_touchscreen_available():
|
||
return
|
||
|
||
# 增加字体大小以便触摸设备阅读
|
||
if control.has_method("add_theme_font_size_override"):
|
||
control.add_theme_font_size_override("font_size", 18)
|
||
|
||
# 为按钮添加更明显的边框
|
||
if control is Button:
|
||
var style_box = StyleBoxFlat.new()
|
||
style_box.bg_color = Color(0.2, 0.4, 0.8, 0.8)
|
||
style_box.border_width_left = 2
|
||
style_box.border_width_right = 2
|
||
style_box.border_width_top = 2
|
||
style_box.border_width_bottom = 2
|
||
style_box.border_color = Color(0.3, 0.5, 0.9, 1.0)
|
||
style_box.corner_radius_top_left = 8
|
||
style_box.corner_radius_top_right = 8
|
||
style_box.corner_radius_bottom_left = 8
|
||
style_box.corner_radius_bottom_right = 8
|
||
|
||
control.add_theme_stylebox_override("normal", style_box)
|
||
|
||
# 按下状态的样式
|
||
var pressed_style = style_box.duplicate()
|
||
pressed_style.bg_color = Color(0.15, 0.3, 0.6, 0.9)
|
||
control.add_theme_stylebox_override("pressed", pressed_style)
|
||
|
||
## 检查是否为移动设备
|
||
func is_mobile_device() -> bool:
|
||
"""
|
||
检查当前是否为移动设备
|
||
@return: 是否为移动设备
|
||
"""
|
||
var os_name = OS.get_name()
|
||
return os_name in ["Android", "iOS"] or DisplayServer.is_touchscreen_available()
|
||
|
||
## 获取推荐的触摸目标大小
|
||
func get_recommended_touch_size() -> Vector2:
|
||
"""
|
||
获取推荐的触摸目标大小
|
||
@return: 推荐的最小触摸大小
|
||
"""
|
||
if is_mobile_device():
|
||
return Vector2(60, 60) # 移动设备推荐最小44-60像素
|
||
else:
|
||
return Vector2(40, 40) # 桌面设备可以更小
|
||
|
||
## 自动优化界面的触摸体验
|
||
func optimize_ui_for_touch(root_node: Control) -> void:
|
||
"""
|
||
自动优化界面的触摸体验
|
||
@param root_node: 根节点
|
||
"""
|
||
if not is_mobile_device():
|
||
return
|
||
|
||
_optimize_node_recursive(root_node)
|
||
|
||
## 递归优化节点
|
||
func _optimize_node_recursive(node: Node) -> void:
|
||
"""
|
||
递归优化节点的触摸体验
|
||
@param node: 节点
|
||
"""
|
||
if node is Button:
|
||
setup_button_feedback(node as Button)
|
||
_apply_touch_friendly_style(node as Control)
|
||
elif node is LineEdit:
|
||
setup_input_feedback(node as LineEdit)
|
||
_apply_touch_friendly_style(node as Control)
|
||
|
||
# 递归处理子节点
|
||
for child in node.get_children():
|
||
_optimize_node_recursive(child)
|