咱们在编辑器中看到的资源,在构建以后会进行一些转化,本章将揭开Creator对资源进行的处理。html
首先咱们将Creator的开发和运行划分为如下几个场景:node
当咱们将资源放到编辑器中时,Creator会为每一个资源生成惟一的uuid以及meta文件,并在项目的library目录下生成对应的json文件来描述这个资源的信息,而uuid与资源的映射关系被放在library目录下的uuid-to-mtime.json文件中。因为资源的引用关系是靠uuid来维系的,因此咱们能够在Creator中随意地修改资源文件名、移动资源路径,而不用担忧资源的关联丢失问题。算法
咱们在编辑器中编辑的prefab、anim、场景等文件本质上是一个json文件,Cocos Creator 设计了一套json规则用于描述各类资源,prefab的json描述了prefab的结构以及每一个节点的属性,但部分属性会放到meta文件中,通常是针对该资源在编辑器中的设置。json
预览的时候使用的是library目录下的资源,不只仅是项目assets目录下的全部资源(包括未被引用到的资源),引擎提供的一些默认资源也能够在library目录下找到。预览的模板位于引擎安装目录下的resources/static/preview-templates,程序的启动脚本为boot.js。数组
项目构建以后,资源会从library目录下移动到构建输出的目录中,基本只会导出参与构建的场景和resources目录下的资源,及其引用到的资源。脚本资源会由多个js脚本合并为一个js,各类json文件也会按照特定的规则进行打包(所谓的packAssets)。async
图片的meta文件大概以下所示,除了ver和uuid以外,还有3个属性:编辑器
这里的subMetas描述了一个SpriteFrame信息,详情可参考Sprite组件工具
{ "ver": "2.0.0", "uuid": "a0576798-bdf4-4f06-972e-5557dee6ee1b", "type": "sprite", "wrapMode": "clamp", "filterMode": "bilinear", "subMetas": { "boss_b_hp1": { "ver": "1.0.3", "uuid": "5425ad9a-e2e0-4c6e-825b-c3ea43b09e4e", "rawTextureUuid": "a0576798-bdf4-4f06-972e-5557dee6ee1b", "trimType": "auto", "trimThreshold": 1, "rotated": false, "offsetX": 0, "offsetY": 0, "trimX": 0, "trimY": 0, "width": 78, "height": 78, "rawWidth": 78, "rawHeight": 78, "borderTop": 0, "borderBottom": 0, "borderLeft": 0, "borderRight": 0, "subMetas": {} } } }
这样的一个图片会在library/imports/xx目录下生成3个文件(若是将图片的type设置为raw则不会有SpriteFrame对应的json文件),分别是以图片uuid为文件名的json文件和png,以及SpriteFrame的uuid为文件名的json文件。性能
Texture对应的json文件内容以下,每个纹理都会生成一个这样的重复的文件:字体
{ "__type__": "cc.Texture2D", "content": "0" }
SpriteFrame对应的json文件内容以下:
{ "__type__": "cc.SpriteFrame", "content": { "name": "boss_b_hp1", "texture": "a0576798-bdf4-4f06-972e-5557dee6ee1b", "atlas": "", "rect": [ 0, 0, 78, 78 ], "offset": [ 0, 0 ], "originalSize": [ 78, 78 ] } }
在构建以后,资源会被导出到res目录下,json文件放在import目录下,png等资源文件放在raw-assets目录。
图集分为plist和图片两个文件,图集图片的meta和普通图片的meta同样,而plist文件的meta记录了图集中全部碎图的信息。主要有ver、uuid、rawTextureUuid、size、type以及subMetas等属性,subMetas记录了每个碎图的meta信息,结构和普通图片的meta同样。
{ "ver": "1.2.4", "uuid": "315d61c8-b6c8-4635-b517-f868dd8b3495", "rawTextureUuid": "01979186-b9a2-4130-a307-a2eacb5fe30f", "size": { "width": 1024, "height": 1024 }, "type": "Texture Packer", "subMetas": { "role1001-move1.png": { "ver": "1.0.3", "uuid": "8e225dbc-7905-416f-a7ac-0730893ad30d", "rawTextureUuid": "01979186-b9a2-4130-a307-a2eacb5fe30f", "trimType": "auto", "trimThreshold": 1, "rotated": false, "offsetX": 0, "offsetY": -52, ...
在library目录下会生成plist的json文件,type为cc.SpriteAtlas,记录了图集中全部spriteFrames的uuid,每个碎图都会有一个描述其SpriteFrame的json文件生成。最后,图片文件照常会有一个Texture和SpriteFrame的json生成。
{ "__type__": "cc.SpriteAtlas", "_name": "role1001.plist", "_objFlags": 0, "_native": "", "_spriteFrames": { "role1001-move1": { "__uuid__": "8e225dbc-7905-416f-a7ac-0730893ad30d" }, "role1001-move2": { "__uuid__": "7e0641ef-5974-4c2d-bad3-80c59a3195d8" }, ...
构建以后,cc.SpriteAtlas与全部的cc.SpriteFrame会合为一个json,而图片自己仍然会导出cc.Texture和cc.SpriteFrame的json。
【合并初始场景依赖的全部json】会让全部用到的json都合并成一个。【内联全部SpriteFrame】会将全部用到的SpriteFrame的json信息复制到引用它们的场景或prefab的json中,若是是单独的一个SpriteFrame,会被直接合并。(这种状况下,其余场景加载该资源时如何处理?即该资源已经被打包到其余场景或prefab中。多个prefab同时引用时谁能打包到该资源呢?加载一个打包资源中的一个json,是否会直接加载该json包中的全部json)
AutoAtlas能够自动将当前目录以及子目录下全部的图片进行合图,他的meta文件描述了合图的规则,如最大尺寸、是否容许旋转、是否强制图片转为正方形、尺寸是否为2的幂、使用的合图算法等等...
{ "ver": "1.1.0", "uuid": "691bdbcd-78c9-41da-864f-481d1af5c8ff", "maxWidth": 1024, "maxHeight": 1024, "padding": 2, "allowRotation": true, "forceSquared": false, "powerOfTwo": true, "heuristices": "BestAreaFit", "format": "png", "quality": 80, "contourBleed": false, "paddingBleed": false, "filterUnused": false, "subMetas": {} }
而在library目录下,AutoAtlas只会生成一个简单的json文件,在预览的时候,AutoAtlas不会发生任何做用。
{ "__type__": "cc.SpriteAtlas", "_name": "AutoAtlas" }
构建以后,会生成cc.SpriteAtlas类型的一个json文件,记录全部碎图的uuid。AutoAtlas所在目录下的碎图会合成一张,而它们的SpriteFrame信息则不会像plist图集同样合并到图集的json文件中,而是每一个SpriteFrame一个json文件。
{ "__type__": "cc.SpriteAtlas", "_spriteFrames": { "building_01": { "__uuid__": "d47RnkKqBHw6xXpAKXUDWt" }, "building_02": { "__uuid__": "a8CDt9ghBA5LzcZdD79OcY" }, "building_03": { "__uuid__": "f4JnL6lkFFjZC9QkBYLbZM" }, "building_04": { "__uuid__": "0cwdvX5/pBXYpf4xhZG+I+" }, "building_05": { "__uuid__": "64GzrRUetDzreLftZ9Unt5" } } }
场景和prefab相似,都是用一个json文件来描述节点树。json文件首先描述一个数组,数组的第一个元素(下标0)描述的是该资源的类型以及该资源特定的属性,接下来是一个一个的节点、组件对象,每一个对象都描述了自身的各类属性,以及它们和其它对象的关系,其中的__id__字段对应的值表示当前json数组的下标。
[ // 数组的第一个元素,资源概述 { "__type__": "cc.prefab", // 类型,场景的__type__为cc.SceneAsset "_name": "", "_objFlags": 0, "_native": "", "data": { // 数据(该prefab的根节点id),场景为scene字段 "__id__": 1 }, "optimizationPolicy": 0, // 建立优化策略(场景无该选项) "asyncLoadAssets": false // 是否开启延迟加载资源(场景无该选项) }, // 数组的第二个元素,prefab的根节点,其name为Base,有2个子节点,id为2和5 { "__type__": "cc.Node", "_name": "Base", "_objFlags": 0, "_parent": null, "_children": [ { "__id__": 2 }, { "__id__": 5 } ], "_tag": -1, "_active": true, "_components": [], "_prefab": { "__id__": 8 }, "_id": "", "_opacity": 255, "_color": { "__type__": "cc.Color", "r": 255, "g": 255, "b": 255, "a": 255 }, "_cascadeOpacityEnabled": true, "_anchorPoint": { "__type__": "cc.Vec2", "x": 0.5, "y": 0.5 }, "_contentSize": { "__type__": "cc.Size", "width": 0, "height": 0 }, "_rotationX": 0, "_rotationY": 0, "_scaleX": 1, "_scaleY": 1, "_position": { "__type__": "cc.Vec2", "x": 0, "y": 0 }, "_skewX": 0, "_skewY": 0, "_localZOrder": 0, "_globalZOrder": 0, "_opacityModifyRGB": false, "groupIndex": 0 }, { ... }, // Sprite组件的数据,它挂载在本数组中下标为2的Node上(第三个元素) { "__type__": "cc.Sprite", "_name": "", "_objFlags": 0, "node": { "__id__": 2 }, "_enabled": true, "_spriteFrame": { // 全部的__uuid__都指向了一个新的资源 "__uuid__": "d4ed19e4-2aa0-47c3-ac57-a402975035ad" }, "_type": 0, "_sizeMode": 1, "_fillType": 0, "_fillCenter": { "__type__": "cc.Vec2", "x": 0, "y": 0 }, "_fillStart": 0, "_fillRange": 0, "_isTrimmedMode": true, "_srcBlendFactor": 770, "_dstBlendFactor": 771, "_atlas": null }, { "__type__": "cc.prefabInfo", "root": { "__id__": 1 }, "asset": { "__id__": 0 }, "fileId": "acUWY0/UZLeZdVqtcRkZuq", "sync": false }, ... ]
// 组件的__type__为脚本的23位uuid "_components": [ { "__type__": "b8386waIgRGVJwXT7yno4pm", "node": { "__id__": 1 }, // myRootNode和mySpriteFrame为脚本中的2个变量,在属性检查器中拖拽的 "myRootNode": { // myRootNode记录着当前prefab中id为2的节点 "__id__": 2 }, "mySpriteFrame": { // mySpriteFrame记录着一个外部的SpriteFrame的uuid "__uuid__": "40t3EpX7tCnq5b2lM2bG8F" }, } ],
Scene和prefab对应的meta文件比较简单,prefab包含了建立优化策略选项,Scene包含了是否自动释放资源选项,他们都包含了是否延迟加载资源的选项。大体以下所示:
// prefab的meta文件内容 { "ver": "1.0.0", "uuid": "c7d921c2-6021-4613-93bd-6201de418e24", "optimizationPolicy": "AUTO", "asyncLoadAssets": false, "subMetas": {} } // scene文件的meta文件内容 { "ver": "1.0.0", "uuid": "2afc2a6e-f61e-4f46-8a52-af34d838a4b0", "asyncLoadAssets": false, "autoReleaseAssets": false, "subMetas": {} }
在library目录下,以及构建目录中,prefab和scene基本是json文件自己内容的一个复制。可能会根据prefab和scene的选项稍微修改json数组首元素的内容(好比添加asyncLoadAssets字段)。
Creator动画保存在anim文件中,每个anim都是一个动画Clip。咱们能够在Creator中的资源管理器右键/新建/Animation Clip来建立新的anim动画文件。要使用动画咱们须要为一个节点挂载Animation组件,而后将anim文件拖拽到Animation组件的clips属性中。关于Creator动画的更多详情能够参考官方文档 https://docs.cocos.com/creator/manual/zh/animation/ 。
anim文件本质是一个json文件,它的内容大体以下,除了Creator标准的json字段,以及Clip的全局属性(wrapMode、speed等)外,curveData字段记录全部的动画信息,events字段记录了该动画中全部的帧事件。它的meta文件只记录了ver、uuid以及一个空的subMetas。
{ "__type__": "cc.AnimationClip", "_name": "1", "_objFlags": 0, "_native": "", "_duration": 0.25, "sample": 60, "speed": 1, "wrapMode": 1, "curveData": { "paths": { "build_b_2": { "props": { "position": [ { "frame": 0, "value": [ 39, 29 ] }, { "frame": 0.25, "value": [ 109, 29 ] } ] } } } }, "events": [ { "frame": 0.25, "func": "", "params": [] } ] }
该文件会被直接拷贝到library目录下,构建以后会直接导出该文件。
声音音效资源的meta文件很是简单,目前惟一的一个自定义属性就是downloadMode,即声音的加载模式,有Web Audio和DOM Audio两种。前者兼容性更好,但会占用更多的内存,故建议短音效用Web Audio,长音乐使用DOM Audio。
{ "ver": "2.0.0", "uuid": "ab548e86-4fca-4320-a8a0-0c1a714d1443", "downloadMode": 0, "subMetas": {} }
在library目录下,Creator会为每一个声音资源生成一个以uuid为命名的json文件,以及将声音文件以uuid命名。json文件的内容以下:
{ "__type__": "cc.AudioClip", "_name": "music_logo", "_objFlags": 0, "_native": ".mp3", "loadMode": 0 }
构建以后library目录下的json和声音文件会被复制到构建目录下的import和raw-assets目录中。
每一个Spine都是由json(Creator暂时不支持skel格式)、atlas、png三个文件组成,它们的meta文件很是简单,没有什么特殊的信息。
在library目录下,png会生成对应的SpriteFrame和Texture的json,以及图片自身。atlas会生成一个简单的json文件,以下所示。骨骼json会进行转换,变成Creator标准的资源格式json,以uuid命名,在当前目录下会建立一个以uuid命名的目录,放着转换前的Spine json文件,名为raw-skeleton.json。(Creator格式的json比原Spine的json要大很多)
{ "__type__": "cc.Asset", "_name": "raptor", "_native": ".atlas" }
构建以后,png对应的SpriteFrame、Texture的json,以及Atlas的json。Spine自己的json会转换成Creator标准的资源格式json输出到构建目录下,并且raw-skeleton.json并不在构建目录中。
在Creator中支持TS和JS脚本,这里不讨论如何编写脚本。脚本的meta文件中有几个有意思的属性,与Plugin相关,意为是否将该脚本做为插件导入。对第三方插件或者底层插件,有可能须要选中Plugin选项,这样的脚本简称插件脚本(未勾选该选项的为普通脚本)。脚本插件在打包时是不会参与构建的。
关于该选项的详细介绍能够查看 https://docs.cocos.com/creator/manual/zh/scripting/plugin-scripts.html 。
{ "ver": "1.0.5", "uuid": "8c87839a-4fd0-4b9e-9363-23bbf1bd16ef", "isPlugin": false, "loadPluginInWeb": true, "loadPluginInNative": true, "loadPluginInEditor": false, "subMetas": {} }
在library目录下,TS会被编译成JS脚本,全部的JS脚本都会以其uuid命名存储。与JS文件一块儿生成的还有map文件(这里放着编译前的原文件内容和路径等相关信息)。
构建以后全部的TS和JS脚本会被编译成JS,打包到一个project.dev.js文件中。构建通常会生成4个js,记录全部资源相关设置的settings.js,启动脚本main.js,开发者的代码project.dev.js以及cocos引擎cocos2d-js.js。若是开启了调试模式,构建出来的js会被精简为一行,剔除全部的注释和空行换行,并自动将一些变量名进行混淆,使用更简短的命名,而不影响代码执行的效果。若是开启了Source Maps,构建代码时会生成map文件,不然不会生成。
咱们能够在Creator编辑器中的项目菜单/项目设置/模块设置下选择剔除咱们不须要用到的模块,从而精简cocos2d-js.js文件的大小(新一代的js打包工具如rollup.js已经能够支持到在打包的时候自动根据引用到的代码去剔除无用代码)。
CocosCreator的字体能够分为3类,系统字、BMFont以及TTF字体。系统字不须要额外的字体资源,而是使用内置的系统字体。BMFont的资源是一张图片以及一个fnt。而TTF字体的资源是一个TTF文件。
fnt资源的meta文件以下所示,指定了fontSize,以及使用的纹理。
{ "ver": "2.1.0", "uuid": "e2fd9257-452a-4ae2-a932-e567c5fd6e91", "textureUuid": "1afd96d7-225c-484b-ab27-fe12902096d6", "fontSize": 32, "subMetas": {} }
在library目录下,除了图片相关的Texture、SpriteFrame等json。fnt文件会被转成一个cc.BitmapFont的json文件,文件内容以下所示,_fntConfig描述了fnt字体的字号、宽高、图集以及每个字在图集中的坐标尺寸等信息。
{ "__type__": "cc.BitmapFont", "_name": "b0", "_objFlags": 0, "_native": "", "fntDataStr": "", "spriteFrame": { "__uuid__": "a3e89811-562f-4a58-943f-895c807f087b" }, "fontSize": 32, "_fntConfig": { "commonHeight": 32, "fontSize": 32, "atlasName": "b0_0.png", "fontDefDictionary": { "36": { "rect": { "x": 81, "y": 0, "width": 79, "height": 111 }, "xOffset": 0, "yOffset": 0, "xAdvance": 79 }, ...
构建以后,cc.BitmapFont和SpriteFrame这2个json会被合并(咱们每每须要同时使用到它们)。
TTF的meta文件只有ver、uuid和空的subMetas字段。在library目录下会生成一个以TTF资源的uuid命名的json文件,在相同目录下有一个以TTF资源的uuid目录,目录下放着ttf资源。
{ "__type__": "cc.TTFFont", "_name": "BlackHanSans-Regular", "_objFlags": 0, "_native": "BlackHanSans-Regular.ttf" }
构建后该json文件会剔除_objFlags字段后导出,而TTF文件会导出到raw-assets目录下。
粒子资源大体能够分为plist和prefab两种:
{ "__type__": "cc.ParticleAsset", "_name": "p_star_fly", "_objFlags": 0, "_native": ".plist", "texture": { "__uuid__": "1544eed3-42e4-46fc-a392-0c4d8b1b9847" } }
在了解了Creator对单个资源的处理以后,咱们要对Creator资源打包规则作更深刻的分析。对于资源打包,咱们主要关注的2点是IO和包体,json的合并能够减小IO操做,在某些状况下也可能增大包体。
在Creator构建后每个图片都会生成一个描述cc.Texture2D的json以及一个cc.SpriteFrame的json,而其中全部的cc.Texture2D.json都会被合并成一个,应该说一个项目在构建以后,正常来讲最多只会有一个cc.Texture2D的json,只是它的data字段会很长。不论图片是来自不一样目录的图片、图集、自动图集、Spine、粒子系统或者BMFont等等,都不影响它们的cc.Texture2D.json被合并。
{ "type": "cc.Texture2D", "data": "0|0|0|0|0|0|0|0|0|0|0|0" }
图片对应的SpriteFrame又会被怎样合并呢?默认的状况下(即不考虑依赖和构建选项的状况)只有plist图集和BMFont字体这两种资源的SpriteFrame会有合并的操做。plist的json会与图集中全部的SpriteFrame的json合并为一个json。BMFont字体的fnt对应的json会与SpriteFrame合并为一个json。
接下来咱们来看一下资源依赖的状况,使用prefab去引用各类类型的资源,json又会如何合并呢?prefab引用的全部资源中,只有单个图片和自动图集中的SpriteFrame会被合并到prefab的json中。
若是咱们在构建时勾选了“内联全部SpriteFrame”,json又会如何合并呢?除了单个图片和自动图集,prefab中用到的图集的SpriteFrame也会被合并进来,但图集的合并是拷贝,也就是说原来的图集和图集中全部SpriteFrame合并的那个json仍然存在。
若是咱们的资源同时被多个prefab引用,在这种状况下,是否勾选“内联全部SpriteFrame”又会有怎样的区别呢?
前面介绍了prefab的依赖对构建打包的影响,在Creator中,除了prefab能够去引用资源外,场景也能够引用外部资源,但正常状况下场景不会去将其引用的SpriteFrame打包进来。在勾选了“内联全部SpriteFrame”的状况下,场景的json才会去合并引用到的SpriteFrame。
在勾选了“合并初始场景依赖的全部JSON”后,初始场景引用到的全部json都会被合并到初始场景的json文件中,这种合并非拷贝,而是将场景引用到的全部资源的json文件合并到一块儿(除了SpriteFrame外,还有粒子json、plist图集完整json、Spine骨骼json、BMFont字体json、动画json等等)。若是没有勾选“内联全部SpriteFrame”,这些json只会放在启动场景的json中,不会影响包体。值得一提的是图片的cc.Texture2D这个json,全部被初始场景引用到的纹理会从这个json中剥离,并合并到初始场景。