mirror of
http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite.git
synced 2025-11-20 05:37:11 +08:00
(client) feat:健康给予,路径优化,结算界面,商店界面 (#60)
Co-authored-by: m0_75251201 <m0_75251201@noreply.gitcode.com> Reviewed-on: http://47.107.252.169:3000/Roguelite-Game-Developing-Team/Gen_Hack-and-Slash-Roguelite/pulls/60
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Utils; // 假设此命名空间包含MonoSingleton
|
||||
using Utils;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
// 假设此命名空间包含MonoSingleton
|
||||
|
||||
namespace Base
|
||||
{
|
||||
/// <summary>
|
||||
/// 定义一个Tick更新接口,用于在常规Update中执行逻辑。
|
||||
/// 定义一个Tick更新接口,用于在常规Update中执行逻辑。
|
||||
/// </summary>
|
||||
public interface ITick
|
||||
{
|
||||
@@ -14,7 +18,7 @@ namespace Base
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 定义一个TickPhysics更新接口,用于在FixedUpdate中执行物理逻辑。
|
||||
/// 定义一个TickPhysics更新接口,用于在FixedUpdate中执行物理逻辑。
|
||||
/// </summary>
|
||||
public interface ITickPhysics
|
||||
{
|
||||
@@ -22,7 +26,7 @@ namespace Base
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 定义一个TickUI更新接口,用于在常规Update中执行UI逻辑。
|
||||
/// 定义一个TickUI更新接口,用于在常规Update中执行UI逻辑。
|
||||
/// </summary>
|
||||
public interface ITickUI
|
||||
{
|
||||
@@ -30,17 +34,44 @@ namespace Base
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 全局计时器和更新管理器,负责在Unity的Update、FixedUpdate和LateUpdate生命周期中调度注册的Ticks。
|
||||
/// 支持游戏暂停、场景加载时自动重置以及缓冲区的添加/移除操作以避免迭代器错误。
|
||||
/// 全局计时器和更新管理器,负责在Unity的Update、FixedUpdate和LateUpdate生命周期中调度注册的Ticks。
|
||||
/// 支持游戏暂停、场景加载时自动重置以及缓冲区的添加/移除操作以避免迭代器错误。
|
||||
/// </summary>
|
||||
public class Clock : MonoSingleton<Clock>
|
||||
{
|
||||
// 存储所有需要在FixedUpdate中执行物理Tick逻辑的对象
|
||||
private readonly HashSet<ITickPhysics> _tickPhysics = new();
|
||||
|
||||
// 待添加的ITickPhysics对象缓冲区
|
||||
private readonly HashSet<ITickPhysics> _tickPhysicsToAdd = new();
|
||||
|
||||
// 待移除的ITickPhysics对象缓冲区
|
||||
private readonly HashSet<ITickPhysics> _tickPhysicsToRemove = new();
|
||||
|
||||
// 存储所有需要在常规Update中执行Tick逻辑的对象
|
||||
private readonly HashSet<ITick> _ticks = new();
|
||||
|
||||
// 待添加的ITick对象缓冲区
|
||||
private readonly HashSet<ITick> _ticksToAdd = new();
|
||||
|
||||
// 待移除的ITick对象缓冲区
|
||||
private readonly HashSet<ITick> _ticksToRemove = new();
|
||||
|
||||
// 存储所有需要在常规Update中执行UI Tick逻辑的对象
|
||||
private readonly HashSet<ITickUI> _tickUIs = new();
|
||||
|
||||
// 待添加的ITickUI对象缓冲区
|
||||
private readonly HashSet<ITickUI> _tickUIsToAdd = new();
|
||||
|
||||
// 待移除的ITickUI对象缓冲区
|
||||
private readonly HashSet<ITickUI> _tickUIsToRemove = new();
|
||||
|
||||
// 游戏是否暂停
|
||||
private bool _pause;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置游戏的暂停状态。当设置为true时,Time.timeScale将变为0;当设置为false时,Time.timeScale将恢复为1。
|
||||
/// 该操作会检查当前状态,避免重复设置Time.timeScale。
|
||||
/// 获取或设置游戏的暂停状态。当设置为true时,Time.timeScale将变为0;当设置为false时,Time.timeScale将恢复为1。
|
||||
/// 该操作会检查当前状态,避免重复设置Time.timeScale。
|
||||
/// </summary>
|
||||
public bool Pause
|
||||
{
|
||||
@@ -56,38 +87,61 @@ namespace Base
|
||||
}
|
||||
}
|
||||
|
||||
// 存储所有需要在常规Update中执行Tick逻辑的对象
|
||||
private readonly HashSet<ITick> _ticks = new();
|
||||
// 存储所有需要在FixedUpdate中执行物理Tick逻辑的对象
|
||||
private readonly HashSet<ITickPhysics> _tickPhysics = new();
|
||||
// 存储所有需要在常规Update中执行UI Tick逻辑的对象
|
||||
private readonly HashSet<ITickUI> _tickUIs = new();
|
||||
|
||||
// 待添加的ITick对象缓冲区
|
||||
private readonly HashSet<ITick> _ticksToAdd = new();
|
||||
// 待添加的ITickPhysics对象缓冲区
|
||||
private readonly HashSet<ITickPhysics> _tickPhysicsToAdd = new();
|
||||
// 待添加的ITickUI对象缓冲区
|
||||
private readonly HashSet<ITickUI> _tickUIsToAdd = new();
|
||||
|
||||
// 待移除的ITick对象缓冲区
|
||||
private readonly HashSet<ITick> _ticksToRemove = new();
|
||||
// 待移除的ITickPhysics对象缓冲区
|
||||
private readonly HashSet<ITickPhysics> _tickPhysicsToRemove = new();
|
||||
// 待移除的ITickUI对象缓冲区
|
||||
private readonly HashSet<ITickUI> _tickUIsToRemove = new();
|
||||
|
||||
/// <summary>
|
||||
/// 在单例首次创建时调用。
|
||||
/// 每帧更新方法。
|
||||
/// 如果游戏未暂停,则执行所有注册的ITick对象的Tick方法;
|
||||
/// 执行所有注册的ITickUI对象的TickUI方法(UI通常不受暂停影响)。
|
||||
/// </summary>
|
||||
protected override void OnStart()
|
||||
private void Update()
|
||||
{
|
||||
SceneManager.sceneLoaded += OnSceneLoadedCallback;
|
||||
ApplyBufferedChanges();
|
||||
// 如果游戏未暂停,则执行常规的Tick更新。
|
||||
if (!_pause)
|
||||
foreach (var tick in _ticks)
|
||||
try
|
||||
{
|
||||
tick.Tick();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"[Clock] ITick对象 '{tick.GetType().Name}' 在Tick()执行期间抛出异常: {e}");
|
||||
}
|
||||
|
||||
// UI更新通常不受游戏暂停影响(例如菜单动画、UI计时器等)。
|
||||
foreach (var uiTick in _tickUIs)
|
||||
try
|
||||
{
|
||||
uiTick.TickUI();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"[Clock] ITickUI对象 '{uiTick.GetType().Name}' 在TickUI()执行期间抛出异常: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 在Clock组件被销毁时调用。
|
||||
/// 取消订阅场景加载事件并清理所有内部Tick列表。
|
||||
/// 每固定帧更新方法。
|
||||
/// 如果游戏未暂停,则执行所有注册的ITickPhysics对象的TickPhysics方法。
|
||||
/// </summary>
|
||||
private void FixedUpdate()
|
||||
{
|
||||
// 如果游戏未暂停,则执行物理Tick更新。
|
||||
if (!_pause)
|
||||
foreach (var physicsTick in _tickPhysics)
|
||||
try
|
||||
{
|
||||
physicsTick.TickPhysics();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError(
|
||||
$"[Clock] ITickPhysics对象 '{physicsTick.GetType().Name}' 在TickPhysics()执行期间抛出异常: {e}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在Clock组件被销毁时调用。
|
||||
/// 取消订阅场景加载事件并清理所有内部Tick列表。
|
||||
/// </summary>
|
||||
protected void OnDestroy()
|
||||
{
|
||||
@@ -96,8 +150,16 @@ namespace Base
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 场景加载完成时的回调方法。
|
||||
/// 用于在加载新场景后清理所有Tick列表并重置游戏暂停状态。
|
||||
/// 在单例首次创建时调用。
|
||||
/// </summary>
|
||||
protected override void OnStart()
|
||||
{
|
||||
SceneManager.sceneLoaded += OnSceneLoadedCallback;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 场景加载完成时的回调方法。
|
||||
/// 用于在加载新场景后清理所有Tick列表并重置游戏暂停状态。
|
||||
/// </summary>
|
||||
/// <param name="scene">被加载的场景。</param>
|
||||
/// <param name="mode">场景加载模式。</param>
|
||||
@@ -107,75 +169,8 @@ namespace Base
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每帧更新方法。
|
||||
/// 如果游戏未暂停,则执行所有注册的ITick对象的Tick方法;
|
||||
/// 执行所有注册的ITickUI对象的TickUI方法(UI通常不受暂停影响)。
|
||||
/// </summary>
|
||||
private void Update()
|
||||
{
|
||||
// 如果游戏未暂停,则执行常规的Tick更新。
|
||||
if (!_pause)
|
||||
{
|
||||
foreach (var tick in _ticks)
|
||||
{
|
||||
try
|
||||
{
|
||||
tick.Tick();
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"[Clock] ITick对象 '{tick.GetType().Name}' 在Tick()执行期间抛出异常: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
// UI更新通常不受游戏暂停影响(例如菜单动画、UI计时器等)。
|
||||
foreach (var uiTick in _tickUIs)
|
||||
{
|
||||
try
|
||||
{
|
||||
uiTick.TickUI();
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"[Clock] ITickUI对象 '{uiTick.GetType().Name}' 在TickUI()执行期间抛出异常: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 每固定帧更新方法。
|
||||
/// 如果游戏未暂停,则执行所有注册的ITickPhysics对象的TickPhysics方法。
|
||||
/// </summary>
|
||||
private void FixedUpdate()
|
||||
{
|
||||
// 如果游戏未暂停,则执行物理Tick更新。
|
||||
if (!_pause)
|
||||
{
|
||||
foreach (var physicsTick in _tickPhysics)
|
||||
{
|
||||
try
|
||||
{
|
||||
physicsTick.TickPhysics();
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Debug.LogError($"[Clock] ITickPhysics对象 '{physicsTick.GetType().Name}' 在TickPhysics()执行期间抛出异常: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在所有Update操作完成后,应用Tick注册和注销的缓冲区更改,确保列表在迭代期间不被修改。
|
||||
/// </summary>
|
||||
private void LateUpdate()
|
||||
{
|
||||
ApplyBufferedChanges();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将一个ITick对象添加到待添加缓冲区。它将在下一个LateUpdate中被添加到主Tick列表。
|
||||
/// 如果对象已经在待移除列表中,则会先从待移除列表中移除,以处理添加/移除冲突。
|
||||
/// 将一个ITick对象添加到待添加缓冲区。它将在下一个LateUpdate中被添加到主Tick列表。
|
||||
/// 如果对象已经在待移除列表中,则会先从待移除列表中移除,以处理添加/移除冲突。
|
||||
/// </summary>
|
||||
/// <param name="tick">要添加的ITick对象。</param>
|
||||
public static void AddTick(ITick tick)
|
||||
@@ -188,8 +183,8 @@ namespace Base
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将一个ITick对象添加到待移除缓冲区。它将在下一个LateUpdate中从主Tick列表移除。
|
||||
/// 如果对象已经在待添加列表中,则会先从待添加列表中移除,以处理添加/移除冲突。
|
||||
/// 将一个ITick对象添加到待移除缓冲区。它将在下一个LateUpdate中从主Tick列表移除。
|
||||
/// 如果对象已经在待添加列表中,则会先从待添加列表中移除,以处理添加/移除冲突。
|
||||
/// </summary>
|
||||
/// <param name="tick">要移除的ITick对象。</param>
|
||||
public static void RemoveTick(ITick tick)
|
||||
@@ -202,8 +197,8 @@ namespace Base
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将一个ITickPhysics对象添加到待添加缓冲区。它将在下一个LateUpdate中被添加到主物理Tick列表。
|
||||
/// 如果对象已经在待移除列表中,则会先从待移除列表中移除,以处理添加/移除冲突。
|
||||
/// 将一个ITickPhysics对象添加到待添加缓冲区。它将在下一个LateUpdate中被添加到主物理Tick列表。
|
||||
/// 如果对象已经在待移除列表中,则会先从待移除列表中移除,以处理添加/移除冲突。
|
||||
/// </summary>
|
||||
/// <param name="physics">要添加的ITickPhysics对象。</param>
|
||||
public static void AddTickPhysics(ITickPhysics physics)
|
||||
@@ -216,8 +211,8 @@ namespace Base
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将一个ITickPhysics对象添加到待移除缓冲区。它将在下一个LateUpdate中从主物理Tick列表移除。
|
||||
/// 如果对象已经在待添加列表中,则会先从待添加列表中移除,以处理添加/移除冲突。
|
||||
/// 将一个ITickPhysics对象添加到待移除缓冲区。它将在下一个LateUpdate中从主物理Tick列表移除。
|
||||
/// 如果对象已经在待添加列表中,则会先从待添加列表中移除,以处理添加/移除冲突。
|
||||
/// </summary>
|
||||
/// <param name="physics">要移除的ITickPhysics对象。</param>
|
||||
public static void RemoveTickPhysics(ITickPhysics physics)
|
||||
@@ -230,8 +225,8 @@ namespace Base
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将一个ITickUI对象添加到待添加缓冲区。它将在下一个LateUpdate中被添加到主UI Tick列表。
|
||||
/// 如果对象已经在待移除列表中,则会先从待移除列表中移除,以处理添加/移除冲突。
|
||||
/// 将一个ITickUI对象添加到待添加缓冲区。它将在下一个LateUpdate中被添加到主UI Tick列表。
|
||||
/// 如果对象已经在待移除列表中,则会先从待移除列表中移除,以处理添加/移除冲突。
|
||||
/// </summary>
|
||||
/// <param name="ui">要添加的ITickUI对象。</param>
|
||||
public static void AddTickUI(ITickUI ui)
|
||||
@@ -244,8 +239,8 @@ namespace Base
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将一个ITickUI对象添加到待移除缓冲区。它将在下一个LateUpdate中从主UI Tick列表移除。
|
||||
/// 如果对象已经在待添加列表中,则会先从待添加列表中移除,以处理添加/移除冲突。
|
||||
/// 将一个ITickUI对象添加到待移除缓冲区。它将在下一个LateUpdate中从主UI Tick列表移除。
|
||||
/// 如果对象已经在待添加列表中,则会先从待添加列表中移除,以处理添加/移除冲突。
|
||||
/// </summary>
|
||||
/// <param name="ui">要移除的ITickUI对象。</param>
|
||||
public static void RemoveTickUI(ITickUI ui)
|
||||
@@ -258,35 +253,26 @@ namespace Base
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将缓冲区中的添加和移除操作应用到主Tick列表中。
|
||||
/// 此方法应在LateUpdate中调用,以确保在所有Tick执行完毕后进行列表修改,从而避免迭代器错误。
|
||||
/// 将缓冲区中的添加和移除操作应用到主Tick列表中。
|
||||
/// 此方法应在LateUpdate中调用,以确保在所有Tick执行完毕后进行列表修改,从而避免迭代器错误。
|
||||
/// </summary>
|
||||
private void ApplyBufferedChanges()
|
||||
{
|
||||
if (_ticksToRemove.Count > 0)
|
||||
{
|
||||
foreach (var tick in _ticksToRemove)
|
||||
{
|
||||
_ticks.Remove(tick);
|
||||
}
|
||||
foreach (var tick in _ticksToRemove) _ticks.Remove(tick);
|
||||
_ticksToRemove.Clear();
|
||||
}
|
||||
|
||||
if (_tickPhysicsToRemove.Count > 0)
|
||||
{
|
||||
foreach (var physicsTick in _tickPhysicsToRemove)
|
||||
{
|
||||
_tickPhysics.Remove(physicsTick);
|
||||
}
|
||||
foreach (var physicsTick in _tickPhysicsToRemove) _tickPhysics.Remove(physicsTick);
|
||||
_tickPhysicsToRemove.Clear();
|
||||
}
|
||||
|
||||
if (_tickUIsToRemove.Count > 0)
|
||||
{
|
||||
foreach (var uiTick in _tickUIsToRemove)
|
||||
{
|
||||
_tickUIs.Remove(uiTick);
|
||||
}
|
||||
foreach (var uiTick in _tickUIsToRemove) _tickUIs.Remove(uiTick);
|
||||
_tickUIsToRemove.Clear();
|
||||
}
|
||||
|
||||
@@ -294,16 +280,10 @@ namespace Base
|
||||
{
|
||||
foreach (var tick in _ticksToAdd)
|
||||
{
|
||||
// 逻辑修改:
|
||||
// 防止将已销毁的Unity对象添加到主Tick列表中。
|
||||
// Unity的UnityEngine.Object重载了"=="运算符,因此对于已销毁的对象,
|
||||
// (unityObject == null) 会返回 true。
|
||||
if (tick is Object unityObject && unityObject == null)
|
||||
{
|
||||
continue; // 跳过已销毁的Unity对象
|
||||
}
|
||||
if (tick is Object unityObject && !unityObject) continue; // 跳过已销毁的Unity对象
|
||||
_ticks.Add(tick);
|
||||
}
|
||||
|
||||
_ticksToAdd.Clear();
|
||||
}
|
||||
|
||||
@@ -311,12 +291,10 @@ namespace Base
|
||||
{
|
||||
foreach (var physicsTick in _tickPhysicsToAdd)
|
||||
{
|
||||
if (physicsTick is Object unityObject && unityObject == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (physicsTick is Object unityObject && !unityObject) continue;
|
||||
_tickPhysics.Add(physicsTick);
|
||||
}
|
||||
|
||||
_tickPhysicsToAdd.Clear();
|
||||
}
|
||||
|
||||
@@ -324,19 +302,17 @@ namespace Base
|
||||
{
|
||||
foreach (var uiTick in _tickUIsToAdd)
|
||||
{
|
||||
if (uiTick is Object unityObject && unityObject == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (uiTick is Object unityObject && unityObject == null) continue;
|
||||
_tickUIs.Add(uiTick);
|
||||
}
|
||||
|
||||
_tickUIsToAdd.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 集中处理所有Tick列表和缓冲区的清理。
|
||||
/// 此方法会在场景加载、Clock被禁用或销毁时调用。
|
||||
/// 集中处理所有Tick列表和缓冲区的清理。
|
||||
/// 此方法会在场景加载、Clock被禁用或销毁时调用。
|
||||
/// </summary>
|
||||
/// <param name="clearPauseState">指示是否同时重置Pause状态和Time.timeScale。</param>
|
||||
private void ClearAllTicksInternal(bool clearPauseState)
|
||||
@@ -358,11 +334,7 @@ namespace Base
|
||||
_tickPhysicsToRemove.Clear();
|
||||
_tickUIsToRemove.Clear();
|
||||
|
||||
if (clearPauseState)
|
||||
{
|
||||
Pause = false;
|
||||
}
|
||||
if (clearPauseState) Pause = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user