Unity3D中Find()方法的返回值的探究

时间:2023-01-05 20:15:49

                      Unity3D中Find()方法的返回值的探究

        首先自我介绍一下,我是一名面临毕业就业压力的在校大学生。出于就业的考虑,机缘巧合之下开始学习Unity3D,至今约半年时间。算是个Unity3D的初学者,在此总结记录些自己的学习经验。希望会对刚开始接触Unity3D的初学者有帮助。

        好了,废话不多说,进入正题:

        就我目前的个人理解,制作游戏时,我们游戏开发者所做的事情就是:通过编写脚本来控制场景中的游戏物体完成目标行为来表现游戏过程的发展。要控制游戏物体,首先就得找到它。所以,我们在编写脚本时会非常频繁的用到GameObject.Find();(包含但不限于GameObject.Find(); GameObject.FindGameObjectWithTag(); GameObject.FindObjectOfType<>(); 方法 ,除非有特殊说明,后文皆用Find()代指以上所有方法)方法。当然这些方法的使用都很简单,这里不做赘述,我今天在此探讨的是这样一个问题:

假如场景中有多个符合Find()方法条件约束的游戏物体,那么这个方法会返回哪一个?        Unity3D中Find()方法的返回值的探究

这里援引官方API,在官方API中并未给出对于这种状况的处理解释。

      本着探(xian)寻(de)本(dan)质(teng)的精神,我对以上问题进行了实际测试。结果如下:

      GameObject.Find();

            此方法的参数为String类型:目标游戏物体的name;

       那么上述问题具体到这里就是:假如场景中有多个重名的gameobject,那么GameObject.Find();方法会返回哪一个?

       一下是测试结果:

Unity3D中Find()方法的返回值的探究 这个示例场景中,脚本绑定在MainCamera游戏物体上,脚本中控制语句如下:

Unity3D中Find()方法的返回值的探究

表面上看,GameObject.Find();方法返回的是左边Hierarchy界面最底部的游戏物体。事实真的如此吗?

于是我进行了验证:通过拖拽改变左侧Hierarchy界面中3个Cube物体的顺序,然后观察运行结果:

Unity3D中Find()方法的返回值的探究

显然通过结果来看,返回结果与左侧hierarchy界面的顺序无关。

那么,Unity3D到底是以怎样的规则来选择返回的游戏物体呢?随机?显然不是的,因为多运行几次就不难看出,被染成红色的总是那个固定的Cube物体。其实我们一直忽略了一点,那就是:游戏物体的创建时间。

       上图中左侧hierarchy界面从上之下的3个Cube物体的创建顺序分别为3,1,2 。至此我们会自然的想到,GameObject.Find();方法返回的是到目前为止最晚被创建的游戏物体(即存在时间最短,最年轻,最新)。至于猜想是否正确,我们可以简单验证一下:Unity3D中Find()方法的返回值的探究

以上这张图是删除掉创建顺序为3之后的结果,



Unity3D中Find()方法的返回值的探究 这是再重新创建一个Cube的结果。

于是我们可以得出一个结论:当GameObject.Find();方法查找的游戏物体在一个场景中存在多个,那么这个方法将会返回最晚被创建的(也就是存在时间最短,最新的)游戏物体;


       GameObject.FindGameObjectWithTag();

有了以上的经验,关于游戏物体在左侧hierarchiy界面的顺序是否对于这个方法有影响的测试我在这里就不做赘述了;直接上结论:游戏物体在左侧hierarchiy界面的顺序与GameObject.FindGameObjectWithTag();这个方法的返回值无关。

       很自然的我们又会想到那必然会跟上面的GameObject.Find();方法一样,跟创建顺序有关。于是我进行了测试,结果显示确实是跟结论一致。可是,我们这里又忽略了一点,游戏物体的Tag是可以被自主更改的,于是这就会产生一个问题:游戏物体的Tag的修改时间顺序,跟它被创建的时间顺序是不一样的。那么GameObject.FindGameObjectWithTag();这个方法会不会跟Tag的创建顺序有关?于是我进行了测试:

Unity3D中Find()方法的返回值的探究 经过多次验证(为避免文章过于繁冗,此处只贴一张图),我得出结论:

GameObject.FindGameObjectWithTag();方法查找的游戏物体在一个场景中存在多个时,此时此方法返回的游戏物体跟游戏物体被创建的时间无关,而是返回Tag修改时间最短(即最后被创建Tag)的游戏物体;


      GameObject.FindObjectOfType<>();

           GameObject.FindObjectOfType<>();这个方法有一中特殊用途:<>中可以填写一种组件的类名,即可以查找绑定有某指定组件的游戏物体,当然这里也可以填写一个脚本的名字。

       经过以上的实际测试,相信大家也能很容易想到:GameObject.FindObjectOfType<>();这个方法返回的游戏物体十有八九应该也是与该游戏物体被添加某种组件的时间顺序有关。

       于是我进行了测试,方法与上面的方法无二。重复的就不赘述了,直接上结论:

GameObject.FindObjectOfType<>();方法查找的游戏物体在一个场景中存在多个时,此时此方法返回的游戏物体跟游戏物体被创建的时间无关,而是与游戏物体被添加这个组件的时间顺序有关,返回最后被添加某组件的游戏物体;

       至此,我的试验完成了,可是就在我准备结束这篇文章之时,Unity3D崩溃了,于是我重新启动,打开场景,发现了一个问题:在我重新运行时,出现了与之前截然相反的结果!

        于是我大胆猜想:当一个场景重新打开时,其之前被搭建的时间顺序信息被打乱(或者甚至被丢弃),Unity3D以自己的规则顺序,运行某种算法将一个场景搭建成你打开的场景。至于这种猜想是否正确,以我目前的能力是无法验证的。

       最后,给初次接触Unity3D的初学者一个提醒:在使用Find()方法查找游戏物体时,应避免重复,否则往往会找到错误的结果。避免重复就得有一个系统的,科学的命名规则。好的命名规则将会使你的程序,代码的易读性,准确性,规则性,甚至美感,大大提升。想了解详情请参阅:http://wenku.baidu.com/link?url=sSSgsx-im0mjjtJGv7icuRaDbBBXtB6Mnfd1cAb33po2bbLXGjLnT1F9mC9v-K-G9E75lkS_ZN3QzuNKR3idPaOshof9N2pBFMoBZo6XbOi