Files
whale-town/scripts/TouchFeedbackManager.gd
2025-12-05 19:00:14 +08:00

272 lines
7.3 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)