(client) feat:UI更新 chore:LogUI性能更好,并且修复反复打开Log消失的bug,删除部分非预期的警告
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Utils;
|
||||
using Utils; // 假设此命名空间包含MonoSingleton
|
||||
|
||||
namespace Base
|
||||
{
|
||||
@ -25,120 +25,239 @@ namespace Base
|
||||
private bool _pause = false;
|
||||
public bool Pause
|
||||
{
|
||||
get
|
||||
{
|
||||
return _pause;
|
||||
}
|
||||
get => _pause;
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
if (value != _pause) // 逻辑修改说明:避免重复设置Time.timeScale
|
||||
{
|
||||
Time.timeScale = 0;
|
||||
Time.timeScale = value ? 0 : 1;
|
||||
_pause = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
Time.timeScale = 1;
|
||||
}
|
||||
_pause = value;
|
||||
}
|
||||
}
|
||||
public List<ITickPhysics> tickPhysics = new();
|
||||
public List<ITick> ticks = new();
|
||||
public List<ITickUI> tickUIs = new();
|
||||
|
||||
// 修改点 1.1:主列表用于迭代
|
||||
private readonly List<ITick> _ticks = new();
|
||||
private readonly List<ITickPhysics> _tickPhysics = new();
|
||||
private readonly List<ITickUI> _tickUIs = new();
|
||||
|
||||
// 修改点 1.1:缓冲列表用于添加
|
||||
private readonly HashSet<ITick> _ticksToAdd = new(); // 逻辑修改说明:使用HashSet避免重复添加,提高查找效率
|
||||
private readonly HashSet<ITickPhysics> _tickPhysicsToAdd = new();
|
||||
private readonly HashSet<ITickUI> _tickUIsToAdd = new();
|
||||
|
||||
// 修改点 1.1:缓冲列表用于移除
|
||||
private readonly HashSet<ITick> _ticksToRemove = new(); // 逻辑修改说明:使用HashSet避免重复移除,提高查找效率
|
||||
private readonly HashSet<ITickPhysics> _tickPhysicsToRemove = new();
|
||||
private readonly HashSet<ITickUI> _tickUIsToRemove = new();
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// 逻辑修改说明:UI部分的Tick不应受_pause影响
|
||||
if (!_pause)
|
||||
foreach (var tick in ticks)
|
||||
{
|
||||
// 逻辑修改说明:迭代时使用只读副本或确保不会被修改
|
||||
// 这里是直接迭代_ticks,确保_ticks在Update生命周期内不会被Add/Remove直接修改
|
||||
// 添加和移除操作通过缓冲区在LateUpdate处理
|
||||
foreach (var tick in _ticks)
|
||||
{
|
||||
tick.Tick();
|
||||
|
||||
foreach (var uiTick in tickUIs) uiTick.TickUI();
|
||||
//if (timer > 1)
|
||||
//{
|
||||
// timer -= 1;
|
||||
// Debug.Log("滴答");
|
||||
//}
|
||||
//timer += Time.deltaTime;
|
||||
}
|
||||
}
|
||||
// UI更新通常不受游戏暂停影响(例如菜单动画、UI计时器等),除非UI本身也需要暂停逻辑。
|
||||
// 根据需求决定是否受_pause影响。此处假设UI不暂停。
|
||||
foreach (var uiTick in _tickUIs)
|
||||
{
|
||||
uiTick.TickUI();
|
||||
}
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
if (!_pause)
|
||||
foreach (var physicsTick in tickPhysics)
|
||||
{
|
||||
foreach (var physicsTick in _tickPhysics)
|
||||
{
|
||||
physicsTick.TickPhysics();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 修改点 1.4:在LateUpdate应用缓冲区的更改
|
||||
private void LateUpdate()
|
||||
{
|
||||
ApplyBufferedChanges();
|
||||
}
|
||||
|
||||
// 修改点 3.1:OnDestroy保持不变,确保事件移除
|
||||
private void OnDestroy()
|
||||
{
|
||||
// 移除事件监听
|
||||
SceneManager.sceneLoaded -= OnSceneLoaded;
|
||||
}
|
||||
|
||||
protected override void OnStart()
|
||||
// 修改点 3.1:OnStart保持不变,负责事件注册和初始化
|
||||
protected override void OnStart() // MonoSingleton的Awake后调用
|
||||
{
|
||||
// 注册场景加载事件
|
||||
SceneManager.sceneLoaded += OnSceneLoaded;
|
||||
|
||||
// 初始化时调用一次
|
||||
Init();
|
||||
// 逻辑修改说明:Initial清理所有列表,而不是填充
|
||||
Init();
|
||||
}
|
||||
|
||||
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
||||
{
|
||||
// 场景加载完成后调用 Init 方法
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化方法
|
||||
/// 初始化/重置方法。清空所有注册列表和缓冲列表。
|
||||
/// </summary>
|
||||
// 修改点 2.1:Init() 方法不再负责FindObjectsByType
|
||||
public void Init()
|
||||
{
|
||||
ticks.Clear();
|
||||
tickPhysics.Clear();
|
||||
tickUIs.Clear();
|
||||
_ticks.Clear();
|
||||
_tickPhysics.Clear();
|
||||
_tickUIs.Clear();
|
||||
|
||||
_ticksToAdd.Clear();
|
||||
_tickPhysicsToAdd.Clear();
|
||||
_tickUIsToAdd.Clear();
|
||||
|
||||
_ticksToRemove.Clear();
|
||||
_tickPhysicsToRemove.Clear();
|
||||
_tickUIsToRemove.Clear();
|
||||
|
||||
// 逻辑修改说明:移除 FindObjectsByType 逻辑
|
||||
// 对象应通过其各自的 OnEnable/OnDisable 生命周期来注册/反注册
|
||||
foreach (var obj in FindObjectsByType<MonoBehaviour>(FindObjectsSortMode.None))
|
||||
{
|
||||
if (obj is ITick tickObj) ticks.Add(tickObj);
|
||||
if (obj is ITickPhysics physicsObj) tickPhysics.Add(physicsObj);
|
||||
if (obj is ITickUI uiObj) tickUIs.Add(uiObj);
|
||||
if (obj is ITick tickObj) _ticks.Add(tickObj);
|
||||
if (obj is ITickPhysics physicsObj) _tickPhysics.Add(physicsObj);
|
||||
if (obj is ITickUI uiObj) _tickUIs.Add(uiObj);
|
||||
}
|
||||
}
|
||||
|
||||
// 修改点 1.2 & 1.3:将更改放入缓冲,并在LateUpdate统一处理
|
||||
public static void AddTick(ITick tick)
|
||||
{
|
||||
if (Instance != null && !Instance.ticks.Contains(tick))
|
||||
Instance.ticks.Add(tick);
|
||||
if (Instance != null && tick != null) // 逻辑修改说明:添加null检查
|
||||
{
|
||||
Instance._ticksToAdd.Add(tick);
|
||||
Instance._ticksToRemove.Remove(tick); // 逻辑修改说明:如果在待移除列表,则先移除
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveTick(ITick tick)
|
||||
{
|
||||
if (Instance != null)
|
||||
Instance.ticks.Remove(tick);
|
||||
if (Instance != null && tick != null) // 逻辑修改说明:添加null检查
|
||||
{
|
||||
Instance._ticksToRemove.Add(tick);
|
||||
Instance._ticksToAdd.Remove(tick); // 逻辑修改说明:如果在待添加列表,则先移除
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddTickPhysics(ITickPhysics physics)
|
||||
{
|
||||
if (Instance != null && !Instance.tickPhysics.Contains(physics))
|
||||
Instance.tickPhysics.Add(physics);
|
||||
if (Instance != null && physics != null)
|
||||
{
|
||||
Instance._tickPhysicsToAdd.Add(physics);
|
||||
Instance._tickPhysicsToRemove.Remove(physics);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveTickPhysics(ITickPhysics physics)
|
||||
{
|
||||
if (Instance != null)
|
||||
Instance.tickPhysics.Remove(physics);
|
||||
if (Instance != null && physics != null)
|
||||
{
|
||||
Instance._tickPhysicsToRemove.Add(physics);
|
||||
Instance._tickPhysicsToAdd.Remove(physics);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddTickUI(ITickUI ui)
|
||||
{
|
||||
if (Instance != null && !Instance.tickUIs.Contains(ui))
|
||||
Instance.tickUIs.Add(ui);
|
||||
if (Instance != null && ui != null)
|
||||
{
|
||||
Instance._tickUIsToAdd.Add(ui);
|
||||
Instance._tickUIsToRemove.Remove(ui);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveTickUI(ITickUI ui)
|
||||
{
|
||||
if (Instance != null)
|
||||
Instance.tickUIs.Remove(ui);
|
||||
if (Instance != null && ui != null)
|
||||
{
|
||||
Instance._tickUIsToRemove.Add(ui);
|
||||
Instance._tickUIsToAdd.Remove(ui);
|
||||
}
|
||||
}
|
||||
|
||||
// 修改点 1.3:应用缓冲区的更改
|
||||
private void ApplyBufferedChanges()
|
||||
{
|
||||
// 先处理移除
|
||||
if (_ticksToRemove.Count > 0)
|
||||
{
|
||||
foreach (var tick in _ticksToRemove)
|
||||
{
|
||||
_ticks.Remove(tick);
|
||||
}
|
||||
_ticksToRemove.Clear();
|
||||
}
|
||||
|
||||
if (_tickPhysicsToRemove.Count > 0)
|
||||
{
|
||||
foreach (var physicsTick in _tickPhysicsToRemove)
|
||||
{
|
||||
_tickPhysics.Remove(physicsTick);
|
||||
}
|
||||
_tickPhysicsToRemove.Clear();
|
||||
}
|
||||
|
||||
if (_tickUIsToRemove.Count > 0)
|
||||
{
|
||||
foreach (var uiTick in _tickUIsToRemove)
|
||||
{
|
||||
_tickUIs.Remove(uiTick);
|
||||
}
|
||||
_tickUIsToRemove.Clear();
|
||||
}
|
||||
|
||||
// 后处理添加
|
||||
if (_ticksToAdd.Count > 0)
|
||||
{
|
||||
foreach (var tick in _ticksToAdd)
|
||||
{
|
||||
if (!_ticks.Contains(tick)) // 逻辑修改说明:避免重复添加到主列表
|
||||
{
|
||||
_ticks.Add(tick);
|
||||
}
|
||||
}
|
||||
_ticksToAdd.Clear();
|
||||
}
|
||||
|
||||
if (_tickPhysicsToAdd.Count > 0)
|
||||
{
|
||||
foreach (var physicsTick in _tickPhysicsToAdd)
|
||||
{
|
||||
if (!_tickPhysics.Contains(physicsTick))
|
||||
{
|
||||
_tickPhysics.Add(physicsTick);
|
||||
}
|
||||
}
|
||||
_tickPhysicsToAdd.Clear();
|
||||
}
|
||||
|
||||
if (_tickUIsToAdd.Count > 0)
|
||||
{
|
||||
foreach (var uiTick in _tickUIsToAdd)
|
||||
{
|
||||
if (!_tickUIs.Contains(uiTick))
|
||||
{
|
||||
_tickUIs.Add(uiTick);
|
||||
}
|
||||
}
|
||||
_tickUIsToAdd.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -202,8 +202,6 @@ namespace Base
|
||||
protected override void OnStart()
|
||||
{
|
||||
SceneManager.sceneLoaded += OnSceneLoaded;
|
||||
|
||||
RegisterAllWindows();
|
||||
}
|
||||
|
||||
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
||||
|
@ -19,41 +19,61 @@ namespace CameraControl
|
||||
private Vector3 _dragOrigin; // 拖拽操作的起始世界坐标
|
||||
private bool _isDragging; // 标记摄像机是否正在被拖拽
|
||||
|
||||
private Camera _camera; // 当前场景中的主摄像机引用
|
||||
private Camera _cachedCamera; // 缓存的场景摄像机引用
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前生效的场景摄像机。懒加载并缓存。
|
||||
/// </summary>
|
||||
public Camera CurrentCamera
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_cachedCamera)
|
||||
{
|
||||
Debug.Log("[CameraControl] Attempting to get main camera...");
|
||||
_cachedCamera = Camera.main; // 尝试获取主摄像机
|
||||
if (!_cachedCamera) // 如果主摄像机不存在或未标记,则尝试查找场景中的第一个摄像机
|
||||
{
|
||||
Debug.LogWarning("[CameraControl] Main camera not found, attempting to find first object of type Camera.");
|
||||
_cachedCamera = FindFirstObjectByType<Camera>();
|
||||
}
|
||||
|
||||
if (!_cachedCamera)
|
||||
{
|
||||
Debug.LogError("[CameraControl] No available camera found in scene! CameraControl functionality will be limited.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log($"[CameraControl] Camera cached: {_cachedCamera.name}");
|
||||
}
|
||||
}
|
||||
return _cachedCamera;
|
||||
}
|
||||
}
|
||||
|
||||
private int dimensionId; // 当前摄像机控制器关注的维度索引
|
||||
private string[] dimensionList; // 维度名称列表
|
||||
|
||||
/// <summary>
|
||||
/// MonoSingleton 的 OnStart 方法,在单例首次创建并激活时调用,早于普通的 Start 方法。
|
||||
/// 用于初始化摄像机缓存。
|
||||
/// </summary>
|
||||
protected override void OnStart()
|
||||
{
|
||||
Debug.Log("[CameraControl] OnStart called. Subscribing to OnFocusedDimensionChanged event.");
|
||||
Program.Instance.OnFocusedDimensionChanged += Init;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当脚本实例被销毁时调用。
|
||||
/// 用于取消订阅 Program.Instance 的事件,防止内存泄漏。
|
||||
/// </summary>
|
||||
private void OnDestroy()
|
||||
{
|
||||
// 在OnDestroy时进行Program.Instance检查是合理的,因为Program实例可能已被销毁。
|
||||
if (Program.Instance != null)
|
||||
{
|
||||
Program.Instance.OnFocusedDimensionChanged -= Init;
|
||||
}
|
||||
Debug.Log("[CameraControl] OnDestroy called. Unsubscribing from OnFocusedDimensionChanged event.");
|
||||
Program.Instance.OnFocusedDimensionChanged -= Init;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 脚本实例在第一次帧更新之前被启用时调用。
|
||||
/// 用于订阅 Program.Instance 的事件,并进行初始设置。
|
||||
/// </summary>
|
||||
private void Start()
|
||||
{
|
||||
// 在Start时进行Program.Instance检查是合理的,防止CameraControl比Program实例更早启动。
|
||||
if (Program.Instance != null)
|
||||
{
|
||||
Program.Instance.OnFocusedDimensionChanged += Init; // 订阅聚焦维度改变事件
|
||||
Init(); // 首次调用初始化,根据当前聚焦维度设置摄像机状态
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("CameraControl 的 Start 方法中 Program.Instance 为空。请检查 Program 单例的初始化顺序。摄像机控制功能将无法初始化。");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据指定的维度对象初始化摄像机控制器。
|
||||
@ -62,36 +82,21 @@ namespace CameraControl
|
||||
/// <param name="obj">当前聚焦的维度对象。</param>
|
||||
private void Init(Dimension obj)
|
||||
{
|
||||
// 修改点 1: 统一 Unity 对象 `null` 检查,移除冗余 `_camera == null`
|
||||
// 确保相机引用有效,如果为空则尝试获取主相机
|
||||
if (!_camera)
|
||||
{
|
||||
_camera = Camera.main;
|
||||
if (!_camera) // 再次检查获取是否成功
|
||||
{
|
||||
_camera = FindFirstObjectByType<Camera>();
|
||||
}
|
||||
}
|
||||
Debug.Log($"[CameraControl] Init(Dimension obj) called. Focused Dimension: {(obj != null ? obj.name : "null")}");
|
||||
|
||||
if (!_camera) // 如果到此为止仍未获取到相机,记录错误并返回
|
||||
dimensionList = Program.Instance.Dimensions;
|
||||
Debug.Log($"[CameraControl] Dimension list updated. Count: {(dimensionList != null ? dimensionList.Length.ToString() : "null")}");
|
||||
|
||||
if (!CurrentCamera) // 如果摄像机仍未找到,记录错误并返回
|
||||
{
|
||||
Debug.LogError("场景中未找到摄像机!CameraControl 功能将无法完全初始化。");
|
||||
// 如果没有相机,后续依赖相机的逻辑都无法执行,直接返回。
|
||||
// dimensionList 的获取如果逻辑上不依赖相机,可以放在此处之外。
|
||||
// 但当前上下文中,Init的主要目的是初始化相机视角等,无相机则无意义。
|
||||
Debug.LogError("[CameraControl] No camera found! CameraControl functionality will not be fully initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 修改点 2: 移除对 `Program.Instance` 的冗余 `null` 检查
|
||||
// 修改点 3: `Init` 方法中 `dimensionList` 的获取位置
|
||||
// 总是获取最新的维度列表,因为外部维度状态可能会变化
|
||||
dimensionList = Program.Instance.Dimensions;
|
||||
|
||||
// 处理 obj 为 null 的情况
|
||||
// 处理 obj 为 null 的情况 - 此时 dimensionList 已更新
|
||||
if (!obj)
|
||||
{
|
||||
Debug.LogWarning("Init 方法在聚焦维度为空的情况下被调用。维度列表已更新,但摄像机状态未根据特定维度设置。");
|
||||
// 此时 dimensionId 仍然是默认值或上次设置的值,不进行 cameraPosition 的设置。
|
||||
Debug.LogWarning("[CameraControl] Init method called with a null focused dimension. Dimension list updated, but camera state not set based on a specific dimension.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -100,15 +105,24 @@ namespace CameraControl
|
||||
if (focusedIndex != -1)
|
||||
{
|
||||
dimensionId = focusedIndex;
|
||||
Debug.Log($"[CameraControl] Focused dimension '{obj.name}' found at index {dimensionId}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"聚焦维度 '{obj.name}' 未在维度列表中找到。回退到 ID 0。");
|
||||
Debug.LogWarning($"[CameraControl] Focused dimension '{obj.name}' not found in the dimension list. Falling back to ID 0.");
|
||||
dimensionId = 0; // 找不到时,回退到第一个维度,避免数组越界
|
||||
}
|
||||
|
||||
// 设置摄像机位置到当前聚焦维度的位置 (移除 Program.Instance 的 null 检查)
|
||||
_camera.transform.position = Program.Instance.FocusedDimension.cameraPosition;
|
||||
// 设置摄像机位置到当前聚焦维度的位置
|
||||
if (Program.Instance.FocusedDimension != null)
|
||||
{
|
||||
CurrentCamera.transform.position = Program.Instance.FocusedDimension.cameraPosition;
|
||||
Debug.Log($"[CameraControl] Camera position set to focused dimension's camera position: {CurrentCamera.transform.position}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("[CameraControl] Focused dimension is null when trying to set camera position. Camera position not explicitly updated based on a dimension.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -116,7 +130,7 @@ namespace CameraControl
|
||||
/// </summary>
|
||||
private void Init()
|
||||
{
|
||||
// 移除 Program.Instance 的 null 检查
|
||||
Debug.Log("[CameraControl] Init() called (no parameters). Calling Init(Program.Instance.FocusedDimension).");
|
||||
Init(Program.Instance.FocusedDimension);
|
||||
}
|
||||
|
||||
@ -126,41 +140,44 @@ namespace CameraControl
|
||||
/// </summary>
|
||||
public void NextDimension()
|
||||
{
|
||||
// 修改点 1: 统一 Unity 对象 `null` 检查
|
||||
if (!_camera)
|
||||
Debug.Log("[CameraControl] NextDimension called.");
|
||||
|
||||
if (!CurrentCamera)
|
||||
{
|
||||
Debug.LogWarning("摄像机引用为空,无法切换维度。");
|
||||
Debug.LogWarning("[CameraControl] Camera reference is null, cannot switch dimensions.");
|
||||
return;
|
||||
}
|
||||
if (dimensionList == null || dimensionList.Length == 0)
|
||||
{
|
||||
Debug.LogWarning("维度列表为空。");
|
||||
Debug.LogWarning("[CameraControl] Dimension list is empty or uninitialized, cannot switch dimensions.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 保存当前摄像机的实际位置到当前维度 (移除 Program.Instance 的 null 检查)
|
||||
// 1. 保存当前摄像机的实际位置到当前维度
|
||||
if (dimensionId >= 0 && dimensionId < dimensionList.Length)
|
||||
{
|
||||
var currentDimension = Program.Instance.GetDimension(dimensionList[dimensionId]);
|
||||
if (currentDimension != null) // currentDimension 可能是普通 C# 对象,所以此处 null 检查是必要的
|
||||
if (currentDimension != null)
|
||||
{
|
||||
currentDimension.cameraPosition = _camera.transform.position;
|
||||
currentDimension.cameraPosition = CurrentCamera.transform.position;
|
||||
Debug.Log($"[CameraControl] Saved current camera position {CurrentCamera.transform.position} to dimension '{dimensionList[dimensionId]}'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"无法找到 ID 为 {dimensionId} ({dimensionList[dimensionId]}) 的维度对象,无法保存摄像机位置。");
|
||||
Debug.LogWarning($"[CameraControl] Could not find Dimension object for ID {dimensionId} ({dimensionList[dimensionId]}), cannot save camera position.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"当前维度ID ({dimensionId}) 超出范围,无法保存摄像机位置 (维度列表长度: {dimensionList.Length})。");
|
||||
Debug.LogWarning($"[CameraControl] Current dimension ID ({dimensionId}) is out of range, cannot save camera position (Dimension list length: {dimensionList.Length}).");
|
||||
}
|
||||
|
||||
// 2. 更新 dimensionId,形成循环切换
|
||||
// 2. 更新 dimensionId, 形成循环切换
|
||||
dimensionId = (dimensionId + 1) % dimensionList.Length;
|
||||
Debug.Log($"[CameraControl] Updated dimensionId to {dimensionId}.");
|
||||
|
||||
// 3. 更新聚焦维度,摄像机位置的更新将由事件触发的 Init 方法处理
|
||||
SetCameraPositionForDimension(dimensionId);
|
||||
SetFocusedDimensionById(dimensionId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -168,21 +185,22 @@ namespace CameraControl
|
||||
/// 摄像机位置的实际更新将通过 Program.Instance.OnFocusedDimensionChanged 事件在 Init(Dimension obj) 方法中处理。
|
||||
/// </summary>
|
||||
/// <param name="id">要设置的维度ID。</param>
|
||||
private void SetCameraPositionForDimension(int id)
|
||||
private void SetFocusedDimensionById(int id)
|
||||
{
|
||||
// 修改点 1: 统一 Unity 对象 `null` 检查
|
||||
if (!_camera)
|
||||
Debug.Log($"[CameraControl] SetFocusedDimensionById called with ID: {id}.");
|
||||
|
||||
if (!CurrentCamera)
|
||||
{
|
||||
Debug.LogWarning("摄像机引用为空,无法设置摄像机位置。");
|
||||
Debug.LogWarning("[CameraControl] Camera reference is null, cannot set camera position.");
|
||||
return;
|
||||
}
|
||||
if (dimensionList == null || id < 0 || id >= dimensionList.Length)
|
||||
{
|
||||
Debug.LogWarning($"维度ID {id} 超出范围或维度列表为空。");
|
||||
Debug.LogWarning($"[CameraControl] Dimension ID {id} is out of range or dimension list is empty, cannot set focused dimension.");
|
||||
return;
|
||||
}
|
||||
// 移除 Program.Instance 的 null 检查
|
||||
Program.Instance.SetFocusedDimension(dimensionList[id]);
|
||||
Debug.Log($"[CameraControl] Program.Instance.SetFocusedDimension called for '{dimensionList[id]}'.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -190,20 +208,19 @@ namespace CameraControl
|
||||
/// </summary>
|
||||
public void Tick()
|
||||
{
|
||||
// 修改点 1: 统一 Unity 对象 `null` 检查
|
||||
if (!_camera) return; // 确保相机存在
|
||||
if (!CurrentCamera) return; // 确保相机存在
|
||||
|
||||
// 当没有拖拽且存在聚焦实体时,摄像机跟随聚焦实体 (移除 Program.Instance 的 null 检查)
|
||||
// 当没有拖拽且存在聚焦实体时,摄像机跟随聚焦实体
|
||||
if (!_isDragging && Program.Instance.FocusedEntity)
|
||||
{
|
||||
var targetPosition = new Vector3(
|
||||
Program.Instance.FocusedEntity.Position.x,
|
||||
Program.Instance.FocusedEntity.Position.y,
|
||||
_camera.transform.position.z);
|
||||
CurrentCamera.transform.position.z);
|
||||
|
||||
// 使用 deltaTime 进行平滑的摄像机跟随
|
||||
_camera.transform.position = Vector3.Lerp(
|
||||
_camera.transform.position,
|
||||
CurrentCamera.transform.position = Vector3.Lerp(
|
||||
CurrentCamera.transform.position,
|
||||
targetPosition,
|
||||
Time.deltaTime * _focusLerpSpeed);
|
||||
}
|
||||
@ -211,6 +228,7 @@ namespace CameraControl
|
||||
// 按下 Tab 键时切换到下一个维度
|
||||
if (Input.GetKeyDown(KeyCode.Tab))
|
||||
{
|
||||
Debug.Log("[CameraControl] Tab key pressed. Calling NextDimension().");
|
||||
NextDimension();
|
||||
}
|
||||
}
|
||||
@ -220,8 +238,7 @@ namespace CameraControl
|
||||
/// </summary>
|
||||
public void TickUI()
|
||||
{
|
||||
// 修改点 1: 统一 Unity 对象 `null` 检查
|
||||
if (!_camera) // 确保相机存在
|
||||
if (!CurrentCamera) // 确保相机存在
|
||||
return;
|
||||
|
||||
HandleMiddleMouseDrag(); // 处理鼠标中键拖拽
|
||||
@ -234,11 +251,15 @@ namespace CameraControl
|
||||
/// <param name="position">要设置的摄像机位置。</param>
|
||||
public void SetPosition(Vector3 position)
|
||||
{
|
||||
// 修改点 1: 统一 Unity 对象 `null` 检查
|
||||
if (_camera) // if (!_camera) 比 if (_camera == null) 更优雅
|
||||
_camera.transform.position = position;
|
||||
if (CurrentCamera)
|
||||
{
|
||||
CurrentCamera.transform.position = position;
|
||||
Debug.Log($"[CameraControl] Camera position explicitly set to: {position}.");
|
||||
}
|
||||
else
|
||||
Debug.LogWarning("摄像机引用为空,无法设置位置。");
|
||||
{
|
||||
Debug.LogWarning("[CameraControl] Camera reference is null, cannot set position.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -246,17 +267,18 @@ namespace CameraControl
|
||||
/// </summary>
|
||||
private void HandleMiddleMouseDrag()
|
||||
{
|
||||
// 修改点 1: 统一 Unity 对象 `null` 检查
|
||||
if (!_camera) return; // 确保相机存在
|
||||
if (!CurrentCamera) return; // 确保相机存在
|
||||
|
||||
// 开始拖拽:检测鼠标中键按下
|
||||
if (Input.GetMouseButtonDown(2)) // 鼠标中键
|
||||
{
|
||||
_dragOrigin = _camera.ScreenToWorldPoint(Input.mousePosition);
|
||||
_dragOrigin = CurrentCamera.ScreenToWorldPoint(Input.mousePosition);
|
||||
_isDragging = true;
|
||||
// 如果有聚焦实体,则在开始拖拽时取消聚焦,暂停跟随 (移除 Program.Instance 的 null 检查)
|
||||
Debug.Log($"[CameraControl] Mouse middle button down. Starting drag from world point: {_dragOrigin}.");
|
||||
// 如果有聚焦实体,则在开始拖拽时取消聚焦,暂停跟随
|
||||
if (Program.Instance.FocusedEntity)
|
||||
{
|
||||
Debug.Log("[CameraControl] Focused entity detected. Setting FocusedEntity to null to pause follow.");
|
||||
Program.Instance.SetFocusedEntity(null);
|
||||
}
|
||||
}
|
||||
@ -264,15 +286,15 @@ namespace CameraControl
|
||||
// 拖拽中:根据鼠标移动更新摄像机位置
|
||||
if (Input.GetMouseButton(2) && _isDragging)
|
||||
{
|
||||
var difference = _dragOrigin - _camera.ScreenToWorldPoint(Input.mousePosition);
|
||||
_camera.transform.position += difference;
|
||||
var difference = _dragOrigin - CurrentCamera.ScreenToWorldPoint(Input.mousePosition);
|
||||
CurrentCamera.transform.position += difference;
|
||||
}
|
||||
|
||||
// 结束拖拽:检测鼠标中键抬起
|
||||
if (Input.GetMouseButtonUp(2))
|
||||
{
|
||||
_isDragging = false;
|
||||
// 拖拽结束后,当前代码不会自动重新聚焦实体。如果需要此行为,应在此处添加逻辑。
|
||||
Debug.Log("[CameraControl] Mouse middle button up. Dragging ended.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -281,23 +303,15 @@ namespace CameraControl
|
||||
/// </summary>
|
||||
private void HandleMouseZoom()
|
||||
{
|
||||
// 修改点 1: 统一 Unity 对象 `null` 检查
|
||||
if (!_camera) return; // 确保相机存在
|
||||
if (!CurrentCamera) return; // 确保相机存在
|
||||
|
||||
var scroll = Input.GetAxis("Mouse ScrollWheel");
|
||||
if (scroll == 0) return; // 没有滚轮滚动,则返回
|
||||
|
||||
// 根据滚轮输入调整正交摄像机的尺寸,并限制在最小和最大缩放之间
|
||||
var newSize = _camera.orthographicSize - scroll * _zoomSpeed;
|
||||
_camera.orthographicSize = Mathf.Clamp(newSize, _minZoom, _maxZoom);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MonoSingleton 的 OnStart 方法,可在单例首次创建时添加额外初始化逻辑。
|
||||
/// </summary>
|
||||
protected override void OnStart()
|
||||
{
|
||||
// 当前为空,是合理的。
|
||||
var newSize = CurrentCamera.orthographicSize - scroll * _zoomSpeed;
|
||||
CurrentCamera.orthographicSize = Mathf.Clamp(newSize, _minZoom, _maxZoom);
|
||||
// Debug.Log($"[CameraControl] Mouse scroll wheel. New orthographicSize: {CurrentCamera.orthographicSize}"); // Too frequent for general logging
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,6 +195,8 @@ namespace Entity
|
||||
|
||||
protected virtual void InitWeaponAnimator()
|
||||
{
|
||||
if (!weaponAnimator)
|
||||
return;
|
||||
for (var i = 0; i < weaponAnimator.transform.childCount; i++)
|
||||
{
|
||||
Destroy(weaponAnimator.transform.GetChild(i).gameObject);
|
||||
@ -527,8 +529,6 @@ namespace Entity
|
||||
// 暂时设定为:如果没有武器,则不进行攻击
|
||||
if (currentWeapon == null)
|
||||
{
|
||||
// 可以在这里添加一个默认的徒手攻击逻辑,或者播放一个“不能攻击”的提示
|
||||
Debug.Log($"{name} 没有装备武器,无法攻击。");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -49,13 +49,6 @@ namespace Item
|
||||
$"ItemResource: Failed to load sprite for texture '{texture}' for item '{def.defName}'.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 仅当 textures 为 null 时警告,因为它可能是预期的数据状态(无图标)
|
||||
Debug.LogWarning(
|
||||
$"ItemResource: ItemDef '{def.defName}' has a null textures array. No icons will be loaded.");
|
||||
}
|
||||
|
||||
// 逻辑修改:Icon 属性现在是 IReadOnlyList<Sprite> 类型,确保外部只读访问
|
||||
Icon = sprites.AsReadOnly(); // 使用 AsReadOnly() 获得一个只读包装器
|
||||
}
|
||||
|
@ -14,14 +14,21 @@ namespace Logging
|
||||
public string Message;
|
||||
public string StackTrace;
|
||||
|
||||
public override string ToString() =>
|
||||
$"[{Timestamp:HH:mm:ss}] [{Type}] {Message}" +
|
||||
(Type == LogType.Exception ? $"\n{StackTrace}" : "");
|
||||
public override string ToString()
|
||||
{
|
||||
// 逻辑修改:扩展条件,使LogType.Error和LogType.Assert也能显示堆栈信息
|
||||
if (Type == LogType.Exception || Type == LogType.Error || Type == LogType.Assert)
|
||||
{
|
||||
return $"[{Timestamp:HH:mm:ss}] [{Type}] {Message}\n{StackTrace}";
|
||||
}
|
||||
return $"[{Timestamp:HH:mm:ss}] [{Type}] {Message}";
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Queue<LogEntry> _logs = new Queue<LogEntry>();
|
||||
private static readonly object _lock = new object(); // 线程锁
|
||||
private static int _maxLogs = 1000; // 默认容量
|
||||
private static bool _isInitialized = false; // 逻辑修改:添加一个私有标志来跟踪是否已初始化
|
||||
|
||||
// 最大日志容量属性
|
||||
public static int MaxLogs
|
||||
@ -35,10 +42,40 @@ namespace Logging
|
||||
}
|
||||
}
|
||||
|
||||
// 逻辑修改:添加 [RuntimeInitializeOnLoadMethod] 特性,确保 Init() 方法在 Unity 启动时自动执行
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
|
||||
public static void Init()
|
||||
{
|
||||
Application.logMessageReceivedThreaded += HandleLog;
|
||||
|
||||
// 确保线程安全地检查和设置初始化状态
|
||||
lock (_lock)
|
||||
{
|
||||
if (_isInitialized)
|
||||
{
|
||||
Debug.LogWarning("[LogCapturer] Init() called multiple times. LogCapturer is already initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
Application.logMessageReceivedThreaded += HandleLog;
|
||||
_isInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 逻辑修改:添加一个 Shutdown 方法来解除事件注册和清理
|
||||
public static void Shutdown()
|
||||
{
|
||||
// 确保线程安全地检查和解除注册
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_isInitialized)
|
||||
{
|
||||
Debug.LogWarning("[LogCapturer] Shutdown() called but LogCapturer was not initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
Application.logMessageReceivedThreaded -= HandleLog;
|
||||
_isInitialized = false;
|
||||
_logs.Clear(); // 逻辑修改:在关闭时清空所有捕获的日志,确保下次启用时是全新状态。
|
||||
}
|
||||
}
|
||||
|
||||
// 日志处理回调
|
||||
@ -88,4 +125,4 @@ namespace Logging
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ namespace Logging
|
||||
public void Init()
|
||||
{
|
||||
Logging.UnityLogger.Init();
|
||||
LogCapturer.Init();
|
||||
// LogCapturer.Init();
|
||||
}
|
||||
public void Clear()
|
||||
{
|
||||
|
@ -352,7 +352,6 @@ namespace Managers
|
||||
// 如果结果为空,则返回 null。
|
||||
if (result.Count == 0)
|
||||
{
|
||||
Debug.LogWarning($"查询失败:未找到定义类型 '{defineType}'");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -50,21 +50,10 @@ namespace Map
|
||||
var rootObj = new GameObject($"_Entities_{id}");
|
||||
rootObj.transform.SetParent(this.transform); // 将其作为Dimension对象的子对象
|
||||
DimensionRoot = rootObj.transform;
|
||||
// 3. 注册此维度到 Program
|
||||
if (Program.Instance != null) // 检查单例是否仍然存在
|
||||
{
|
||||
Program.Instance.RegisterDimension(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError(
|
||||
"[Dimension] Program.Instance is null during Dimension Awake. Cannot register dimension.", this);
|
||||
}
|
||||
|
||||
|
||||
Program.Instance.RegisterDimension(this);
|
||||
// 5. 处理 defaultOpen 逻辑,设置Program的焦点维度
|
||||
// 确保在自身注册到 Program 之后再设置焦点,这样 Program 内部才能找到它
|
||||
if (defaultOpen && Program.Instance != null)
|
||||
if (defaultOpen)
|
||||
{
|
||||
Program.Instance.SetFocusedDimension(_dimensionId);
|
||||
}
|
||||
|
@ -3,14 +3,67 @@ using UnityEngine.UI;
|
||||
|
||||
namespace UI
|
||||
{
|
||||
public class BarUI:MonoBehaviour
|
||||
public class BarUI : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Image image;
|
||||
|
||||
[Header("Progress Gradient")] [SerializeField]
|
||||
private Gradient progressGradient; // 用于定义多色进度渐变
|
||||
|
||||
[Header("Editor Preview")] [SerializeField] [Range(0, 1)]
|
||||
private float _editorProgressPreview = 0f; // 用于在编辑器中预览的进度值
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置进度条的当前进度 (0-1)。
|
||||
/// 设置时会同时更新进度条的填充量和根据渐变更新颜色。
|
||||
/// </summary>
|
||||
public float Progress
|
||||
{
|
||||
get => image.fillAmount;
|
||||
set => image.fillAmount = value;
|
||||
set
|
||||
{
|
||||
// 在运行时检查image是否已赋值
|
||||
if (image == null)
|
||||
{
|
||||
Debug.LogWarning("BarUI: Image reference is not set! Cannot update progress or color.", this);
|
||||
return;
|
||||
}
|
||||
|
||||
// 确保进度值在0到1之间,防止出现异常情况
|
||||
float clampedValue = Mathf.Clamp01(value);
|
||||
image.fillAmount = clampedValue;
|
||||
|
||||
// 使用Gradient的Evaluate方法根据进度值获取对应的渐变颜色
|
||||
// Unity编辑器会自动为Gradient字段初始化一个默认实例,但在某些特殊运行时情况下,
|
||||
// 还是可以加一个null检查以增加健壮性。
|
||||
if (progressGradient != null)
|
||||
{
|
||||
image.color = progressGradient.Evaluate(clampedValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果梯度未定义(极少发生),则使用默认颜色并发出警告
|
||||
Debug.LogWarning("BarUI: Progress Gradient is not set! Using default white color.", this);
|
||||
image.color = Color.white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OnValidate是Unity编辑器特有的方法,当脚本实例在编辑器中被加载或Inspector中的数据被修改时调用
|
||||
private void OnValidate()
|
||||
{
|
||||
// 只有当存在Image引用时才进行更新,避免在编辑器中因未赋值而引发NullReferenceException
|
||||
if (image != null)
|
||||
{
|
||||
// 在编辑器中修改_editorProgressPreview时,同步更新实际的Progress
|
||||
// 这会触发Progress属性的setter,进而更新fillAmount和color
|
||||
Progress = _editorProgressPreview;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 在编辑器中未分配Image时给出提示,防止用户迷惑
|
||||
Debug.LogWarning("BarUI: Image reference is not assigned. Editor preview disabled.", this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,8 @@
|
||||
using System.Linq; // 用于可能的LINQ操作,但在此版本中可能不直接使用
|
||||
using TMPro; // 用于 TextMeshPro 组件
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events; // 用于 UnityEvent
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.Serialization; // 用于 UnityEvent
|
||||
|
||||
namespace UI
|
||||
{
|
||||
@ -11,7 +12,7 @@ namespace UI
|
||||
[Tooltip("当按钮被点击时触发的UnityEvent。可以在Inspector中配置.")]
|
||||
public UnityEvent OnClick;
|
||||
|
||||
public MeshRenderer renderer; // 请确保在Inspector中拖拽赋值
|
||||
[FormerlySerializedAs("renderer")] public MeshRenderer meshRenderer; // 请确保在Inspector中拖拽赋值
|
||||
public Material outlineMaterial; // 请确保在Inspector中拖拽赋值
|
||||
|
||||
public TMP_Text text; // 文本组件
|
||||
@ -20,7 +21,7 @@ namespace UI
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (renderer == null)
|
||||
if (meshRenderer == null)
|
||||
{
|
||||
Debug.LogError("Button3D: MeshRenderer is not assigned. Please assign it in the Inspector.", this);
|
||||
return;
|
||||
@ -42,7 +43,7 @@ namespace UI
|
||||
|
||||
// 存储原始材质数组,以便在添加和移除描边时正确操作
|
||||
// .ToArray() 是为了确保我们拿到的是拷贝,而不是引用,防止外部意外修改
|
||||
_originalMaterials = renderer.materials.ToArray();
|
||||
_originalMaterials = meshRenderer.materials.ToArray();
|
||||
|
||||
// 确保初始化时没有边框材质
|
||||
// Important: 调用RemoveOutlineMaterialInternal()可能会清除_originalMaterials,所以要确保先保存
|
||||
@ -67,7 +68,7 @@ namespace UI
|
||||
|
||||
private void OnMouseEnter()
|
||||
{
|
||||
if (renderer == null) return;
|
||||
if (meshRenderer == null) return;
|
||||
|
||||
// 鼠标进入时显示文本
|
||||
if (text != null)
|
||||
@ -78,30 +79,30 @@ namespace UI
|
||||
// 如果没有描边材质,或者渲染器已经有描边材质,就没必要再添加了
|
||||
// 检查当前材质数组长度是否已经大于等于_originalMaterials的长度+1
|
||||
// 这样可以避免重复添加
|
||||
if (outlineMaterial == null || renderer.materials.Length > _originalMaterials.Length)
|
||||
if (outlineMaterial == null || meshRenderer.materials.Length > _originalMaterials.Length)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果当前材质数组和_originalMaterials不一致,说明可能被其他逻辑修改了,
|
||||
// 稳妥起见,最好先恢复到_originalMaterials
|
||||
if (!renderer.materials.SequenceEqual(_originalMaterials))
|
||||
if (!meshRenderer.materials.SequenceEqual(_originalMaterials))
|
||||
{
|
||||
//Debug.LogWarning("Button3D: Renderer materials were unexpectedly modified before OnMouseEnter. Restoring original materials.");
|
||||
// 通常不应该发生,除非有其他脚本在修改
|
||||
renderer.materials = _originalMaterials;
|
||||
meshRenderer.materials = _originalMaterials;
|
||||
}
|
||||
|
||||
// 创建一个新数组,包含原始材质和描边材质
|
||||
Material[] newMaterials = new Material[_originalMaterials.Length + 1];
|
||||
var newMaterials = new Material[_originalMaterials.Length + 1];
|
||||
System.Array.Copy(_originalMaterials, newMaterials, _originalMaterials.Length);
|
||||
newMaterials[_originalMaterials.Length] = outlineMaterial;
|
||||
renderer.materials = newMaterials;
|
||||
meshRenderer.materials = newMaterials;
|
||||
}
|
||||
|
||||
private void OnMouseExit()
|
||||
{
|
||||
if (renderer == null) return;
|
||||
if (meshRenderer == null) return;
|
||||
|
||||
// 鼠标离开时隐藏文本
|
||||
if (text != null)
|
||||
@ -124,7 +125,7 @@ namespace UI
|
||||
/// </summary>
|
||||
private void RemoveOutlineMaterialInternal()
|
||||
{
|
||||
if (renderer == null) return;
|
||||
if (meshRenderer == null) return;
|
||||
// 即使_originalMaterials == null(因为Awake中的LogError),也可以安全赋值空数组
|
||||
// 但如果_originalMaterials确实是null,说明Awake有问题,后续操作也可能继续出错
|
||||
if (_originalMaterials == null)
|
||||
@ -134,7 +135,7 @@ namespace UI
|
||||
}
|
||||
|
||||
// 直接将渲染器材质恢复为_originalMaterials的副本
|
||||
renderer.materials = _originalMaterials.ToArray(); // 使用ToArray()确保赋值一个副本,避免_originalMaterials被意外修改
|
||||
meshRenderer.materials = _originalMaterials.ToArray(); // 使用ToArray()确保赋值一个副本,避免_originalMaterials被意外修改
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ using UnityEngine.SceneManagement;
|
||||
|
||||
namespace UI
|
||||
{
|
||||
public class DevMenuUI : UIBase
|
||||
public class DevMenuUI : FullScreenUI
|
||||
{
|
||||
public GameObject menuContent;
|
||||
|
||||
|
@ -84,7 +84,7 @@ namespace UI
|
||||
}
|
||||
|
||||
// 尝试将新的实体转换为角色类型。
|
||||
Character newCharacter = entity as Character;
|
||||
var newCharacter = entity as Character;
|
||||
if (newCharacter != null)
|
||||
{
|
||||
focusedEntity = newCharacter;
|
||||
@ -151,11 +151,11 @@ namespace UI
|
||||
return;
|
||||
}
|
||||
|
||||
int requiredUIs = focusedEntity.Inventory.Capacity;
|
||||
int currentUIPoolSize = itemUIPool.Count; // 当前对象池中 ItemUI 实例的总数。
|
||||
var requiredUIs = focusedEntity.Inventory.Capacity;
|
||||
var currentUIPoolSize = itemUIPool.Count; // 当前对象池中 ItemUI 实例的总数。
|
||||
|
||||
// 遍历所有必要的物品槽位,复用对象池中的 ItemUI,或在不足时创建新的 ItemUI。
|
||||
for (int i = 0; i < requiredUIs; i++)
|
||||
for (var i = 0; i < requiredUIs; i++)
|
||||
{
|
||||
ItemUI itemUI;
|
||||
if (i < currentUIPoolSize)
|
||||
@ -178,7 +178,7 @@ namespace UI
|
||||
}
|
||||
|
||||
// 如果库存槽位数量减少,禁用对象池中多余的 ItemUI 实例。
|
||||
for (int i = requiredUIs; i < currentUIPoolSize; i++)
|
||||
for (var i = requiredUIs; i < currentUIPoolSize; i++)
|
||||
{
|
||||
if (itemUIPool[i] != null && itemUIPool[i].gameObject != null)
|
||||
{
|
||||
@ -213,9 +213,9 @@ namespace UI
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < itemUIPool.Count; i++)
|
||||
for (var i = 0; i < itemUIPool.Count; i++)
|
||||
{
|
||||
ItemUI itemUI = itemUIPool[i];
|
||||
var itemUI = itemUIPool[i];
|
||||
if (itemUI != null && itemUI.gameObject != null)
|
||||
{
|
||||
// 只有在 ItemUI 激活状态下才设置其选中状态,避免对禁用UI的操作
|
||||
@ -239,12 +239,12 @@ namespace UI
|
||||
return;
|
||||
}
|
||||
|
||||
float scrollInput = Input.GetAxis("Mouse ScrollWheel");
|
||||
var scrollInput = Input.GetAxis("Mouse ScrollWheel");
|
||||
|
||||
if (scrollInput != 0) // 检测到滚轮输入
|
||||
{
|
||||
int currentSelection = focusedEntity.CurrentSelected;
|
||||
int inventoryCapacity = focusedEntity.Inventory.Capacity;
|
||||
var currentSelection = focusedEntity.CurrentSelected;
|
||||
var inventoryCapacity = focusedEntity.Inventory.Capacity;
|
||||
|
||||
if (scrollInput > 0) // 滚轮向上,选择前一个
|
||||
{
|
||||
|
21
Client/Assets/Scripts/UI/FullScreenUI.cs
Normal file
21
Client/Assets/Scripts/UI/FullScreenUI.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using Base;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UI
|
||||
{
|
||||
public class FullScreenUI:UIBase,ITickUI
|
||||
{
|
||||
public FullScreenUI()
|
||||
{
|
||||
isInputOccupied = true;
|
||||
exclusive=true;
|
||||
}
|
||||
public virtual void TickUI()
|
||||
{
|
||||
if(!IsVisible)
|
||||
return;
|
||||
if(Input.GetKeyDown(KeyCode.Escape))
|
||||
UIInputControl.Instance.Hide(this);
|
||||
}
|
||||
}
|
||||
}
|
2
Client/Assets/Scripts/UI/FullScreenUI.cs.meta
Normal file
2
Client/Assets/Scripts/UI/FullScreenUI.cs.meta
Normal file
@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 92b2dc3c0fc0475596413b883c51e9b2
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Prefab;
|
||||
using TMPro;
|
||||
using Prefab; // 假设 TextPrefab 在 Prefab 命名空间下
|
||||
using TMPro; // 假设 TextPrefab 内部使用了 TextMeshPro
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace UI
|
||||
@ -21,66 +21,80 @@ namespace UI
|
||||
{ LogType.Assert, new Color(0.8f, 0.4f, 1f) }
|
||||
};
|
||||
|
||||
private List<Transform> _logItems = new List<Transform>(); // 已创建的日志条目
|
||||
// 逻辑修改:将_logItems改为存储TextPrefab实例,避免频繁GetComponent
|
||||
private List<TextPrefab> _logItems = new List<TextPrefab>(); // 已创建的日志条目
|
||||
private int _lastLogCount = 0; // 上次显示的日志数量
|
||||
|
||||
|
||||
private void Start()
|
||||
// 逻辑修改:在Update中周期性检查日志数量变化并刷新UI
|
||||
private void Update()
|
||||
{
|
||||
Logging.LogCapturer.Clear();
|
||||
// 获取当前LogCapturer中的日志数量(最旧在前)
|
||||
var currentCapturerLogCount = Logging.LogCapturer.GetLogs(reverseOrder: false).Count;
|
||||
if (_lastLogCount != currentCapturerLogCount)
|
||||
{
|
||||
RefreshLogDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Show()
|
||||
{
|
||||
base.Show();
|
||||
RefreshLogDisplay();
|
||||
RefreshLogDisplay(); // 首次显示时刷新
|
||||
}
|
||||
|
||||
private void RefreshLogDisplay()
|
||||
{
|
||||
var logs = Logging.LogCapturer.GetLogs();
|
||||
// 逻辑修改:获取"最旧在前,最新在后"的日志列表,与UI显示顺序匹配
|
||||
var currentLogsInCapturer = Logging.LogCapturer.GetLogs(reverseOrder: false);
|
||||
var newLogCount = currentLogsInCapturer.Count;
|
||||
var existingUiItemCount = _logItems.Count;
|
||||
|
||||
// 如果日志数量减少,清理多余的条目
|
||||
if (logs.Count < _lastLogCount)
|
||||
// 逻辑修改:处理日志数量减少的情况(日志被从LogCapturer的队列前端移除,即最旧的日志)
|
||||
if (newLogCount < existingUiItemCount)
|
||||
{
|
||||
for (var i = logs.Count; i < _lastLogCount; i++)
|
||||
// 计算需要移除的UI条目数量
|
||||
var itemsToRemove = existingUiItemCount - newLogCount;
|
||||
// 从_logItems的开头移除(销毁最旧的UI元素)
|
||||
for (var i = 0; i < itemsToRemove; i++)
|
||||
{
|
||||
// 确保销毁对应的GameObject,避免内存泄露
|
||||
Destroy(_logItems[i].gameObject);
|
||||
}
|
||||
|
||||
_logItems.RemoveRange(logs.Count, _logItems.Count - logs.Count);
|
||||
_logItems.RemoveRange(0, itemsToRemove); // 从列表中移除引用
|
||||
}
|
||||
|
||||
// 更新现有条目
|
||||
for (var i = 0; i < Math.Min(logs.Count, _logItems.Count); i++)
|
||||
// 逻辑修改:处理日志数量增加的情况(LogCapturer中新增日志)
|
||||
else if (newLogCount > existingUiItemCount)
|
||||
{
|
||||
UpdateLogEntry(_logItems[i], logs[logs.Count - 1 - i]);
|
||||
}
|
||||
|
||||
// 添加新的条目
|
||||
if (logs.Count > _lastLogCount)
|
||||
{
|
||||
for (var i = _lastLogCount; i < logs.Count; i++)
|
||||
// 从现有UI条目数量开始,创建新的UI条目,并添加到_logItems末尾
|
||||
for (var i = existingUiItemCount; i < newLogCount; i++)
|
||||
{
|
||||
CreateLogEntry(logs[logs.Count - 1 - i]);
|
||||
CreateLogEntry(currentLogsInCapturer[i]); // 创建并添加新的UI元素,会自动追加到_logItems
|
||||
}
|
||||
}
|
||||
|
||||
_lastLogCount = logs.Count;
|
||||
// 逻辑修改:更新所有现有/剩余的UI条目内容,确保与LogCapturer中的数据一致
|
||||
// 这一步确保了UI元素能准确反映其对应的日志数据,处理了任何可能的日志内容更新或初始设置。
|
||||
for (var i = 0; i < newLogCount; i++)
|
||||
{
|
||||
UpdateLogEntry(_logItems[i], currentLogsInCapturer[i]);
|
||||
}
|
||||
|
||||
_lastLogCount = newLogCount; // 更新上次显示的日志数量
|
||||
}
|
||||
|
||||
private void CreateLogEntry(Logging.LogCapturer.LogEntry entry)
|
||||
{
|
||||
// 实例化文本预制体
|
||||
// 实例化文本预制体,并将其添加到内容面板
|
||||
var logItem = Instantiate(textPrefab, contentPanel);
|
||||
_logItems.Add(logItem.transform);
|
||||
_logItems.Add(logItem); // 逻辑修改:直接添加TextPrefab实例
|
||||
|
||||
UpdateLogEntry(logItem.transform, entry);
|
||||
UpdateLogEntry(logItem, entry); // 逻辑修改:直接传入TextPrefab实例进行更新
|
||||
}
|
||||
|
||||
private void UpdateLogEntry(Transform logItemTransform, Logging.LogCapturer.LogEntry entry)
|
||||
// 逻辑修改:UpdateLogEntry现在直接接收TextPrefab实例,更高效
|
||||
private void UpdateLogEntry(TextPrefab logItem, Logging.LogCapturer.LogEntry entry)
|
||||
{
|
||||
var logItem = logItemTransform.GetComponent<TextPrefab>();
|
||||
|
||||
// 设置文本内容
|
||||
logItem.Label = entry.ToString();
|
||||
|
||||
@ -96,5 +110,22 @@ namespace UI
|
||||
|
||||
logItem.text.alignment = TextAlignmentOptions.TopLeft;
|
||||
}
|
||||
|
||||
// 逻辑修改:添加OnDestroy方法来清理动态创建的UI元素
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (_logItems != null)
|
||||
{
|
||||
foreach (var item in _logItems)
|
||||
{
|
||||
// 检查item及其gameObject是否仍有效,以防在其他地方已经被销毁或为空
|
||||
if (item != null && item.gameObject != null)
|
||||
{
|
||||
Destroy(item.gameObject);
|
||||
}
|
||||
}
|
||||
_logItems.Clear(); // 清空列表引用
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ namespace UI
|
||||
{
|
||||
windowResolution.value = 0;
|
||||
}
|
||||
windowMode.value = (int)currentSettings.currentWindowMode;
|
||||
}
|
||||
public void CancelSettings()
|
||||
{
|
||||
|
Reference in New Issue
Block a user