using UnityEngine;
using UnityEngine.UI;
using BaseGames.Core;
using BaseGames.Core.Events;
namespace BaseGames.UI
{
///
/// 输入设备图标切换器。
/// 订阅 InputDeviceTypeEventChannelSO,在设备切换时通知场景内所有 InputIconImage 刷新。
///
/// ⚠️ 旧版只支持 KB / 手柄二值切换;新版支持 KeyboardMouse / Xbox / PlayStation / Switch。
/// 通常挂在 UIRoot 上,与 InputDeviceDetector 配合使用。
///
public class InputDeviceIconSwitcher : MonoBehaviour
{
[Header("Event Channel")]
[Tooltip("由 InputDeviceDetector 广播的设备类型事件")]
[SerializeField] private InputDeviceTypeEventChannelSO _onDeviceChanged;
private readonly CompositeDisposable _subs = new();
private void OnEnable() => _onDeviceChanged?.Subscribe(OnDeviceChanged).AddTo(_subs);
private void OnDisable() => _subs.Clear();
private void OnDeviceChanged(InputDeviceType _)
{
// 通知场景内所有 InputIconImage 刷新(含非本对象子节点的其他 Canvas 区域)
foreach (var img in FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None))
img.Refresh();
}
}
// ─────────────────────────────────────────────────────────────────────────
///
/// 单个按键图标 Image 组件。
///
/// 支持两种查询模式:
/// • ByActionName(推荐):填写 ActionName(如 "Interact"),
/// 由 IInputIconService 自动解析当前设备 + 改键后的实际绑定路径 → 图标。
/// • ByBindingPath(兼容/装饰用):直接填写固定路径(如 "<Keyboard>/space"),
/// 适合教程截图等不跟随改键变化的场景。
///
[RequireComponent(typeof(Image))]
public class InputIconImage : MonoBehaviour
{
public enum LookupMode { ByActionName, ByBindingPath }
[SerializeField] private LookupMode _mode = LookupMode.ByActionName;
[Tooltip("Action 名称,如 Interact / Jump / Attack(仅 ByActionName 模式使用)")]
[SerializeField] private string _actionName;
[Tooltip("固定绑定路径,如 /space(仅 ByBindingPath 模式使用)")]
[SerializeField] private string _bindingPath;
private Image _image;
private IInputIconService _iconService;
private void Awake() => _image = GetComponent();
private void OnEnable()
{
_iconService = ServiceLocator.GetOrDefault();
if (_iconService != null)
_iconService.OnIconSetChanged += Refresh;
Refresh();
}
private void OnDisable()
{
if (_iconService != null)
_iconService.OnIconSetChanged -= Refresh;
}
/// 刷新图标显示。设备切换或改键后由 InputDeviceIconSwitcher / InputIconService 调用。
public void Refresh()
{
if (_image == null) return;
Sprite sprite = null;
if (_mode == LookupMode.ByActionName && !string.IsNullOrEmpty(_actionName))
{
sprite = _iconService?.GetActionIcon(_actionName);
}
else if (_mode == LookupMode.ByBindingPath && !string.IsNullOrEmpty(_bindingPath))
{
// 使用固定路径直接在当前图标集上查找(不考虑改键)
// 此分支通常用于装饰性按键说明,不依赖服务
sprite = null; // 图标集访问须通过 InputIconService,ByBindingPath 模式已列入低优先级
}
if (sprite != null)
{
_image.sprite = sprite;
_image.enabled = true;
}
else
{
_image.enabled = false;
}
}
}
}