【问题标题】:Find inactive GameObject by name, tag or layer按名称、标签或层查找非活动游戏对象
【发布时间】:2017-06-09 11:02:43
【问题描述】:

首先,我需要停用一个游戏对象,然后在 10 秒后激活它,所以我认为协程是合适的:

IEnumerator BarDeactivate(float sec)
{
        yield return new WaitForSeconds(sec);

        var obj = GameObject.Find("OBJ");
        obj.SetActive(false);
}

IEnumerator BarReactivate(float sec)
{
        yield return new WaitForSeconds(sec);

        var obj = transform.Find("OBJ");
        obj.SetActive(true);
}

显然,我不能再使用GameObject.Find,所以我使用transform.Find 来查找inactive 游戏对象,但是.SetActive 现在当然不起作用,因为obj 实际上不是游戏对象...

如何转换找到的变换,以便再次激活它?

我试过obj.gameObject.SetActive(true),但肯定是错的,因为对象不会复活......

【问题讨论】:

    标签: c# unity3d


    【解决方案1】:

    问题是 Unity 无法找到非活动的游戏对象。 GameObject.Find 只会找到活动的游戏对象。您应该找到 GameObject 并将其存储在全局变量中,或者将变量设为 public,然后从编辑器中分配它。

    我的解决方案使用全局变量,然后将 GameObject 存储在初学者中,这样您就不必再次查找它。

    GameObject obj;
    
    void Start()
    {
        obj = GameObject.Find("OBJ");
    }
    IEnumerator BarDeactivate(float sec)
    {
        yield return new WaitForSeconds(sec);
        obj.SetActive(false);
    }
    
    IEnumerator BarReactivate(float sec)
    {
        yield return new WaitForSeconds(sec);
        obj.SetActive(true);
    }
    

    下面是我制作的一个包装器,它通过名称、标签或层来查找游戏对象,即使它们处于非活动状态。

    您不应该在每一帧都使用这些,因为它们很慢。如果在 StartAwake 函数中使用它们是很好的。

    找到一个游戏对象:

    用法:

    void Start()
    {
        GameObject objByName = FindInActiveObjectByName("Cube");
        GameObject objByTag = FindInActiveObjectByTag("CubeTag");
        GameObject objByLayer = FindInActiveObjectByLayer(LayerMask.NameToLayer("CubeLayer"));
    }
    

    按名称查找处于活动状态的游戏对象:

    GameObject FindInActiveObjectByName(string name)
    {
        Transform[] objs = Resources.FindObjectsOfTypeAll<Transform>() as Transform[];
        for (int i = 0; i < objs.Length; i++)
        {
            if (objs[i].hideFlags == HideFlags.None)
            {
                if (objs[i].name == name)
                {
                    return objs[i].gameObject;
                }
            }
        }
        return null;
    }
    

    通过标签查找处于活动状态的游戏对象:

    GameObject FindInActiveObjectByTag(string tag)
    {
    
        Transform[] objs = Resources.FindObjectsOfTypeAll<Transform>() as Transform[];
        for (int i = 0; i < objs.Length; i++)
        {
            if (objs[i].hideFlags == HideFlags.None)
            {
                if (objs[i].CompareTag(tag))
                {
                    return objs[i].gameObject;
                }
            }
        }
        return null;
    }
    

    按层查找处于活动状态的游戏对象:

    GameObject FindInActiveObjectByLayer(int layer)
    {
    
        Transform[] objs = Resources.FindObjectsOfTypeAll<Transform>() as Transform[];
        for (int i = 0; i < objs.Length; i++)
        {
            if (objs[i].hideFlags == HideFlags.None)
            {
                if (objs[i].gameObject.layer == layer)
                {
                    return objs[i].gameObject;
                }
            }
        }
        return null;
    }
    


    查找所有游戏对象(注意下面所有函数名称中对象中的“s”):

    用法:

    void Start()
    {
        GameObject[] objByNames = FindInActiveObjectsByName("Cube");
        GameObject[] objByTags = FindInActiveObjectsByTag("CubeTag");
        GameObject[] objByLayers = FindInActiveObjectsByLayer(LayerMask.NameToLayer("CubeLayer"));
    }
    

    按名称查找处于活动状态的 GameObject[s]:

    GameObject[] FindInActiveObjectsByName(string name)
    {
        List<GameObject> validTransforms = new List<GameObject>();
        Transform[] objs = Resources.FindObjectsOfTypeAll<Transform>() as Transform[];
        for (int i = 0; i < objs.Length; i++)
        {
            if (objs[i].hideFlags == HideFlags.None)
            {
                if (objs[i].gameObject.name == name)
                {
                    validTransforms.Add(objs[i].gameObject);
                }
            }
        }
        return validTransforms.ToArray();
    }
    

    按标签查找非活动游戏对象:

    GameObject[] FindInActiveObjectsByTag(string tag)
    {
        List<GameObject> validTransforms = new List<GameObject>();
        Transform[] objs = Resources.FindObjectsOfTypeAll<Transform>() as Transform[];
        for (int i = 0; i < objs.Length; i++)
        {
            if (objs[i].hideFlags == HideFlags.None)
            {
                if (objs[i].gameObject.CompareTag(tag))
                {
                    validTransforms.Add(objs[i].gameObject);
                }
            }
        }
        return validTransforms.ToArray();
    }
    

    按层查找处于活动状态的 GameObject[s]:

    GameObject[] FindInActiveObjectsByLayer(int layer)
    {
        List<GameObject> validTransforms = new List<GameObject>();
        Transform[] objs = Resources.FindObjectsOfTypeAll<Transform>() as Transform[];
        for (int i = 0; i < objs.Length; i++)
        {
            if (objs[i].hideFlags == HideFlags.None)
            {
                if (objs[i].gameObject.layer == layer)
                {
                    validTransforms.Add(objs[i].gameObject);
                }
            }
        }
        return validTransforms.ToArray();
    }
    

    【讨论】:

      【解决方案2】:

      在您的情况下,Invoke 是比协程更好的选择。此外,据我所知,您不能 .Find 一个非活动对象,因此您应该将找到的对象分配给一个字段。

      var obj;
      
      void BarDeactivate(){
          obj = GameObject.Find("OBJ");
          obj.SetActive(false);
      }
      
      void BarReactivate(){
          obj.SetActive(true);
      }
      

      像这样通过 Invoke 调用它们:

      Invoke("BarDeactivate", sec);
      Invoke("BarReactivate", sec);
      

      【讨论】:

      • 有效!非常感谢。尽管我不得不将另一个答案标记为已接受,因为在这种情况下,它建立在我的协程解决方案之上并解决了它,但是您的答案非常优雅和有用。我在稍微不同的情况下尝试过它,它就像一个魅力。非常感谢
      【解决方案3】:

      我在 ARCore、Vuforia 等方面遇到了这个问题,因为游戏对象在被跟踪之前是不活跃的。一种方法是等待目标被识别,然后寻找游戏对象,但如果它们手动处于非活动状态,唯一的另一种(简单?)方法是手动列出它们并将它们作为公共数组与脚本链接。如果您的脚本已链接,那么即使是非活动的 GameObject 也可以访问。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-13
        • 1970-01-01
        相关资源
        最近更新 更多