我应该使用哪个集合来处理 C# 中基于时间的游戏事件

问题描述 投票:0回答:1

在游戏中安排基于时间的事件的最佳集合是什么?我想按时间对元素进行排序并仅检查第一个

while (collection[0].TimeToTrigger <= time)
{
    collection[0].Trigger();
    collection.RemoveAt(0);
}

基本集合有什么问题:

  • List
    - 在删除/插入时移动元素
  • Queue
    - 没有插入
c# unity-game-engine collections
1个回答
0
投票

非常有趣且深刻的问题。不明白为什么它不喜欢。可能是因为细节不够。例如,您要在这个收藏中保留什么样的物品。使用哪个集合的决定应该基于您对如何使用它的估计(您也没有提到)和集合的操作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。您可以查看这篇文章来简要回顾排序后的集合。

© www.soinside.com 2019 - 2024. All rights reserved.