【问题标题】:Optimizing GameObject unique ID assigner Unity优化 GameObject 唯一 ID 分配器 Unity
【发布时间】:2021-07-23 22:24:59
【问题描述】:

最近我正在为多人游戏开发门系统,但我遇到了门 ID(指定要与哪个门交互)的问题。我想避免手动分配 ID,因为我的游戏有很多门,所以我找到了一个解决方案 - 而不是不可靠的 FindObjectsOfType,我构建了以下场景循环:

void IterateThroughScene(Scene scene)
        {
            SortedList<string, NetworkedObject> sortedObjects = new SortedList<string, NetworkedObject>();
            //List<CrossSceneAudioSyncListener> audioListeners = new List<CrossSceneAudioSyncListener>();
            
            foreach (GameObject sceneRootObject in scene.GetRootGameObjects())
            {
                foreach (NetworkedObject netObj in sceneRootObject.GetComponentsInChildren<NetworkedObject>())
                {
                    Vector3 position = netObj.transform.position;
                    string transformHash = position.x.ToString("0.00") + position.y.ToString("0.00") + position.z.ToString("0.00");
                    transformHash = Hashing.MD5(transformHash);
                    
                    sortedObjects.Add(transformHash, netObj);

                    //CrossSceneAudioSyncListener audioListener = netObj.GetComponent<CrossSceneAudioSyncListener>();
                    //if(audioListener != null) audioListeners.Add(audioListener);
                }
            }

            //CrossSceneAudioSyncInstance.LoadObjects(audioListeners);
            
            Dictionary<ushort, NetworkedObject> preparedObjects = new Dictionary<ushort, NetworkedObject>();
            ushort lastId = _ids[scene.name];
            
            foreach (var part in sortedObjects)
            {
                NetworkedObject preparedObject = part.Value;
                preparedObject.GetObjectData().id = lastId;
                preparedObjects[lastId] = preparedObject;
                lastId++;
            }

            _ids[scene.name] = lastId;
            _registeredObjects[scene.name] = preparedObjects;
        }

这里我一步一步列出这个方法的作用:

  • SortedList 被实例化以保存对象
  • 2 个 foreach 正在获取场景中的所有对象
    • 这里脚本生成位置的MD5并添加到SortedList中
  • 之后,创建 Dictionary 实例来保存最终数据
  • 下一个 foreach 完成,循环通过 SortedList 并以可靠的方式分配 NetworkedObject ID。

这在中小型场景中做得很好,但我开始在大型场景中遇到严重问题 - 我有一台很好的 PC 并且迭代需要 12 秒,我的游戏目标是中型 PC .

那么,你知道如何优化这个算法吗?

【问题讨论】:

  • 你能不能只标记所有的门并使用FindGameObjectsWithTag。我不知道内部FindObjectsOfType 是如何工作的,所以我无法比较这段代码的有效性。我能想象的唯一让搜索更有效的地方是修剪。您正在遍历场景中的每个对象,然后获取每个具有组件的子对象。您可以让门将所有根父节点标记为有门以便于查找。
  • FindObjectOfType 不是一种可靠的方法。它可能以不同的顺序返回对象,这是不可接受的,有时我别无选择并且需要使用子对象
  • 或者,与其在大海捞针中寻找针,不如让针告诉你它自己。您可以让门获取门管理器的引用,然后让它在调用函数时分配 id,或者使用静态实例实现 Singleton Pattern
  • 不保存值是什么意思?你很可能不是marking the scene as dirty。如果您确实需要在运行时执行此操作,请制作一个异步加载屏幕,并在需要时将其扔掉。我建议废弃它并制作一个编辑器工具。
  • @TEEBQNE 感谢 MarkSceneDirty!现在编辑器脚本按预期工作!这个算法现在没用了。

标签: c# algorithm unity3d optimization


【解决方案1】:

由于我不知道FindObjectsOfType 的内部结构,因此很难将该方法与您的 sn-p 进行比较。但是,您确实提到了顺序很重要,并且由于不能保证 FindObjectsOfType 以任何特定顺序返回对象,因此它不适用于您的用例。

要优化 sn-p,您需要以某种方式修剪您的搜索。当您查看所有根游戏对象时,您可以用每个根对象作为子对象的门数来标记每个根对象,并为每个根保留一个计数器。这样一来,一旦达到需要从子级发送的数量,它就可以停止搜索该根对象。

但是,您似乎只想为场景中的对象分配有序 id 以供参考,我建议您使用编辑器工具来处理分配。代码几乎相同,但优点是在运行时不需要关心开销,因为它是在游戏之外计算的。在实现任何改变场景的编辑器工具时,请确保mark the scene as dirty 以确保 Unity 将保存更改。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多