Files
zeling_v2/Assets/_Game/Scripts/UI/HUD/InteractPromptWidget.cs
Joywayer e879efaa89 Add InputDeviceIconSetSO configuration guide and related documentation
- Created a new markdown file detailing the configuration of InputDeviceIconSetSO.
- Included sections on system architecture, field explanations, image specifications, and complete workflow from setup to runtime.
- Documented the automatic device recognition logic and provided troubleshooting for common issues.
- Added references to relevant files and scripts for easier navigation.
2026-05-23 00:10:23 +08:00

120 lines
4.4 KiB
C#
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.
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using BaseGames.Core;
using BaseGames.Core.Events;
namespace BaseGames.UI.HUD
{
/// <summary>
/// 交互提示 Widget。
///
/// 职责:
/// • 订阅 InteractPromptEventChannelSO 显示/隐藏提示
/// • 显示按键图标Image+ 动作文本TMP_Text
/// • 监听 IInputIconService.OnIconSetChanged在设备切换或改键后自动刷新图标
///
/// 布置方式:放在 HUD Canvas 下,引用对应的事件频道 SO 资产。
/// 不依赖 HUDController可独立使用。
/// </summary>
public sealed class InteractPromptWidget : MonoBehaviour
{
[Header("UI 引用")]
[SerializeField] private Image _keyIcon;
[SerializeField] private TMP_Text _labelText;
[Tooltip("整个提示根节点,控制显示/隐藏")]
[SerializeField] private GameObject _root;
[Header("Event Channels")]
[SerializeField] private InteractPromptEventChannelSO _onShowPrompt;
[SerializeField] private VoidEventChannelSO _onHidePrompt;
// ── 运行时状态 ────────────────────────────────────────────────────────
private IInputIconService _iconService;
private string _currentActionName;
private readonly CompositeDisposable _subs = new();
// ── Lifecycle ─────────────────────────────────────────────────────────
private void OnEnable()
{
// ServiceLocator 可能在此组件 OnEnable 时尚未注册(执行顺序问题),
// 延迟到 ShowPrompt 首次调用时再获取,确保服务可用
_onShowPrompt?.Subscribe(ShowPrompt).AddTo(_subs);
_onHidePrompt?.Subscribe(HidePrompt).AddTo(_subs);
HidePrompt();
}
private void OnDisable()
{
_subs.Clear();
UnsubscribeFromIconService();
}
// ── Handlers ──────────────────────────────────────────────────────────
private void ShowPrompt(InteractPromptEvent evt)
{
_currentActionName = evt.ActionName;
// 延迟绑定:首次显示时获取服务(确保 ServiceLocator 已初始化)
if (_iconService == null)
{
_iconService = ServiceLocator.GetOrDefault<IInputIconService>();
if (_iconService != null)
_iconService.OnIconSetChanged += RefreshIcon;
}
if (_labelText != null)
_labelText.text = evt.LabelText;
RefreshIcon();
if (_root != null)
_root.SetActive(true);
else
gameObject.SetActive(true);
}
private void HidePrompt()
{
_currentActionName = null;
if (_root != null)
_root.SetActive(false);
else
gameObject.SetActive(false);
}
// ── Icon Refresh ──────────────────────────────────────────────────────
/// <summary>设备切换或改键后刷新图标。由 IInputIconService.OnIconSetChanged 调用。</summary>
private void RefreshIcon()
{
if (_keyIcon == null || string.IsNullOrEmpty(_currentActionName)) return;
var sprite = _iconService?.GetActionIcon(_currentActionName);
if (sprite != null)
{
_keyIcon.sprite = sprite;
_keyIcon.enabled = true;
}
else
{
// 找不到图标时隐藏图标格,避免显示错误占位图
_keyIcon.enabled = false;
}
}
private void UnsubscribeFromIconService()
{
if (_iconService != null)
{
_iconService.OnIconSetChanged -= RefreshIcon;
_iconService = null;
}
}
}
}