下面以如下的测试场景作为例子,进行说明。此时测试的脚本是挂载在TestNode1上
一、GameObject.Find(string param)
根据名字查找
最常用的方法是GameObject.Find,这里参数可以填物体的名字,并且是全局搜索,与脚本所在的节点并没有关系,比如下面直接查找TestNode111和TestNode22,均可以找到对应的点
if (GameObject.Find("TestNode111") != null)
{
Debug.Log("GameObject.Find TestNode111 true");
}
else
{
Debug.Log("GameObject.Find TestNode111 false");
}
if (GameObject.Find("TestNode22") != null)
{
Debug.Log("GameObject.Find TestNode22 true");
}
else
{
Debug.Log("GameObject.Find TestNode22 false");
}
但是由于这个方法查找的是全局的物体,所以当物体比较多的时候会消耗较大的性能,所以不要过于频繁地调用。还有要注意的一点是,如果场景中存在同名节点的话。这里只会返回找到的第一个节点,所以要避免重名的情况。
还有就是GameObject.Find参数为物体名时,无法找到active为false的节点,可以尝试将TestNode111的active设为false,可以看到这时候就无法找到这个节点了
根据路径查找
参数还可以填路径,这里的路径可以是绝对路径和相对路径,通过路径来寻找节点的消耗,会比直接根据物体名称要低,节点结构还是如下
绝对路径是以"/"开头或者物体名字开头,并且场景名称是不在这个路径里面。比如查找TestNode111这个点。
绝对路径应该填GameObject.Find("/TestNode1/TestNode11/TestNode111")
如果填的是GameObject.Find("/TestScene/TestNode1/TestNode11/TestNode111")或者GameObject.Find("TestScene/TestNode1/TestNode11/TestNode111")都是无法查找到对应节点的。
相对路径的时候需要以物体的name开头,而不能以"/"开头
比如GameObject.Find("TestNode11/TestNode111") 查找成功
而GameObject.Find("/TestNode111")查找失败
if (GameObject.Find("TestNode11/TestNode111") != null)
{
Debug.Log("GameObject.Find TestNode11/TestNode111 true");
}
else
{
Debug.Log("GameObject.Find TestNode11/TestNode111 false");
}
if (GameObject.Find("/TestNode1/TestNode11/TestNode111") != null)
{
Debug.Log("GameObject.Find /TestNode1/TestNode11/TestNode111 true");
}
else
{
Debug.Log("GameObject.Find /TestNode1/TestNode11/TestNode111 false");
}
if (GameObject.Find("TestNode1/TestNode11/TestNode111") != null)
{
Debug.Log("GameObject.Find TestNode1/TestNode11/TestNode111 true");
}
else
{
Debug.Log("GameObject.Find TestNode1/TestNode11/TestNode111 false");
}
if (GameObject.Find("TestScene/TestNode1/TestNode11/TestNode111") != null)
{
Debug.Log("GameObject.Find TestScene/TestNode1/TestNode11/TestNode111 true");
}
else
{
Debug.Log("GameObject.Find TestScene/TestNode1/TestNode11/TestNode111 false");
}
if (GameObject.Find("/TestNode111") != null)
{
Debug.Log("GameObject.Find /TestNode111 true");
}
else
{
Debug.Log("GameObject.Find /TestNode111 false");
}
在用绝对路径找active为false的时候,如果被查找的节点active为false,而父节点active为true,还是可以找到这个节点的。结果如下
用相对路径查找,则无法找到active为false的节点
而当他的父节点active也为false的时候查找就会失败,结果如下
二、GameObject.FindWithTag
GameObject.FindWithTag的逻辑跟GameObject.Find基本相同,同样是全局查找。跟GameObject根据名字查找的功能类似,只不过查找的是根据Tag属性,而且同样无法找到active为false的节点。
三.Transform.Find
transform.Find是查找挂载脚本节点的子节点,并且只能找到孩子节点,直接Find孙子是无法找到的。如果想要找到孙子节点,就需要逐级地去调用Find函数。并且transform.Find也可以找到active为false的节点,下面是直接查找孩子节点和孙子节点的结果
if (this.transform.Find("TestNode11") != null)
{
Debug.Log("this.transform.Find TestNode11 true");
}
else
{
Debug.Log("this.transform.Find TestNode11 false");
}
if (this.transform.Find("TestNode111") != null)
{
Debug.Log("this.transform.Find TestNode111 true");
}
else
{
Debug.Log("this.transform.Find TestNode111 false");
}
四、获取active为false的根节点的方法
因为transform可以通过层级关系查找active为false的节点。所以用transform.Find基本可以找到场景里的所有节点。对于不在这个Transfrom的节点树上的根节点,比如例子中的TestNode2,如果active为true,也可以直接用GameObject.Find来查找。
但是这里面还包含一种特殊的情况,就是不在同一个节点树上,active为false的根节点,下图中的TestNode2是active为false的根节点。
这时候有两种方法
UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects()
Resources.FindObjectsOfTypeAll(typeof(GameObject))
代码如下
GameObject[] allRoot = UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects();
for (int i = 0; i < allRoot.Length; i++)
{
if (allRoot[i].name == "TestNode2")
{
Debug.Log("GetRootGameObjects find TestNode2 true");
break;
}
}
GameObject[] all = Resources.FindObjectsOfTypeAll(typeof(GameObject)) as GameObject[];
for (int i = 0; i < all.Length; i++)
{
var item = all[i];
if (item.scene.isLoaded)
{
if (item.name == "TestNode2")
{
Debug.Log("FindObjectsOfTypeAll find TestNode2 true");
break;
}
}
}
可以看到下方的结果,两种方法都可以顺利到找到TestNode2