功能:使不同类可以按不同优先级、不同频率,统一的Update。
特点:可以管理不同类的Update顺序与频率。调整顺序可以保证逻辑的一致性,调整频率可以减少不必要的性能消耗,统一调用可以减少Unity底层调用Update()的开销。
使用方法:将Ib_UpdateManager挂载到场景的物体上。类继承接口IUpdate后,实现ManagedUpdate(float deltaTime);方法,并通过Ib_Event事件系统在初始化的时候注册到Ib_UpdateManager,并在销毁时注销即可。重复注册可以更改优先级和频率。
使用示例:
using Cysharp.Threading.Tasks;
using Ib_Core;
using UnityEngine;
public class Sample_Ib_Update_Test1 : MonoBehaviour,IUpdate
{
void Start()
{
//调用IUpdate的拓展方法注册到Ib_UpdateManager,更新优先级为Normal,间隔为0,即每帧更新
this.RegisterOrUpdateManagedUpdate(Ib_UpdatePriority.Normal,0,this.GetCancellationTokenOnDestroy());
}
void OnDestroy()
{
//调用IUpdate的拓展方法从Ib_UpdateManager中注销,避免内存泄漏
this.DeregisterManagedUpdate();
}
/// <summary>
/// 实现IUpdate接口的ManagedUpdate方法,可以接收时间差
/// </summary>
/// <param name="deltaTime">时间差</param>
public void ManagedUpdate(float deltaTime)
{
Ib_Log.Info($"[{System.DateTime.Now}]>> {GetType().Name} >> ManagedUpdate >> deltaTime:{deltaTime}");
}
}
public class Sample_Ib_Update_Test2 : MonoBehaviour,IUpdate
{
void Start()
{
//优先级为Early,在Normal之前更新,间隔为0,即每帧更新
this.RegisterOrUpdateManagedUpdate(Ib_UpdatePriority.Early,0,this.GetCancellationTokenOnDestroy());
}
......
}
public class Sample_Ib_Update_Test3 : MonoBehaviour,IUpdate
{
void Start()
{
//优先级为Normal,间隔为0.5秒,即每0.5秒更新一次
this.RegisterOrUpdateManagedUpdate(Ib_UpdatePriority.Normal,0.5f,this.GetCancellationTokenOnDestroy());
}
......
}
下图可以看到每帧调用下来优先级为Early(值为-1)的Test2总是在优先级为Normal(值为0)的Test1前更新,更新间隔为0.5s、优先级为Normal的Test3仍保持着正确的顺序更新。

源码:
Ib_UpdateManager继承了泛型单例,这不是必须的,所有的注册和注销都是通过Ib_Event事件中心进行的。只需要保证场景上只有一个Ib_UdpateManager在运行即可。若没有Ib_Event可以直接使用单例注册,修改Ib_UpdateExtensions中的注册方法即可。
using System.Collections.Generic;
using Ib_Core;
using Ib_Core.Ib_Controller;
using UnityEngine;
public class Ib_UpdateBox
{
public IUpdate updateTarget;
public int updatePriority;
public float updateInterval;
public float updateTimer;
public int listIndex;
public Ib_UpdateBox(IUpdate update,int priority, float interval)
{
updateTarget = update;
updatePriority = priority;
updateInterval = interval;
updateTimer = 0;
listIndex = -1;
}
}
/// <summary>
/// 同一Update管理器。支持优先级和不同更新频率。
/// 通过OnRegisterOrUpdateManagedUpdate方法注册,OnDeregisterManagedUpdate撤销
/// </summary>
public class Ib_UpdateManager : Ib_Singleton<Ib_UpdateManager>
{
/// <summary>
/// 最大回溯帧数,用于防止更新频率过低导致的卡顿
/// </summary>
private const int MaxBacklogFrame = 5;
/// <summary>
/// 检查GO物体是否已被销毁
/// </summary>
private const bool CheckFakeNull = false;
#region 订阅部分
private readonly Dictionary<int, List<Ib_UpdateBox>> _priorityUpdates = new Dictionary<int, List<Ib_UpdateBox>>();
private readonly List<Ib_UpdateBox> _pendingAdditions = new List<Ib_UpdateBox>();
private readonly HashSet<IUpdate> _pendingAdditionsSet = new HashSet<IUpdate>();
private readonly List<IUpdate> _pendingRemovals = new List<IUpdate>();
private readonly List<Ib_UpdateBox> _pendingChanges = new List<Ib_UpdateBox>();
private readonly Dictionary<IUpdate, Ib_UpdateBox> _registeredDic = new Dictionary<IUpdate, Ib_UpdateBox>();
private List<int> _sortedPriorityKeys = new List<int>();
private bool _isPriorityKeysDirty = false;
protected override void Awake()
{
base.Awake();
//订阅注册事件
OnRegisterOrUpdateManagedUpdate.Register(RegisterManagedUpdate);
OnDeregisterManagedUpdate.Register(DeregisterManagedUpdate);
}
protected override void OnDestroy()
{
base.OnDestroy();
//取消订阅事件
OnRegisterOrUpdateManagedUpdate.Deregister(RegisterManagedUpdate);
OnDeregisterManagedUpdate.Deregister(DeregisterManagedUpdate);
}
private void RegisterManagedUpdate(IUpdate managedUpdate,Ib_UpdatePriority updatePriority,float updateInterval)
{
if (managedUpdate == null) return;
//保证更新频率是非负数
updateInterval = Mathf.Max(0, updateInterval);
//完全新增,加入待更新列表
if (!_registeredDic.ContainsKey(managedUpdate))
{
//防止重复添加
if (_pendingAdditionsSet.Contains(managedUpdate)) return;
var box = new Ib_UpdateBox(managedUpdate, (int)updatePriority, updateInterval);
_pendingAdditions.Add(box);
_pendingAdditionsSet.Add(box.updateTarget);
}
else
{
var existingBox = _registeredDic[managedUpdate];
// 仅更新频率
if (existingBox.updatePriority == (int)updatePriority)
{
existingBox.updateInterval = updateInterval;
}
// 更新优先级,加入待更新列表
else
{
// 创建一个临时的Box作为数据载体传给 ProcessPendingLists
var changeBox = new Ib_UpdateBox(managedUpdate, (int)updatePriority, updateInterval);
_pendingChanges.Add(changeBox);
}
}
}
private void DeregisterManagedUpdate(IUpdate managedUpdate)
{
//如果已经在运行列表中,加入待移除队列
if (_registeredDic.ContainsKey(managedUpdate))
{
_pendingRemovals.Add(managedUpdate);
}
//如果还在待添加列表中(同帧注册),直接从待添加列表移除
else
{
if (!_pendingAdditionsSet.Contains(managedUpdate)) return;
int pendingIndex = _pendingAdditions.FindIndex(x => x.updateTarget == managedUpdate);
if (pendingIndex != -1)
{
_pendingAdditions.RemoveAt(pendingIndex);
}
_pendingAdditionsSet.Remove(managedUpdate);
}
}
#endregion
#region 执行部分
private Ib_UpdateBox _updateBox;
private void Update()
{
ProcessPendingLists();
if (_isPriorityKeysDirty)
{
//当有新的优先级时,进行排序
SortPriorityKeys();
}
// 按照优先级顺序遍历
foreach (int priority in _sortedPriorityKeys)
{
var updateList = _priorityUpdates[priority];
int updateCnt = updateList.Count;
float deltaTime = Time.deltaTime;
for (int i = 0; i < updateCnt; i++)
{
_updateBox = updateList[i];
if (CheckFakeNull && _updateBox.updateTarget is UnityEngine.Object uObj && uObj == null)
{
DeregisterManagedUpdate(_updateBox.updateTarget);
continue;
}
if (_updateBox.updateInterval == 0)
{
try
{
_updateBox.updateTarget.ManagedUpdate(deltaTime);
}
catch (System.Exception ex)
{
Ib_Log.Error($"Update failed for {_updateBox.updateTarget.GetType().Name}");
Ib_Log.Error(ex);
}
_updateBox.updateTimer = 0;
continue;
}
_updateBox.updateTimer += deltaTime;
//允许的最大积压更新次数,当卡顿时会一次性更新
if (_updateBox.updateTimer > _updateBox.updateInterval * MaxBacklogFrame)
{
_updateBox.updateTimer = _updateBox.updateInterval * MaxBacklogFrame;
}
while (_updateBox.updateTimer >= _updateBox.updateInterval)
{
try
{
_updateBox.updateTarget.ManagedUpdate(_updateBox.updateInterval);
}
catch (System.Exception ex)
{
// 异常处理逻辑只在这里,当异常真的发生时才执行
Ib_Log.Error($"Update failed for {_updateBox.updateTarget.GetType().Name}");
Ib_Log.Error(ex);
}
_updateBox.updateTimer -= _updateBox.updateInterval;
}
}
}
}
private void ProcessPendingLists()
{
if (_pendingRemovals.Count > 0)
{
foreach (var toRemove in _pendingRemovals)
{
if (_registeredDic.TryGetValue(toRemove, out var boxToRemove))
{
RemoveBoxFromList(boxToRemove);
_registeredDic.Remove(toRemove);
}
}
_pendingRemovals.Clear();
}
if (_pendingAdditions.Count > 0)
{
foreach (var toAdd in _pendingAdditions)
{
if (!_registeredDic.ContainsKey(toAdd.updateTarget))
{
AddBoxToList(toAdd);
_registeredDic.Add(toAdd.updateTarget, toAdd);
}
}
_pendingAdditions.Clear();
_pendingAdditionsSet.Clear();
}
if (_pendingChanges.Count > 0)
{
foreach (var change in _pendingChanges)
{
if (_registeredDic.TryGetValue(change.updateTarget, out var oldBox))
{
RemoveBoxFromList(oldBox);
change.listIndex = -1;
change.updateTimer = oldBox.updateTimer; // 继承之前的计时器状态
AddBoxToList(change);
_registeredDic[change.updateTarget] = change;
}
}
_pendingChanges.Clear();
}
}
private void RemoveBoxFromList(Ib_UpdateBox box)
{
if (_priorityUpdates.TryGetValue(box.updatePriority, out var list))
{
int indexToRemove = box.listIndex;
int lastIndex = list.Count - 1;
// 越界保护
if (indexToRemove < 0 || indexToRemove > lastIndex) return;
if (indexToRemove < lastIndex)
{
var lastBox = list[lastIndex];
list[indexToRemove] = lastBox;
lastBox.listIndex = indexToRemove;
}
list.RemoveAt(lastIndex);
}
}
private void AddBoxToList(Ib_UpdateBox box)
{
if (!_priorityUpdates.TryGetValue(box.updatePriority, out var list))
{
list = new List<Ib_UpdateBox>();
_priorityUpdates[box.updatePriority] = list;
_isPriorityKeysDirty = true;
}
list.Add(box);
box.listIndex = list.Count - 1;
}
private void SortPriorityKeys()
{
_sortedPriorityKeys.Clear();
_sortedPriorityKeys.AddRange(_priorityUpdates.Keys);
_sortedPriorityKeys.Sort();
_isPriorityKeysDirty = false;
}
#endregion
}
namespace Ib_Core
{
using System.Threading;
/// <summary>
/// ManagedUpdate的优先级
/// </summary>
public enum Ib_UpdatePriority
{
First = -2,
Early = -1,
Normal = 0,
Late = 1,
Last = 2,
}
public class OnRegisterOrUpdateManagedUpdate : Ib_Event<OnRegisterOrUpdateManagedUpdate, IUpdate,Ib_UpdatePriority,float> { };
public class OnDeregisterManagedUpdate : Ib_Event<OnDeregisterManagedUpdate,IUpdate> { };
public interface IUpdate
{
public void ManagedUpdate(float deltaTime);
}
}
namespace Ib_Core
{
using System.Threading;
/// <summary>
/// Ib_Update的拓展方法,简化了注册
/// </summary>
public static class Ib_UpdateExtensions
{
/// <summary>
/// 注册或更新ManagedUpdate
/// </summary>
/// <param name="self"></param>
/// <param name="priority">更新的优先级,越小越早执行</param>
/// <param name="interval">每次更新的间隔</param>
/// <param name="cts">异步取消令牌</param>
public static void RegisterOrUpdateManagedUpdate(this IUpdate self, Ib_UpdatePriority priority, float interval, CancellationToken cts)
{
//通过Ib_Event事件来注册到Ib_UpdateManager
OnRegisterOrUpdateManagedUpdate.InvokeNextFrame(self,priority,interval,cts);
}
public static void DeregisterManagedUpdate(this IUpdate self)
{
//通过Ib_Event事件来撤销注册到Ib_UpdateManager
OnDeregisterManagedUpdate.InvokeNextFrame(self,CancellationToken.None);
}
}
}
评论(0)
暂无评论