代码生成器插件与Creator预制体文件解析
前言
-
之前写过一篇自动生成脚本的工具,但是我给它起名叫半自动代码生成器。之所以称之为半自动,因为我觉得全自动代码生成器应该做到两点:代码生成+自动绑定。之前的工具只做了代码生成,并没有做自动绑定,所以鄙人又花时间研究了CocosCreator的预制体文件,实现了自动绑定的能力,并且支持了插件使用方式。
-
本篇内容,不仅仅是宣传自己的插件工具,还会帮助大家分析一下Creator的预制体文件格式,使购买插件的同学可以将插件价值最大化,也能让读者对Creator的预制体文件有所了解。
Creator 预制体文件格式分析
- 首先我们展示一小段预制体文件。
[
{
"__type__": "cc.Prefab",
"_name": "",
"_objFlags": 0,
"_native": "",
"data": {
"__id__": 1
},
"optimizationPolicy": 0,
"asyncLoadAssets": false,
"readonly": false
},
{
"__type__": "cc.Node",
"_name": "LoginView",
"_objFlags": 0,
"_parent": null,
"_children": [
{
"__id__": 2
},
{
"__id__": 6
},
{
"__id__": 18
},
{
"__id__": 21
},
{
"__id__": 33
},
{
"__id__": 42
},
{
"__id__": 63
},
{
"__id__": 84
}
],
"_active": true,
"_components": [
{
"__id__": 105
},
{
"__id__": 106
}
],
"_prefab": {
"__id__": 107
},
"_opacity": 255,
"_color": {
"__type__": "cc.Color",
"r": 255,
"g": 255,
"b": 255,
"a": 255
},
"_contentSize": {
"__type__": "cc.Size",
"width": 960,
"height": 640
},
"_anchorPoint": {
"__type__": "cc.Vec2",
"x": 0.5,
"y": 0.5
},
"_trs": {
"__type__": "TypedArray",
"ctor": "Float64Array",
"array": [
480,
320,
0,
0,
0,
0,
1,
1,
1,
1
]
},
"_eulerAngles": {
"__type__": "cc.Vec3",
"x": 0,
"y": 0,
"z": 0
},
"_skewX": 0,
"_skewY": 0,
"_is3DNode": false,
"_groupIndex": 0,
"groupIndex": 0,
"_id": ""
}
]
-
当你第一次看到这个文件的时候可能会有所疑惑,此文件是一个一维数组的json对象。
数组第一个位置是预制体文件的描述可以忽略。第二个位置的对象就是这个文件根节点对应的属性了。也是最重要的部分。从数据的_children 和_components字段可以看出,引擎是根据__id__这个字段来寻找其他数据的。只不过这个__id__并非你所理解的id,而是数组的索引位置。并且配置中所有涉及到寻找其他数据都是用的这种__id__方式。包括给自己的脚本组件绑定节点。 -
由于我们是要导出和绑定其中的属性,所以我们只关注__type__,_name,_childern,_components这几个属性就可以了。
-
__type__: 是一个比较重要的属性,对于普通的组件,类型会是cc.Node,cc.Sprite,cc.Button之类的。对于脚本的类型比较特别,它并不是你定义的类名,而已一串经过处理的字符。但是它的特点就是长。所以我会用长度是否大于20来判断是否是脚本组件。
下方是我已经做好绑定脚本的配置内容。也说明如果你要给预制体添加脚本也就是给预制体的数组添加一个下面格式的配置而已。通过下方的配置也可以看出我给这个脚本绑定了start$VButton,login$VLabel,login$\VLabel,show$VRichText四个变量和testItem$ATestItemView一个数组。
{
"__type__": "3e347nRcdVAiYpq6icd+8+w",
"_name": "",
"_objFlags": 0,
"node": {
"__id__": 1
},
"_enabled": true,
"start$VButton": {
"__id__": 14
},
"login$VLabel": {
"__id__": 19
},
"back$VButton": {
"__id__": 29
},
"show$VRichText": {
"__id__": 40
},
//绑定的是一个数组,长度为3
"testItem$ATestItemView": [
{
"__id__": 61
},
{
"__id__": 82
},
{
"__id__": 103
}
],
"_id": ""
},
- _name: 它是所有节点的名称,注意,组件是没有名称的,所以我们处理文件的时候也是从根节点深度遍历所有的子节点,然后在遍历节点的时候出理它的组件。
因为Creator的节点都是有名称的,而且还有空格,支持重名,这些都是代码生成器所不允许的。所以如果你想导出一个属性就要用特定的字符标识。
比如工具现在使用的是$V标识输出的是一个变量。$A标识输出的是一个数组,当然数组还需要名称都相同。
var TAG = '$V'
var LIST = '$A'
当然这里边还有一个问题就是一个节点可能挂了很多组件,那我们要怎么出理呢?
首先是做一个筛选,只有给定的组件才可以输出
var NORMAL_COMP_LIST = ['cc.Label', 'cc.Sprite', 'cc.RichText', 'cc.Button', 'cc.ScrollView']
其次工具会将名称后边加上类型,以区别不同的组件的情况。
因此这也是一个可自定义和扩展的部分。
-
_children: 就是遍历的节点,我们不用关心这个配置文件的数组有多长,就从这些子节点深度遍历就可以了。
-
_components: 遍历每个节点的时候我们再遍历一次它的所有组件,然后做上边我们说的操作。这样一个文件走一遍之后我们的类需要的信息也就生成了。
问题讨论
-
既然脚本的类型是 "type": "3e347nRcdVAiYpq6icd+8+w",那么我们怎么找到对应的脚本文件的名称呢?
当你右键一个脚本文件,点击打开Library中的资源选项,会跳转到一个js文件中
这个文件有四个特点,一是它的文件名是你脚本的uuid.js。二是文件带有cc._RF.push(module,,三是带有类型"3e347nRcdVAiYpq6icd+8+w"。四是带有脚本名称。所以你只要查找文件中带有cc._RF.push(module,字段并且带有你传入的类型的文件并返回后处理一下就可以获得脚本名称了。当然也可以得到路径并做好import from 的设置。
这里可能有人会觉得,搜索整个imports路径是不是很慢,其实不是,即使再慢还能比手动绑定慢吗?所以这个速度可以无视。 -
怎么处理的creator自带的meta机制,我是将代码生成和自动绑定分成两个脚本。代码生成之后会刷新生成脚本的目录,然后再调用自动绑定的脚本。刷新预制体目录。
这里边一直强调的就是刷新指定的目录,而不是刷新整个assets或者整个Script。原因是我在使用的时候发现,刷新整个目录会造成编辑器卡死,体验很不好,所以当你不设置的脚本目录不存在就做导出时,creator显示的目录位置不是实际中硬盘中显示的位置,重启编辑器后才会正确,就是因为我刷新的目录是你指定的目录。如果指定的目录不存在,目录会创建,但是不会刷新。
刷新后的预制体文件可能会报错,可以无视,双击预制体文件重新查看就可以了。 -
如何做到绑定嵌套的预制体的节点?
首先在导出代码的时候一旦遇到有脚本的节点就返回。继续遍历其他子节点。这样你的脚本里就不会声明其他脚本要声明的内容。
然后在绑定的时候首先会找到应该做数据绑定的脚本,然后再深入遍历,当你发现你处理的这个节点上有脚本的时候就会用它身上脚本处理它的子节点。所以如果一个节点有多个脚本就只能绑定第一个脚本的数据。
功能介绍
-
根据预制体文件生成脚本
-
自定义输入目录和输出目录
-
自动绑定属性+数组
使用$V标识变量
使用$A标识数组
属性名称默认带有类型。
-
自动绑定button事件
-
可扩展导出属性类型
-
自动绑定其他预制体的属性,和button事件
-
自动导入使用到的其他脚本
手懒不想自己实现的可以关注公众号,进入微店购买。
欢迎扫码关注公众号《微笑游戏》,浏览更多内容。
欢迎扫码关注公众号《微笑游戏》,浏览更多内容。