- Round 8 report highlights improvements in architecture, editor usability, and data robustness, with a total score of 80/100. - Round 9 report focuses on editor extension capabilities, identifying issues with room data indexing and layout editing, resulting in a score of 76/100. - Round 26 report evaluates the system against commercial standards, noting new issues and confirming previous fixes, with a score of 95.8/100.
139 lines
5.7 KiB
C#
139 lines
5.7 KiB
C#
using UnityEngine;
|
||
using UnityEngine.Serialization;
|
||
using TMPro;
|
||
using System.Collections.Generic;
|
||
using BaseGames.Core;
|
||
using BaseGames.Core.Events;
|
||
|
||
namespace BaseGames.World.Map
|
||
{
|
||
/// <summary>
|
||
/// 探索进度百分比 UI 组件。
|
||
/// 显示全局探索进度和当前区域探索进度,随 OnExplorationChanged 实时更新。
|
||
/// <para>挂在 HUD 或地图面板下;需配置两个 TMP_Text 字段和可选的 StringEventChannelSO。</para>
|
||
/// </summary>
|
||
public class MapProgressDisplay : MonoBehaviour
|
||
{
|
||
[Header("文本组件")]
|
||
[Tooltip("全局探索进度文本,例如 '已探索 42%'。留空则不更新。")]
|
||
[SerializeField] private TMP_Text _globalProgressText;
|
||
|
||
[Tooltip("当前区域进度文本,例如 '区域:67%'。留空则不更新。")]
|
||
[SerializeField] private TMP_Text _regionProgressText;
|
||
|
||
[Header("格式字符串({0:P0} = 百分比,{1} = 区域显示名)")]
|
||
[SerializeField] private string _globalFormat = "已探索 {0:P0}";
|
||
[SerializeField] private string _regionFormat = "{1}:{0:P0}";
|
||
|
||
[Header("区域名映射(与 RegionNameDisplay 共用同一机制)")]
|
||
[Tooltip("RegionId → 本地化显示名映射。未配置时直接显示 RegionId。")]
|
||
[FormerlySerializedAs("_regionNameEntries")]
|
||
[SerializeField] private RegionNameEntry[] _regionNames;
|
||
|
||
[Header("Event Channels")]
|
||
[Tooltip("区域切换事件;订阅后区域切换时自动刷新区域进度。")]
|
||
[SerializeField] private StringEventChannelSO _onRegionChanged;
|
||
|
||
private IMapService _mapSvc;
|
||
private string _currentRegionId;
|
||
private readonly CompositeDisposable _subs = new();
|
||
// R15-N2 RegionId → Entry 字典,将 ResolveRegionDisplayName 从 O(N) 降至 O(1)
|
||
private Dictionary<string, RegionNameEntry> _regionDict;
|
||
|
||
private void Awake()
|
||
{
|
||
BuildRegionDict();
|
||
}
|
||
|
||
private void OnValidate() => BuildRegionDict();
|
||
|
||
private void OnEnable()
|
||
{
|
||
_mapSvc = ServiceLocator.GetOrDefault<IMapService>();
|
||
if (_mapSvc != null)
|
||
{
|
||
_mapSvc.OnExplorationChanged += Refresh;
|
||
_currentRegionId = _mapSvc.CurrentRegionId;
|
||
}
|
||
_onRegionChanged?.Subscribe(OnRegionChanged).AddTo(_subs);
|
||
Refresh();
|
||
}
|
||
|
||
private void OnDisable()
|
||
{
|
||
if (_mapSvc != null)
|
||
{
|
||
_mapSvc.OnExplorationChanged -= Refresh;
|
||
_mapSvc = null;
|
||
}
|
||
_subs.Clear();
|
||
}
|
||
|
||
private void OnRegionChanged(string regionId)
|
||
{
|
||
_currentRegionId = regionId;
|
||
Refresh();
|
||
}
|
||
|
||
/// <summary>立即刷新进度文本。可由外部调用(例如地图面板打开时)。</summary>
|
||
public void Refresh()
|
||
{
|
||
if (_mapSvc == null)
|
||
_mapSvc = ServiceLocator.GetOrDefault<IMapService>();
|
||
if (_mapSvc == null) return;
|
||
|
||
// 全局探索进度
|
||
if (_globalProgressText != null)
|
||
{
|
||
float progress = _mapSvc.GetExplorationProgress();
|
||
try
|
||
{
|
||
_globalProgressText.text = string.Format(_globalFormat, progress);
|
||
}
|
||
catch (System.FormatException)
|
||
{
|
||
_globalProgressText.text = $"{progress:P0}";
|
||
Debug.LogWarning($"[MapProgressDisplay] _globalFormat 格式字符串配置有误:'{_globalFormat}',已回退到默认显示。", this);
|
||
}
|
||
}
|
||
|
||
// 当前区域进度
|
||
if (_regionProgressText != null && !string.IsNullOrEmpty(_currentRegionId))
|
||
{
|
||
var rooms = _mapSvc.GetRoomsByRegion(_currentRegionId);
|
||
if (rooms != null && rooms.Length > 0)
|
||
{
|
||
int exploredCount = 0;
|
||
foreach (var r in rooms)
|
||
if (r != null && _mapSvc.IsExplored(r.RoomId)) exploredCount++;
|
||
float regionProgress = (float)exploredCount / rooms.Length;
|
||
// R15-N2 解析区域显示名(本地化 Key → DisplayName → RegionId 回退)
|
||
string regionDisplayName = ResolveRegionDisplayName(_currentRegionId);
|
||
try
|
||
{
|
||
_regionProgressText.text = string.Format(_regionFormat, regionProgress, regionDisplayName);
|
||
}
|
||
catch (System.FormatException)
|
||
{
|
||
_regionProgressText.text = $"{regionDisplayName}:{regionProgress:P0}";
|
||
Debug.LogWarning($"[MapProgressDisplay] _regionFormat 格式字符串配置有误:'{_regionFormat}',已回退到默认显示。", this);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// ── 辅助方法 ──────────────────────────────────────────────────────────
|
||
|
||
/// <summary>预建 RegionId → Entry 字典,O(1) 查询。</summary>
|
||
private void BuildRegionDict()
|
||
=> _regionDict = MapServiceExtensions.BuildRegionDict(_regionNames);
|
||
|
||
/// <summary>
|
||
/// 将 regionId 解析为玩家可读的显示名。
|
||
/// 优先读 LocKey(本地化),其次 DisplayName,最后回退到 regionId 本身。
|
||
/// </summary>
|
||
private string ResolveRegionDisplayName(string regionId)
|
||
=> MapServiceExtensions.ResolveRegionDisplayName(_regionDict, regionId);
|
||
}
|
||
}
|