在游戏中安排基于时间的事件的最佳集合是什么?我想按时间对元素进行排序并仅检查第一个
while (collection[0].TimeToTrigger <= time)
{
collection[0].Trigger();
collection.RemoveAt(0);
}
基本集合有什么问题:
List
- 在删除/插入时移动元素Queue
- 没有插入非常有趣且深刻的问题。不明白为什么它不喜欢。可能是因为细节不够。例如,您要在这个收藏中保留什么样的物品。使用哪个集合的决定应该基于您对如何使用它的估计(您也没有提到)和集合的操作O(n)复杂度。
但是,我敢说,我遇到了您的问题,并且您希望创建一个用于管理跨时间回调的系统。我不知道您为此目的创建了哪个类,但我会使用像
SortedDictionary<long, List<Action>>
这样的集合。其中 long 是时间戳(可以是浮点数或任何其他值),以及分配给该时间的回调列表。排序字典的元素添加和检索复杂度为 O(log(n)),获取第一个元素的复杂度为 O(1)。此外,第一个元素始终具有最低的时间戳。
到目前为止,您可以使用如下方法添加回调:
private readonly SortedDictionary<long, List<Action>> _callbacks = new();
public void AddCallback(long timestamp, Action callback)
{
if (callback == null)
return;
Debug.Log($"Delayed callback submitted: {callback.Method.Name} with time = {new DateTime(timestamp)}");
if (timestamp < _currentTime) // case handling for passed callback submission could be helpful, but not necessary.
{
Debug.Log($"Invoke delayed callback: {callback.Method.Name}");
callback.Invoke();
return;
}
if (!_callbacks.ContainsKey(timestamp))
{
_callbacks.Add(timestamp, new List<Action>());
}
_callbacks[timestamp].Add(callback);
}
回调执行可以放在 Update 方法中,如下所示:
private void Update()
{
_currentTime = // get current time the way you like.
if (_callbacks.Any())
{
KeyValuePair<long, List<Action>> kvp;
while (_callbacks.Any() && (kvp = _callbacks.First()).Key < currentTimeStamp)
{
// copy events before execution cause it could be modified while execution
var callbacksCollection = new Action[kvp.Value.Count];
kvp.Value.CopyTo(callbacksCollection);
foreach (var callback in callbacksCollection)
{
Debug.Log($"Invoke delayed callback: {callback.Method.Name}");
callback.Invoke();
}
_callbacks.Remove(kvp.Key);
}
}
}
因此,我也认为
SortedList
适合这个问题。它的操作时间复杂度较差,但占用的内存较少。
另外,您可以使用此代码进行一系列优化,例如集合重新创建,如果它变得太大(不要忘记 C# 中的所有集合在内存中不会变小,即使您删除所有元素)或有某种类型大型回调序列的池等。但是,我想再说一遍,像这样的问题没有单一的答案。而且,你描述的问题很糟糕。
PS。您可以查看这篇文章来简要回顾排序后的集合。