Files
zeling_v2/Assets/_Game/Scripts/World/Map/MapInputHandler.cs
Joywayer f74d7f1877 Add independent review reports for Minimap system (Rounds 8, 9, and 26)
- 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.
2026-05-25 23:15:12 +08:00

128 lines
5.6 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 UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using BaseGames.Input;
namespace BaseGames.World.Map
{
/// <summary>
/// 全屏地图输入处理器(架构 15_MapShopModule §1.3.1)。
/// 挂在与 MapPanel 相同的 GameObject 上MapPanel OnEnable/OnDisable 联动启停)。
/// <list type="bullet">
/// <item>鼠标滚轮缩放(以鼠标位置为缩放中心)</item>
/// <item>方向键 / 摇杆平移(经由 InputReaderSO.NavigateEvent 派发)</item>
/// </list>
/// </summary>
[RequireComponent(typeof(MapPanel))]
public class MapInputHandler : MonoBehaviour, IScrollHandler
{
[SerializeField] private InputReaderSO _inputReader;
[SerializeField] private ScrollRect _scrollRect;
[SerializeField] private RectTransform _zoomTarget; // 通常为 _roomContainer格子根节点
[Header("缩放")]
[SerializeField, Range(0.2f, 1f)] private float _zoomMin = 0.4f;
[SerializeField, Range(1f, 5f)] private float _zoomMax = 3.0f;
[SerializeField, Range(0.05f, 0.5f)] private float _zoomStep = 0.12f;
[Header("平移")]
[SerializeField] private float _keyPanSpeed = 600f; // px / 秒
private Vector2 _navInput;
private MapPanel _panel;
private void Awake()
{
_panel = GetComponent<MapPanel>();
#if UNITY_EDITOR || DEVELOPMENT_BUILD
// R25-N2 _zoomTarget 须配置为 MapPanel 的格子根节点(与 _roomContainer 相同),
// 否则 OnScroll 写入的 scale 与 MapPanel.CurrentZoom 读取的 scale 将来自不同节点,导致静默状态分裂。
if (_zoomTarget == null)
Debug.LogWarning("[MapInputHandler] _zoomTarget 未配置,缩放功能将失效。请在 Inspector 中指定 MapPanel 的格子根节点_roomContainer。", this);
#endif
}
private void OnEnable()
{
if (_inputReader != null)
{
_inputReader.NavigateEvent += OnNavigate;
// R13-N4 居中到玩家快捷键
_inputReader.MapCenterEvent += OnMapCenter;
}
}
private void OnDisable()
{
_navInput = Vector2.zero;
if (_inputReader != null)
{
_inputReader.NavigateEvent -= OnNavigate;
_inputReader.MapCenterEvent -= OnMapCenter;
}
}
private void OnNavigate(Vector2 dir) => _navInput = dir;
// R13-N4 将视图居中到玩家所在房间
private void OnMapCenter() => _panel?.CenterOnCurrentRoom();
private void Update()
{
if (_scrollRect == null || _navInput == Vector2.zero) return;
// R18-N1 contentSize 需乘以当前缩放系数,否则缩放后平移速度感知偏差。
// R19-N1 / R24-N2 统一读 _panel.CurrentZoom_zoomTarget.localScale.x
// 消除独立 _zoom 字段与 CurrentZoom 的双份状态——OnScroll 直接写 localScale
// CurrentZoom 即时反映最新值,不再需要额外同步。
var content = _scrollRect.content;
var viewport = _scrollRect.viewport != null
? _scrollRect.viewport
: (RectTransform)_scrollRect.transform;
Vector2 contentSize = content.rect.size;
Vector2 viewportSize = viewport.rect.size;
float currentZoom = _panel != null ? _panel.CurrentZoom
: (_zoomTarget != null ? _zoomTarget.localScale.x : 1f);
float rangeX = contentSize.x * currentZoom - viewportSize.x;
float rangeY = contentSize.y * currentZoom - viewportSize.y;
if (rangeX <= 0f && rangeY <= 0f) return; // 内容比视口小,无需平移
Vector2 delta = _navInput * (_keyPanSpeed * Time.unscaledDeltaTime);
Vector2 norm = _scrollRect.normalizedPosition;
if (rangeX > 0f) norm.x = Mathf.Clamp01(norm.x + delta.x / rangeX);
if (rangeY > 0f) norm.y = Mathf.Clamp01(norm.y + delta.y / rangeY);
_scrollRect.normalizedPosition = norm;
}
// ── 鼠标滚轮缩放 ─────────────────────────────────────────────────────
public void OnScroll(PointerEventData eventData)
{
if (_zoomTarget == null) return;
// R24-N2 直接读 _zoomTarget.localScale.x 作为当前缩放,消除独立 _zoom 字段
float currentZoom = _zoomTarget.localScale.x;
float newZoom = Mathf.Clamp(
currentZoom + eventData.scrollDelta.y * _zoomStep,
_zoomMin, _zoomMax);
if (Mathf.Approximately(newZoom, currentZoom)) return;
// 将鼠标屏幕坐标转为 zoomTarget 本地坐标(缩放前)
RectTransformUtility.ScreenPointToLocalPointInRectangle(
_zoomTarget, eventData.position, eventData.pressEventCamera, out Vector2 pivotBefore);
_zoomTarget.localScale = new Vector3(newZoom, newZoom, 1f);
// 将同一屏幕点再次映射(缩放后),计算偏移量保持鼠标下方内容不动
RectTransformUtility.ScreenPointToLocalPointInRectangle(
_zoomTarget, eventData.position, eventData.pressEventCamera, out Vector2 pivotAfter);
Vector2 offset = pivotAfter - pivotBefore;
_zoomTarget.anchoredPosition += offset * newZoom;
}
}
}