Tag:Unity文件,Unity文件引用,Meta文件,GUID,FileID,LocalIDhtml
本文介绍unity工程中的文件类型,文件引用原理和meta文件的yaml结构等node
参考文档:数据结构
在unity3d中通常存在这么几种文件编辑器
资源文件指一些建立好的,而且再也不修改的文件。这样的文件通常是美术设计师,音频视频设计师创造的文件,好比FBX文件,贴图文件,音频文件,视频文件,动画文件(虽然动画文件能够被认为是配置文件,不过在因为通常不会去作修改,因此也认为是资源文件)。像这类文件,unity中都会在导入时进行转化。每个类型都对应一个AssetImporter,好比AudioImporter,TextureImporter,ModelImport等等。在unity中点击这样的资源,在Inspector面板会出现设置界面,以下图所示是一个FBX的设置界面:svn
代码文件包括全部的代码文件,代码库文件,shader文件等,在导入时,unity会进行一次编译。动画
序列化文件一般是指unity可以序列化的文件,通常是unity自身的一些类型。好比prefab(预制体),unity3d(场景)文件,asset(ScriptableObject)文件.mat文件(材质球),这些文件可以在运行时直接反序列化为对应类的一个实例。ui
文本文档比较特殊,它不是序列化文件,可是unity能够识别为TextAsset。很像资源文件,可是又不须要资源文件那样进行设置和转化。好比txt、xml文件等等。设计
非序列文件是Unity没法识别的文件,好比一个文件夹也会被认为是一个文件,可是没法识别。3d
meta文件在unity中的做用很是关键,它有2个做用orm
因为meta文件的重要性,这里先说说meta文件的数据结构。meta文件实质上是一个文本文档,只是采用的是一种叫作YAML的格式来写的(见Description of the Format)。unity中的序列化文件都是用这个格式类写的,好比prefab,场景等(后文会继续)。
咱们使用nodepad++打开一个meta文件,而后在菜单中将语言设置为YAML,以下图所示:
这是一个asset文件(ScriptableObject)的meta文件
guid是meta中最最最重要的数据。这个guid表明了这个文件,不管这个文件是什么类型(甚至是文件夹)。换句话说,经过GUID就能够找到工程中的这个文件,不管它在项目的什么位置。在编辑器中使用AssetDatabase.GUIDToAssetPath和AssetDatabase.AssetPathToGUID进行互转。
因此在每次svn提交时若是发现有meta文件变动,必定要打开看一下。看看这个guid是否被更改。理论上是不须要更改的。
后面比较重要的数据是ImportSetting数据。根据不一样的文件类型,它的数据是不一样的ImportSetting数据,好比上面的NativeFormatImporter,ModelImporter,AudioImporter等等。只要对照Inspector面板中的条目,均可以看懂每一行的意义。
因此知道这个以后,咱们能够发现,假如咱们把一个文件和这个文件的meta文件从一个Unity工程复制到另外一个Unity工程中,它的配置是不会变的。(之前在2个工程手动裁剪同一个模型的20个动画真是傻到家了,直接将这个fbx和它的meta文件拷贝过去就行!)
有一个问题是,若是是一个图集,下面有若干个图片,那么,这个GUID怎么对应一个文件呢?是的,对于一个文件下有多个文件的状况,就须要另一个ID来表示,这就是LocalID。更习惯用meta文件中的名字FileID。
FileID存储方式有2种
回到本节一开始的问题,若是是图集,由于是图片自己是资源文件,因此会有FileID存储在对应的meta文件中。打开任意一个图集,好比如下这个图集对应的meta文件
至此就是整个Unity的GUID/LocalID系统的基础了。经过GUID找到任何一个文件,经过FileID找到其中的某个子文件。
上文已经提到,对于全部的序列化文件,unity采用的是YAML来书写。因此对于一个unity3d(场景)文件,prefab文件,材质,控制器等,均可以用文本文档软件打开。这里仍是用Notepad++打开。
为了可以简洁地说明问题,咱们在unity中建立一个新的场景,而后建立2个Cube,一个作成Prefab。如图所示:
保存以后,用Notepad++打开这个1.unity3d。而后在菜单中设置语言为YAML。
能够看到大概的数据
展开第一个GameObject,能够看到这个的Name就是Main Camera。这个物体上有4个组件,一一对应下面的数据。这就是物体内的引用关系。每个Unity对象都会有一个FileID,而后在须要引用时,使用这些FileID便可。因此在实例化一个这样的GameObject时,只要依照次序,依次建立物体,组件,初始化数据并进行引用绑定便可在场景中生成一个实例。
咱们在Inspector面板中的右上角点击,而后选择Debug转成Debug模式下的Inspector面板
在Hierarchy面板中选中Main Camera能够看到如图所示,全部的组件的LocalIdentfierInFile的值就是刚刚在Notepad++中看到的数据
这里有一点,咱们看到有一个叫作InstanceID的数据。这个是unity中一个实例的ID。每个Unity实例都会有一个InstanceID。在运行时,可使用UnityEngine.Object的GetInstanceID获取。可是要注意的是,每一次运行,至关于从新生成了新的实例,因此这个值是可变的。(更多细节参考《Unity编辑器下和运行时的加载过程》)
在GameObject以后就是这个GameObject的组件数据(不知道次序会不会乱,理论上不影响)。每个组件的数据基本上就是这个组件的一堆参数了。能够结合Unity中这个组件的面板来了解每个数据的意义。
这里有一个问题,好比这里有一个组件是FlareLayer,可是在YAML里面只是一个Behaviour(全部Behaviour组件都看不到类型名字),怎么样才能知道他是一个FlareLayer?
能够看到在这个数据上方,在FileID左边咱们看到一个124。对,这个就是FlareLayer。请参考YAML Class ID Reference,每个unity类型都有一个对应的数字。
那么自定义脚本类呢?
咱们建立一个Test脚本,继承MonoBehaviour。里面什么都不写。添加到Main Camera物体上。保存场景而后回到Notepad++。
能够看到多了一个MonoBehaviour,而且这个里面有一个m_Script数据,指向对应的GUID及其FileID。上文咱们已经说了,任何一个文件均可以经过GUID找到,而后经过FileID找到它内部的子文件。因此这样就能识别出这个具体是什么类了。
咱们往Test中写2个字段
public int A;
public Test RefTest;
在Main Camera中,设置Test脚本的A值为111,RefTest设置为自身。保存后回到Notepad++;
看到数据想必都明白了。
能够往Test中写一些其余类型的数据,看看这些序列化数据放在YAML的哪一个位置!这里再也不展开(这些数据和编辑器的SerializedProperty息息相关)
在YAML的最下面有一个数据是Prefab数据
看起来很复杂,可是实际上,它就保存了最重要的几个数据
因此上面的数据就是GUID为161b04a3180d83a4080b19801daaf356的Prefab,修改后的FileID为4040867914032966的一堆数据和FileID为1205630099335284的Name数据。
经过打开咱们制做的Cube的Prefab文件及其meta文件,咱们能够看到,meta文件中的GUID就是那个,而Prefab中存在4040867914032966(Transform)和1205630099335284(GameObject)
OK,至此,序列化文件的数据和引用的原理都已完毕
我的博客请访问:http://www.cnblogs.com/CodeGize/