【问题标题】:Better way to find Gameobjects without GameObject.Find在没有 GameObject.Find 的情况下找到 Gameobjects 的更好方法
【发布时间】:2018-09-17 20:08:31
【问题描述】:

使用 Unity,我正在开发一款游戏,其中所有带有特定标签的 Gameobjects 相当有规律地消失/重新出现(平均每 10 秒)。我使用GameObject.FindGameObjectsWithTag() 创建一个Gameobject[],每次需要使对象可见/不可见时,我都会通过它枚举。我不能在开始时调用它一次,因为在播放时会创建新的Gameobjects。我认为每次创建/销毁某些东西时访问和更改Gameobject[] 会更糟糕。有没有更好的方法来处理这个问题。我知道GameObject.Find 方法对性能的影响有多大...

【问题讨论】:

    标签: c# unity3d optimization


    【解决方案1】:

    是的,有更好的方法来做到这一点。有一个可以存储游戏对象的带有List 变量的脚本。使其成为单例更好,但不是必需的。

    这个单例脚本应该附加到一个空的游戏对象:

    public class GameObjectManager : MonoBehaviour
    {
        //Holds instance of GameObjectManager
        public static GameObjectManager instance = null;
        public List<GameObject> allObjects = new List<GameObject>();
    
        void Awake()
        {
            //If this script does not exit already, use this current instance
            if (instance == null)
                instance = this;
    
            //If this script already exit, DESTROY this current instance
            else if (instance != this)
                Destroy(gameObject);
        }
    }
    

    现在,编写一个脚本,将自己注册到GameObjectManager 脚本中的List。它应该在Awake 函数中注册自己并在OnDestroy 函数中取消注册。

    此脚本必须附加到您要添加到列表中的每个预制件上。只需从编辑器中执行此操作:

    public class GameObjectAutoAdd : MonoBehaviour
    {
        void Awake()
        {
            //Add this GameObject to List when it is created
            GameObjectManager.instance.allObjects.Add(gameObject);
        }
    
        void OnDestroy()
        {
            //Remove this GameObject from the List when it is about to be destroyed
            GameObjectManager.instance.allObjects.Remove(gameObject);
        }
    }
    

    如果游戏对象不是预制件而是通过代码创建的游戏对象,只需在创建后将GameObjectAutoAdd 脚本附加到它们:

    GameObject obj = new GameObject("Player");
    obj.AddComponent<GameObjectAutoAdd>();
    

    您现在可以使用GameObjectManager.instance.allObjects[n]; 在列表中访问您的GameObjects,其中n 是索引号,您不必再使用任何Find 函数来查找游戏对象。

    【讨论】:

    • 感激不尽。这解决了我所有的问题!你不能更好地解释它。你有我最深切的感谢。
    • 不客气。顺便说一句,我在 OnDestroy 函数中的答案中有一个错字,我使用 List Add 函数而不是 Remove 函数。 Add 函数只能在 Awake 函数中。我刚刚修好了。 确保更新代码。
    • 通常我更喜欢在Start而不是Awake中执行外部引用操作,除非事先建立了非常具体的脚本执行顺序。
    • @Galandil 我明白你的意思。不知道要放置代码的函数可能会导致变量在使用前未初始化等问题。不过,我花了几分钟时间决定在AwakeStartOnEnable 之间使用哪一个,并决定使用Awake。这个决定背后的两个原因是: 1.Awake 函数即使在该脚本被禁用时也会被调用。如果不这样做,脚本将不会在禁用时自行注册。 2.Awake函数将在注册它的第一帧被调用,以便在其他脚本的Start更新中使用。
    • 我的错!一定是误点击
    【解决方案2】:

    调用 GameObject.Find 确实会消耗大量资源。

    重点应该是保存结果并始终使用它,但我知道你不能这样做。

    另一种选择是将所有这些游戏对象作为一个游戏对象的子对象,我们将其称为 handlerGameobject。它将有一个不使用 GameObeject.Find 的脚本,它可以使用较少资源的 getChild 或 transform.Find。

    希望对你有帮助!

    【讨论】:

    • 非常感谢!它确实有帮助。
    • @Chopi 您需要 15 个代表才能投票。 OP是新的,还没有那个代表,所以不能投票。虽然,他/她可以接受他/她已经完成的答案。
    猜你喜欢
    • 1970-01-01
    • 2021-08-10
    • 2016-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-21
    相关资源
    最近更新 更多