赞
踩
我们写好的脚本,是经过编译之后才被使用,而Unity游戏引擎对脚本的编译顺序也是顺序的,了解这个顺序会对程序编码大有裨益。同时,写在我们脚本中的函数也是按一个固定的执行顺序执行的,这个固定的执行顺序就是Unity的生命周期,这是Unity学习者必须掌握的。
编译的原则是在第一个引用前编译它,因此,将脚本放在Assets不同文件夹下不同位置会有不同的编译顺序。官方给出的编译顺序如下:
其中各个特殊文件夹是什么请参考本系列的第一篇文章。可以看到,编译一共分为四个阶段,两大块(标准资源配置块和自定义块),且每个块下的Editor文件夹中的资源编译靠后(可以理解Editor编写的为引擎工具,是对其所属块内资源的编辑使用,因此要靠后编译)。
在Unity中一般存在这么几种文件类型:资源文件(Imported Assset),代码文件,序列化文件(Native Asset),文本文档,非序列化文件,meta文件。
每个编译阶段都会产生对应的项目文件。以C#为例,当项目中包含有C#脚本时,Unity引擎会产出以Assembly-CSharp为前缀,csproj为后缀的文件,名称中包含“vs”表示是给Visual Studio用的,不含则是给Mono Develop用的。
可能部分初学者没看过Assembly-CSharp-firstpass.csproj文件,那是因为你的项目里没有Standard Assets, Pro Standard Assets和Plugins三个文件夹中的任何一个,自然也不会编译产生这个项目文件。
在产生这些项目文件的编译过程中,同时也会在工程根目录/Library/ScriptAssemblies下生成dll,分别为:
Assembly-CSharp-Editor.dll:包含所有Editor下的脚本;
Assembly-CSharp-firstpass.dll:包含Standard Assets, Pro Standard Assets, Plugins文件夹下的脚本(不含Editor文件夹)
Assembly-CSharp.dll:包含除了以上两种所有位于Assets目录中的脚本;
不同语言的脚本,编译出的工程文件的前后缀也不同,也会生成不同的dll文件,下面为不同语言对应的前后缀:
资源文件(Imported Asset):指一些创建好,并且不再修改的文件。比如美术给的FBX文件,贴图,音频,视频等等。这类文件在导入时都会对应一个Asset Importer,生成对应的.meta文件和存储在Library目录下Unity可识别的内部格式。每次修改原始文件,Unity都会重新导入一次,当删除Library或里面某个文件,会让Unity重新导入相应的资源,不会对工程造成影响;
代码文件:包括所有的代码文件,代码库文件,shader文件等,在导入时Unity会进行一次编译。
序列化文件(Nativa Asset):序列化文件是指Unity能够序列化的文件,一般为Unity自身的类型,如prefab,场景文件,.mat文件(材质球),asset(ScriptableObject)文件。这些文件能够在运行时直接反序列化为对应类的一个实例。
文本文档:不是序列化文件,但是Unity可以识别为TextAsset,如txt, xml, json等;
非序列化文件:Unity无法识别的文件。
Assets文件夹中所有文件,文件夹,经过Unity导入过程后,都会在其同目录下生成一个.meta文件,该文件Unity内部用来管理文件的,记录着重要内容。meta文件本质上是一个使用YAML格式编写的文本文档。1
guid,global unique ID,是meta中最重要的数据。它是该项目中全局唯一的,代表了这个文件。只要通过这个GUID就可以找到工程中的这个文件。对于Unity的序列文件来说,引用的对象就是这个GUID,故一旦meta中GUID变更了,会造成一场引用丢失的灾难。
当该文件为从外部导入的资源文件,那么会有一个对应的ImportSetting。不同文件类型对应着不同的ImportSetting数据,如:NativeFormatImporter, ModelImporter, AudioImporter等等。ImportSetting中每一行都对应着Inspector面板中的条目。因此,当我们将一个文件和该文件的meta文件从一个Unity工程复制到另一个工程中,它的配置是不会变的。
当一个文件下有多个其它文件,如一个图集下面有若干图片,那么一个GUID怎么对应其下的文件呢?这个时候就需要FileID,通过GUID找到任何一个文件,再通过FileID找到其中某个子文件。
对于非序列化的资源文件,由于不会更改源文件,所以FileID存储在meta文件中,像FBX文件,图集就是这种类型;对于序列化文件,其自身数据中存储自身的FileID,也会记录所有子文件的FileID,因此mete文件中只有自身的FileID,如AnimatorController, prefab等。
当文件名为"CVS"或者该文件拓展名为".tmp"时,该文件会被隐藏(在Project视图中不可见)。
对于游戏场景中所有继承了MonoBehaviour的组件(自定义脚本),MonoBehaviour提供了一系列函数供调用。当游戏运行时,进程会按照生命周期中函数的顺序自动调用,如:当执行完所有游戏物体的OnMouseXXX()后才会执行所有游戏物体的Update()。
这里推荐一篇关于Unity生命周期的文章。下面为Unity生命周期图:
开发中生命周期需要注意的地方:
Unity内部的序列化文件都是用这个格式类写的,如prefab, 场景等; ↩︎
Reset()函数是在编辑模式下使用的,严格来说不属于生命周期,Reset()函数在将该脚本附加到游戏物体上时或点击组件栏右上角菜单下的Reset选项时调用; ↩︎
这里还要强调一下生命周期中创建脚本实例的情况:在创建脚本实例过程中,若创建带有该脚本的游戏物体且该游戏物体为激活状态(创建后立刻被激死也不行),则该脚本的Awake()在创建过程中会立刻执行,而该脚本的Start()则根据执行添加该脚本时的生命周期不同而有所区别:若该脚本实例在Awake()中创建则在当前帧和其它要执行的Start()一起执行;若是在Start()或之后的生命周期中里被创建则会延后到下一帧执行。 ↩︎
改变Time.timeScale将会对FixedUpdate()函数的执行造成影响。因为FixedUpdate()是根据时间来执行的,而Time.timeScale会对游戏中的时间进行缩放(虽然不会影响真实过了的时间)。因此,随着Time.timeScale的增大,FixedUpdate()执行的频率将会越来越高;而当Time.timeScale为0时,FixedUpdate()将会停止执行。(其它的如WaitForSeconds()和时间相关的受同样的影响); ↩︎
Time.timeScale不会影响Update()和LateUpdate()的执行速度; ↩︎
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。