Files
zeling_v2/Assets/_Game/Scripts/World/Map/MapManager.cs
Joywayer 5cb6c2a19d Add final evaluation report for Minimap system after all fixes and improvements
- Summarized the evolution of scores across five review rounds
- Detailed the status of each evaluation dimension post-fixes
- Highlighted remaining issues and recommended future work for further enhancements
- Compared current system against industry benchmarks
2026-05-25 14:25:19 +08:00

124 lines
5.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 System.Collections.Generic;
using System.Linq;
using UnityEngine;
using BaseGames.Core;
using BaseGames.Core.Events;
using BaseGames.Core.Save;
namespace BaseGames.World.Map
{
/// <summary>
/// 运行时地图管理器(架构 15_MapShopModule §1.2)。
/// 挂在 Persistent 场景 [GameManagers] 下,通过事件驱动记录已探索/已完整地图的房间。
/// 实现 ISaveable 持久化探索进度。
/// </summary>
[DefaultExecutionOrder(-700)]
public class MapManager : MonoBehaviour, ISaveable, IMapService
{
[SerializeField] private MapDatabaseSO _database;
[Header("Event Channels")]
[SerializeField] private StringEventChannelSO _onRoomEntered; // 订阅 EVT_RoomEntered
[SerializeField] private StringEventChannelSO _onMapUpdated; // 发布:房间发现时
[SerializeField] private StringEventChannelSO _onRegionChanged; // 发布玩家首次进入新区域时EVT_RegionChanged
// 三级可见性:
// Unknown → 未进入过(默认)
// Explored → 进入过(显示轮廓/格子)
// Mapped → 完整地图信息(购买 MapFragment 或存档点揭示)
private HashSet<string> _exploredRooms = new();
private HashSet<string> _mappedRooms = new();
private string _currentRegionId;
private int _totalRoomCount = -1; // -1 = 未缓存OnLoad 后重置
private readonly CompositeDisposable _subs = new();
private void Awake()
{
if (ServiceLocator.GetOrDefault<IMapService>() != null) { Destroy(gameObject); return; }
ServiceLocator.Register<IMapService>(this);
}
private void OnEnable()
{
_onRoomEntered?.Subscribe(OnRoomEntered).AddTo(_subs);
ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Register(this);
}
private void OnDisable()
{
_subs.Clear();
ServiceLocator.GetOrDefault<ISaveableRegistry>()?.Unregister(this);
}
// ── ISaveable ─────────────────────────────────────────────────────────
public void OnSave(SaveData data)
{
data.Map.ExploredRooms = new HashSet<string>(_exploredRooms);
data.Map.MappedRooms = new HashSet<string>(_mappedRooms);
}
public void OnLoad(SaveData data)
{
_exploredRooms = data.Map.ExploredRooms != null ? new HashSet<string>(data.Map.ExploredRooms) : new HashSet<string>();
_mappedRooms = data.Map.MappedRooms != null ? new HashSet<string>(data.Map.MappedRooms) : new HashSet<string>();
_totalRoomCount = -1; // 强制下次调用 GetExplorationProgress 时重新计数
}
// ── 事件驱动房间发现 ──────────────────────────────────────────────────
private void OnRoomEntered(string roomId)
{
bool changed = _exploredRooms.Add(roomId);
if (changed) _onMapUpdated?.Raise(roomId);
// 区域变化检测RegionId 非空且与上一次不同时广播 EVT_RegionChanged
var regionId = _database?.GetRoom(roomId)?.RegionId;
if (!string.IsNullOrEmpty(regionId) && regionId != _currentRegionId)
{
_currentRegionId = regionId;
_onRegionChanged?.Raise(regionId);
}
}
/// <summary>
/// 标记为已获取地图碎片信息(购买 MapFragment SO 触发)。
/// 仅写入 _mappedRooms若玩家尚未亲自踏入该房间则显示为灰色轮廓Mapped
/// 亲自踏入后Explored优先级更高显示为白色。
/// </summary>
public void SetMapped(string roomId)
{
if (_mappedRooms.Add(roomId))
_onMapUpdated?.Raise(roomId);
}
// ── 查询 API ──────────────────────────────────────────────────────────
public bool IsExplored(string roomId) => _exploredRooms.Contains(roomId);
public bool IsMapped(string roomId) => _mappedRooms.Contains(roomId);
public string CurrentRegionId => _currentRegionId;
public MapDatabaseSO Database => _database;
public int ExploredRoomCount => _exploredRooms.Count;
public float GetExplorationProgress()
{
if (_database?.AllRooms == null || _database.AllRooms.Length == 0) return 0f;
if (_totalRoomCount < 0)
_totalRoomCount = _database.AllRooms.Count(r => r != null);
return _totalRoomCount > 0 ? Mathf.Clamp01((float)_exploredRooms.Count / _totalRoomCount) : 0f;
}
public MapRoomDataSO[] GetRoomsByRegion(string regionId)
{
if (string.IsNullOrEmpty(regionId) || _database?.AllRooms == null)
return System.Array.Empty<MapRoomDataSO>();
return _database.AllRooms.Where(r => r != null && r.RegionId == regionId).ToArray();
}
private void OnDestroy()
{
ServiceLocator.Unregister<IMapService>(this);
}
}
}