Files
zeling_v2/Assets/_Game/Scripts/World/Map/RegionNameDisplay.cs
2026-05-25 11:54:37 +08:00

126 lines
4.8 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 System;
using System.Collections;
using UnityEngine;
using TMPro;
using BaseGames.Core;
using BaseGames.Core.Events;
using BaseGames.Localization;
namespace BaseGames.World.Map
{
/// <summary>
/// 进入新区域时在屏幕中央短暂渐显区域名称(架构 15_MapShopModule §1.6)。
/// 挂在 HUD 根节点下,订阅 EVT_RegionChanged执行淡入—保持—淡出动画序列。
/// 可通过 _regionNames 配置原始 RegionId 到本地化显示名的映射;未配置时直接显示 RegionId。
/// </summary>
[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<CanvasGroup>();
_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;
/// <summary>返回最终显示名:优先读 LocKey其次 DisplayName最后回退到 RegionId。</summary>
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;
}
}
}