using System; using System.Collections; using UnityEngine; using TMPro; using BaseGames.Core; using BaseGames.Core.Events; using BaseGames.Localization; namespace BaseGames.World.Map { /// /// 进入新区域时在屏幕中央短暂渐显区域名称(架构 15_MapShopModule §1.6)。 /// 挂在 HUD 根节点下,订阅 EVT_RegionChanged,执行淡入—保持—淡出动画序列。 /// 可通过 _regionNames 配置原始 RegionId 到本地化显示名的映射;未配置时直接显示 RegionId。 /// [RequireComponent(typeof(CanvasGroup))] public class RegionNameDisplay : MonoBehaviour { [SerializeField] private TMP_Text _regionText; [Header("动画时长(秒)")] [SerializeField] [Range(0.1f, 2f)] private float _fadeDuration = 0.4f; [SerializeField] [Range(0.5f, 5f)] private float _holdDuration = 2.0f; [Header("区域名映射(留空则直接显示 RegionId)")] [SerializeField] private RegionNameEntry[] _regionNames; [Header("Event Channels")] [SerializeField] private StringEventChannelSO _onRegionChanged; private CanvasGroup _cg; private Coroutine _showCoroutine; private readonly CompositeDisposable _subs = new(); private void Awake() { _cg = GetComponent(); _cg.alpha = 0f; gameObject.SetActive(false); } private void OnEnable() { _onRegionChanged?.Subscribe(OnRegionChanged).AddTo(_subs); } private void OnDisable() { _subs.Clear(); } // ── 事件响应 ────────────────────────────────────────────────────────── private void OnRegionChanged(string regionId) { if (string.IsNullOrEmpty(regionId)) return; if (_regionText != null) _regionText.text = ResolveDisplayName(regionId); if (_showCoroutine != null) StopCoroutine(_showCoroutine); _showCoroutine = StartCoroutine(ShowSequence()); } // ── 动画序列 ────────────────────────────────────────────────────────── private IEnumerator ShowSequence() { gameObject.SetActive(true); yield return StartCoroutine(FadeTo(1f)); yield return new WaitForSecondsRealtime(_holdDuration); yield return StartCoroutine(FadeTo(0f)); gameObject.SetActive(false); } private IEnumerator FadeTo(float target) { float start = _cg.alpha; float elapsed = 0f; while (elapsed < _fadeDuration) { _cg.alpha = Mathf.Lerp(start, target, elapsed / _fadeDuration); elapsed += Time.unscaledDeltaTime; yield return null; } _cg.alpha = target; } // ── 辅助方法 ────────────────────────────────────────────────────────── private string ResolveDisplayName(string regionId) { if (_regionNames != null) foreach (var e in _regionNames) if (e.RegionId == regionId) return e.GetDisplayName(); return regionId; } } [Serializable] public struct RegionNameEntry { [Tooltip("场景/区域 ID,与 EVT_RegionChanged 事件传递的字符串匹配。")] public string RegionId; [Tooltip("本地化 Key(如 REGION_CITY_NAME)。设置后运行时通过 LocalizationManager 自动解析。")] public string LocKey; [Tooltip("直接显示名(LocKey 为空时使用)。建议优先配置 LocKey,仅在开发或单语言项目中直接善用。")] public string DisplayName; /// 返回最终显示名:优先读 LocKey,其次 DisplayName,最后回退到 RegionId。 public string GetDisplayName() { if (!string.IsNullOrEmpty(LocKey)) { string localized = LocalizationManager.Get(LocKey, LocalizationTable.UI); // LocalizationManager 在未找到 Key 时返回 Key 本身,判断是否是真正翻译结果 if (!string.IsNullOrEmpty(localized) && localized != LocKey) return localized; } return !string.IsNullOrEmpty(DisplayName) ? DisplayName : RegionId; } } }