cocos2d-cli 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cocos-cli.js +38 -26
- package/package.json +1 -1
- package/src/commands/create-scene.js +381 -351
- package/src/commands/prefab-create.js +437 -25
- package/src/commands/set.js +19 -0
- package/src/commands/tree.js +2 -2
- package/src/lib/fire-utils.js +3 -3
|
@@ -1,21 +1,30 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* create-scene 命令 -
|
|
2
|
+
* create-scene 命令 - 从 JSON 结构创建场景文件
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
4
|
+
* JSON 格式示例:
|
|
5
|
+
* {
|
|
6
|
+
* "name": "Panel",
|
|
7
|
+
* "width": 400,
|
|
8
|
+
* "height": 300,
|
|
9
|
+
* "color": "#ffffff",
|
|
10
|
+
* "components": [
|
|
11
|
+
* { "type": "sprite", "sizeMode": 1 },
|
|
12
|
+
* { "type": "widget", "top": 0, "bottom": 0 }
|
|
13
|
+
* ],
|
|
14
|
+
* "children": [...]
|
|
15
|
+
* }
|
|
16
|
+
*
|
|
17
|
+
* 节点属性:name, width, height, x, y, color, opacity, anchorX, anchorY, rotation, scaleX, scaleY, active
|
|
18
|
+
* 组件属性:type + 各组件特有属性
|
|
19
|
+
*
|
|
20
|
+
* 场景会自动包含 Canvas 和 Main Camera 节点
|
|
12
21
|
*/
|
|
13
22
|
|
|
14
23
|
const fs = require('fs');
|
|
15
24
|
const path = require('path');
|
|
16
|
-
const { Components, generateId
|
|
25
|
+
const { Components, generateId } = require('../lib/components');
|
|
17
26
|
|
|
18
|
-
//
|
|
27
|
+
// 支持的组件类型
|
|
19
28
|
const COMPONENT_TYPES = {
|
|
20
29
|
'sprite': 'sprite',
|
|
21
30
|
'label': 'label',
|
|
@@ -29,136 +38,32 @@ const COMPONENT_TYPES = {
|
|
|
29
38
|
};
|
|
30
39
|
|
|
31
40
|
/**
|
|
32
|
-
*
|
|
33
|
-
* 支持格式:
|
|
34
|
-
* - 节点名称
|
|
35
|
-
* - 节点名称 (组件1, 组件2)
|
|
36
|
-
* - 节点名称 #width=100 #height=50 #x=10 #y=20
|
|
37
|
-
*
|
|
38
|
-
* 树形符号支持:
|
|
39
|
-
* ├─ └─ │ 以及 Windows 下可能出现的 ? 乱码形式
|
|
41
|
+
* 解析颜色字符串 #RRGGBB 或 #RRGGBBAA
|
|
40
42
|
*/
|
|
41
|
-
function
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
// 模式2: Windows 乱码 ??
|
|
59
|
-
const branchPattern = /([├└]─|├|└|\?\?|\?)\s*/g;
|
|
60
|
-
const branches = [];
|
|
61
|
-
let match;
|
|
62
|
-
let lastBranchEnd = 0;
|
|
63
|
-
|
|
64
|
-
while ((match = branchPattern.exec(line)) !== null) {
|
|
65
|
-
branches.push(match[1]);
|
|
66
|
-
lastBranchEnd = match.index + match[0].length;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (branches.length > 0) {
|
|
70
|
-
// 找到了分支符号,深度 = 分支数量
|
|
71
|
-
depth = branches.length;
|
|
72
|
-
contentStart = lastBranchEnd;
|
|
73
|
-
} else {
|
|
74
|
-
// 没有分支符号,检查缩进
|
|
75
|
-
for (let i = 0; i < line.length; i++) {
|
|
76
|
-
const char = line[i];
|
|
77
|
-
if (char !== ' ' && char !== '\t') {
|
|
78
|
-
contentStart = i;
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
depth = Math.floor(contentStart / 4);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// 提取节点内容
|
|
86
|
-
let content = line.substring(contentStart).trim();
|
|
87
|
-
|
|
88
|
-
// 清理可能残留的符号(- 和空格)
|
|
89
|
-
content = content.replace(/^[\-\s]+/, '').trim();
|
|
90
|
-
|
|
91
|
-
if (!content) continue;
|
|
92
|
-
|
|
93
|
-
// 解析节点信息
|
|
94
|
-
const nodeInfo = parseNodeLine(content);
|
|
95
|
-
|
|
96
|
-
// 构建树结构
|
|
97
|
-
while (stack.length > depth) {
|
|
98
|
-
stack.pop();
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const node = {
|
|
102
|
-
name: nodeInfo.name,
|
|
103
|
-
components: nodeInfo.components,
|
|
104
|
-
options: nodeInfo.options,
|
|
105
|
-
children: []
|
|
43
|
+
function parseColor(colorStr) {
|
|
44
|
+
if (!colorStr || typeof colorStr !== 'string') return null;
|
|
45
|
+
|
|
46
|
+
let hex = colorStr.replace('#', '');
|
|
47
|
+
if (hex.length === 6) {
|
|
48
|
+
return {
|
|
49
|
+
r: parseInt(hex.substring(0, 2), 16),
|
|
50
|
+
g: parseInt(hex.substring(2, 4), 16),
|
|
51
|
+
b: parseInt(hex.substring(4, 6), 16),
|
|
52
|
+
a: 255
|
|
53
|
+
};
|
|
54
|
+
} else if (hex.length === 8) {
|
|
55
|
+
return {
|
|
56
|
+
r: parseInt(hex.substring(0, 2), 16),
|
|
57
|
+
g: parseInt(hex.substring(2, 4), 16),
|
|
58
|
+
b: parseInt(hex.substring(4, 6), 16),
|
|
59
|
+
a: parseInt(hex.substring(6, 8), 16)
|
|
106
60
|
};
|
|
107
|
-
|
|
108
|
-
if (stack.length === 0) {
|
|
109
|
-
rootNodes.push(node);
|
|
110
|
-
} else {
|
|
111
|
-
stack[stack.length - 1].node.children.push(node);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
stack.push({ depth, node });
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return rootNodes;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* 解析单行节点定义
|
|
122
|
-
* 格式:NodeName (comp1, comp2) #key=value
|
|
123
|
-
*/
|
|
124
|
-
function parseNodeLine(line) {
|
|
125
|
-
let name = line;
|
|
126
|
-
let components = [];
|
|
127
|
-
let options = {};
|
|
128
|
-
|
|
129
|
-
// 提取组件 (xxx)
|
|
130
|
-
const compMatch = line.match(/\(([^)]+)\)/);
|
|
131
|
-
if (compMatch) {
|
|
132
|
-
name = name.replace(compMatch[0], '').trim();
|
|
133
|
-
const compList = compMatch[1].split(',').map(c => c.trim().toLowerCase());
|
|
134
|
-
for (const comp of compList) {
|
|
135
|
-
if (COMPONENT_TYPES[comp]) {
|
|
136
|
-
components.push(COMPONENT_TYPES[comp]);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// 提取选项 #key=value
|
|
142
|
-
const optionMatches = name.matchAll(/#(\w+)=([^\s#]+)/g);
|
|
143
|
-
for (const match of optionMatches) {
|
|
144
|
-
const key = match[1];
|
|
145
|
-
let value = match[2];
|
|
146
|
-
|
|
147
|
-
// 类型转换
|
|
148
|
-
if (/^\d+$/.test(value)) value = parseInt(value);
|
|
149
|
-
else if (/^\d+\.\d+$/.test(value)) value = parseFloat(value);
|
|
150
|
-
else if (value === 'true') value = true;
|
|
151
|
-
else if (value === 'false') value = false;
|
|
152
|
-
|
|
153
|
-
options[key] = value;
|
|
154
61
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
return { name, components, options };
|
|
62
|
+
return null;
|
|
158
63
|
}
|
|
159
64
|
|
|
160
65
|
/**
|
|
161
|
-
* 生成 UUID
|
|
66
|
+
* 生成 UUID
|
|
162
67
|
*/
|
|
163
68
|
function generateUUID() {
|
|
164
69
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
|
@@ -169,67 +74,343 @@ function generateUUID() {
|
|
|
169
74
|
}
|
|
170
75
|
|
|
171
76
|
/**
|
|
172
|
-
*
|
|
77
|
+
* 解析组件定义
|
|
173
78
|
*/
|
|
174
|
-
function
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
79
|
+
function parseComponent(compDef) {
|
|
80
|
+
if (typeof compDef === 'string') {
|
|
81
|
+
const type = COMPONENT_TYPES[compDef.toLowerCase()];
|
|
82
|
+
return type ? { type, props: {} } : null;
|
|
83
|
+
}
|
|
178
84
|
|
|
179
|
-
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
85
|
+
if (typeof compDef === 'object' && compDef.type) {
|
|
86
|
+
const type = COMPONENT_TYPES[compDef.type.toLowerCase()];
|
|
87
|
+
if (!type) return null;
|
|
88
|
+
|
|
89
|
+
const props = { ...compDef };
|
|
90
|
+
delete props.type;
|
|
91
|
+
return { type, props };
|
|
185
92
|
}
|
|
93
|
+
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
186
96
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
97
|
+
/**
|
|
98
|
+
* 应用组件属性
|
|
99
|
+
*/
|
|
100
|
+
function applyComponentProps(comp, props) {
|
|
101
|
+
if (!props || !comp) return;
|
|
102
|
+
|
|
103
|
+
const type = comp.__type__;
|
|
104
|
+
|
|
105
|
+
// Widget 特殊处理:根据设置的方向计算 alignFlags
|
|
106
|
+
if (type === 'cc.Widget') {
|
|
107
|
+
const ALIGN = {
|
|
108
|
+
top: 1,
|
|
109
|
+
verticalCenter: 2,
|
|
110
|
+
bottom: 4,
|
|
111
|
+
left: 8,
|
|
112
|
+
horizontalCenter: 16,
|
|
113
|
+
right: 32
|
|
114
|
+
};
|
|
115
|
+
let alignFlags = 0;
|
|
116
|
+
|
|
117
|
+
for (const dir of ['top', 'bottom', 'left', 'right', 'horizontalCenter', 'verticalCenter']) {
|
|
118
|
+
if (props[dir] !== undefined && props[dir] !== null) {
|
|
119
|
+
alignFlags |= ALIGN[dir];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (alignFlags > 0) {
|
|
124
|
+
comp._alignFlags = alignFlags;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 通用属性映射
|
|
129
|
+
const propMap = {
|
|
130
|
+
'sizeMode': '_sizeMode',
|
|
131
|
+
'fillType': '_fillType',
|
|
132
|
+
'fillCenter': '_fillCenter',
|
|
133
|
+
'fillStart': '_fillStart',
|
|
134
|
+
'fillRange': '_fillRange',
|
|
135
|
+
'trim': '_isTrimmedMode',
|
|
136
|
+
'string': '_string',
|
|
137
|
+
'fontSize': '_fontSize',
|
|
138
|
+
'lineHeight': '_lineHeight',
|
|
139
|
+
'horizontalAlign': '_N$horizontalAlign',
|
|
140
|
+
'verticalAlign': '_N$verticalAlign',
|
|
141
|
+
'overflow': '_N$overflow',
|
|
142
|
+
'fontFamily': '_N$fontFamily',
|
|
143
|
+
'wrap': '_enableWrapText',
|
|
144
|
+
'alignFlags': '_alignFlags',
|
|
145
|
+
'left': '_left',
|
|
146
|
+
'right': '_right',
|
|
147
|
+
'top': '_top',
|
|
148
|
+
'bottom': '_bottom',
|
|
149
|
+
'horizontalCenter': '_horizontalCenter',
|
|
150
|
+
'verticalCenter': '_verticalCenter',
|
|
151
|
+
'isAbsLeft': '_isAbsLeft',
|
|
152
|
+
'isAbsRight': '_isAbsRight',
|
|
153
|
+
'isAbsTop': '_isAbsTop',
|
|
154
|
+
'isAbsBottom': '_isAbsBottom',
|
|
155
|
+
'interactable': '_N$interactable',
|
|
156
|
+
'transition': '_N$transition',
|
|
157
|
+
'zoomScale': 'zoomScale',
|
|
158
|
+
'duration': 'duration',
|
|
159
|
+
'layoutType': '_N$layoutType',
|
|
160
|
+
'cellSize': '_N$cellSize',
|
|
161
|
+
'startAxis': '_N$startAxis',
|
|
162
|
+
'paddingLeft': '_N$paddingLeft',
|
|
163
|
+
'paddingRight': '_N$paddingRight',
|
|
164
|
+
'paddingTop': '_N$paddingTop',
|
|
165
|
+
'paddingBottom': '_N$paddingBottom',
|
|
166
|
+
'spacingX': '_N$spacingX',
|
|
167
|
+
'spacingY': '_N$spacingY',
|
|
168
|
+
'resize': '_resize',
|
|
169
|
+
'designResolution': '_designResolution',
|
|
170
|
+
'fitWidth': '_fitWidth',
|
|
171
|
+
'fitHeight': '_fitHeight',
|
|
172
|
+
'orthoSize': '_orthoSize',
|
|
173
|
+
'backgroundColor': '_backgroundColor',
|
|
174
|
+
'cullingMask': '_cullingMask',
|
|
175
|
+
'zoomRatio': '_zoomRatio'
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
if (type === 'cc.Label' && props.string !== undefined) {
|
|
179
|
+
comp._N$string = props.string;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
for (const [key, value] of Object.entries(props)) {
|
|
183
|
+
const compKey = propMap[key];
|
|
184
|
+
if (compKey) {
|
|
185
|
+
if (key === 'fillCenter' && Array.isArray(value)) {
|
|
186
|
+
comp[compKey] = { "__type__": "cc.Vec2", "x": value[0], "y": value[1] };
|
|
187
|
+
} else if (key === 'cellSize' && Array.isArray(value)) {
|
|
188
|
+
comp[compKey] = { "__type__": "cc.Size", "width": value[0], "height": value[1] };
|
|
189
|
+
} else if (key === 'designResolution' && Array.isArray(value)) {
|
|
190
|
+
comp[compKey] = { "__type__": "cc.Size", "width": value[0], "height": value[1] };
|
|
191
|
+
} else if ((key === 'backgroundColor' || key === 'color') && typeof value === 'string') {
|
|
192
|
+
const color = parseColor(value);
|
|
193
|
+
if (color) {
|
|
194
|
+
comp[compKey] = { "__type__": "cc.Color", ...color };
|
|
195
|
+
}
|
|
196
|
+
} else {
|
|
197
|
+
comp[compKey] = value;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
190
202
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
203
|
+
/**
|
|
204
|
+
* 创建场景数据结构
|
|
205
|
+
*/
|
|
206
|
+
function createSceneData(nodeDefs, sceneName) {
|
|
207
|
+
const data = [];
|
|
208
|
+
|
|
209
|
+
// 场景 UUID
|
|
210
|
+
const sceneUUID = generateUUID();
|
|
211
|
+
const canvasUUID = generateUUID();
|
|
212
|
+
const cameraUUID = generateUUID();
|
|
213
|
+
|
|
214
|
+
// 索引 0: cc.SceneAsset
|
|
215
|
+
data.push({
|
|
216
|
+
"__type__": "cc.SceneAsset",
|
|
217
|
+
"_name": sceneName || "NewScene",
|
|
218
|
+
"_objFlags": 0,
|
|
219
|
+
"_native": "",
|
|
220
|
+
"scene": { "__id__": 1 }
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// 索引 1: cc.Scene
|
|
224
|
+
data.push({
|
|
225
|
+
"__type__": "cc.Scene",
|
|
226
|
+
"_name": sceneName || "NewScene",
|
|
227
|
+
"_objFlags": 0,
|
|
228
|
+
"_parent": null,
|
|
229
|
+
"_children": [{ "__id__": 2 }],
|
|
230
|
+
"_active": true,
|
|
231
|
+
"_components": [],
|
|
232
|
+
"_prefab": null,
|
|
233
|
+
"_opacity": 255,
|
|
234
|
+
"_color": { "__type__": "cc.Color", "r": 255, "g": 255, "b": 255, "a": 255 },
|
|
235
|
+
"_contentSize": { "__type__": "cc.Size", "width": 0, "height": 0 },
|
|
236
|
+
"_anchorPoint": { "__type__": "cc.Vec2", "x": 0, "y": 0 },
|
|
237
|
+
"_trs": { "__type__": "TypedArray", "ctor": "Float64Array", "array": [0, 0, 0, 0, 0, 0, 1, 1, 1, 1] },
|
|
238
|
+
"_is3DNode": true,
|
|
239
|
+
"_groupIndex": 0,
|
|
240
|
+
"groupIndex": 0,
|
|
241
|
+
"autoReleaseAssets": false,
|
|
242
|
+
"_id": sceneUUID
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// 索引 2: Canvas 节点
|
|
246
|
+
data.push({
|
|
247
|
+
"__type__": "cc.Node",
|
|
248
|
+
"_name": "Canvas",
|
|
249
|
+
"_objFlags": 0,
|
|
250
|
+
"_parent": { "__id__": 1 },
|
|
251
|
+
"_children": [{ "__id__": 3 }], // Main Camera
|
|
252
|
+
"_active": true,
|
|
253
|
+
"_components": [{ "__id__": 5 }, { "__id__": 6 }], // Canvas, Widget
|
|
254
|
+
"_prefab": null,
|
|
255
|
+
"_opacity": 255,
|
|
256
|
+
"_color": { "__type__": "cc.Color", "r": 255, "g": 255, "b": 255, "a": 255 },
|
|
257
|
+
"_contentSize": { "__type__": "cc.Size", "width": 960, "height": 640 },
|
|
258
|
+
"_anchorPoint": { "__type__": "cc.Vec2", "x": 0.5, "y": 0.5 },
|
|
259
|
+
"_trs": { "__type__": "TypedArray", "ctor": "Float64Array", "array": [480, 320, 0, 0, 0, 0, 1, 1, 1, 1] },
|
|
260
|
+
"_eulerAngles": { "__type__": "cc.Vec3", "x": 0, "y": 0, "z": 0 },
|
|
261
|
+
"_skewX": 0,
|
|
262
|
+
"_skewY": 0,
|
|
263
|
+
"_is3DNode": false,
|
|
264
|
+
"_groupIndex": 0,
|
|
265
|
+
"groupIndex": 0,
|
|
266
|
+
"_id": canvasUUID
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// 索引 3: Main Camera 节点
|
|
270
|
+
data.push({
|
|
271
|
+
"__type__": "cc.Node",
|
|
272
|
+
"_name": "Main Camera",
|
|
273
|
+
"_objFlags": 0,
|
|
274
|
+
"_parent": { "__id__": 2 },
|
|
275
|
+
"_children": [],
|
|
276
|
+
"_active": true,
|
|
277
|
+
"_components": [{ "__id__": 4 }], // Camera
|
|
278
|
+
"_prefab": null,
|
|
279
|
+
"_opacity": 255,
|
|
280
|
+
"_color": { "__type__": "cc.Color", "r": 255, "g": 255, "b": 255, "a": 255 },
|
|
281
|
+
"_contentSize": { "__type__": "cc.Size", "width": 0, "height": 0 },
|
|
282
|
+
"_anchorPoint": { "__type__": "cc.Vec2", "x": 0.5, "y": 0.5 },
|
|
283
|
+
"_trs": { "__type__": "TypedArray", "ctor": "Float64Array", "array": [0, 0, 0, 0, 0, 0, 1, 1, 1, 1] },
|
|
284
|
+
"_eulerAngles": { "__type__": "cc.Vec3", "x": 0, "y": 0, "z": 0 },
|
|
285
|
+
"_skewX": 0,
|
|
286
|
+
"_skewY": 0,
|
|
287
|
+
"_is3DNode": false,
|
|
288
|
+
"_groupIndex": 0,
|
|
289
|
+
"groupIndex": 0,
|
|
290
|
+
"_id": cameraUUID
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
// 索引 4: Camera 组件
|
|
294
|
+
data.push({
|
|
295
|
+
"__type__": "cc.Camera",
|
|
296
|
+
"_name": "",
|
|
297
|
+
"_objFlags": 0,
|
|
298
|
+
"node": { "__id__": 3 },
|
|
299
|
+
"_enabled": true,
|
|
300
|
+
"_cullingMask": 4294967295,
|
|
301
|
+
"_clearFlags": 7,
|
|
302
|
+
"_backgroundColor": { "__type__": "cc.Color", "r": 0, "g": 0, "b": 0, "a": 255 },
|
|
303
|
+
"_depth": -1,
|
|
304
|
+
"_zoomRatio": 1,
|
|
305
|
+
"_targetTexture": null,
|
|
306
|
+
"_fov": 60,
|
|
307
|
+
"_orthoSize": 10,
|
|
308
|
+
"_nearClip": 1,
|
|
309
|
+
"_farClip": 4096,
|
|
310
|
+
"_ortho": true,
|
|
311
|
+
"_rect": { "__type__": "cc.Rect", "x": 0, "y": 0, "width": 1, "height": 1 },
|
|
312
|
+
"_renderStages": 1,
|
|
313
|
+
"_alignWithScreen": true,
|
|
314
|
+
"_id": generateId()
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
// 索引 5: Canvas 组件
|
|
318
|
+
data.push({
|
|
319
|
+
"__type__": "cc.Canvas",
|
|
320
|
+
"_name": "",
|
|
321
|
+
"_objFlags": 0,
|
|
322
|
+
"node": { "__id__": 2 },
|
|
323
|
+
"_enabled": true,
|
|
324
|
+
"_designResolution": { "__type__": "cc.Size", "width": 960, "height": 640 },
|
|
325
|
+
"_fitWidth": false,
|
|
326
|
+
"_fitHeight": true,
|
|
327
|
+
"_id": generateId()
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
// 索引 6: Widget 组件 (Canvas)
|
|
331
|
+
data.push({
|
|
332
|
+
"__type__": "cc.Widget",
|
|
333
|
+
"_name": "",
|
|
334
|
+
"_objFlags": 0,
|
|
335
|
+
"node": { "__id__": 2 },
|
|
336
|
+
"_enabled": true,
|
|
337
|
+
"alignMode": 1,
|
|
338
|
+
"_target": null,
|
|
339
|
+
"_alignFlags": 45,
|
|
340
|
+
"_left": 0,
|
|
341
|
+
"_right": 0,
|
|
342
|
+
"_top": 0,
|
|
343
|
+
"_bottom": 0,
|
|
344
|
+
"_verticalCenter": 0,
|
|
345
|
+
"_horizontalCenter": 0,
|
|
346
|
+
"_isAbsLeft": true,
|
|
347
|
+
"_isAbsRight": true,
|
|
348
|
+
"_isAbsTop": true,
|
|
349
|
+
"_isAbsBottom": true,
|
|
350
|
+
"_isAbsHorizontalCenter": true,
|
|
351
|
+
"_isAbsVerticalCenter": true,
|
|
352
|
+
"_originalWidth": 0,
|
|
353
|
+
"_originalHeight": 0,
|
|
354
|
+
"_id": generateId()
|
|
355
|
+
});
|
|
195
356
|
|
|
196
|
-
// Canvas
|
|
357
|
+
// Canvas 节点索引
|
|
197
358
|
const canvasIndex = 2;
|
|
198
|
-
const canvas = data[canvasIndex];
|
|
199
359
|
|
|
200
|
-
//
|
|
201
|
-
function addNode(
|
|
360
|
+
// 递归添加用户节点
|
|
361
|
+
function addNode(def, parentIndex) {
|
|
202
362
|
const nodeIndex = data.length;
|
|
203
363
|
const uuid = generateUUID();
|
|
204
364
|
|
|
365
|
+
// 解析组件
|
|
366
|
+
const compList = (def.components || [])
|
|
367
|
+
.map(parseComponent)
|
|
368
|
+
.filter(Boolean);
|
|
369
|
+
|
|
370
|
+
// 解析颜色
|
|
371
|
+
let color = { "__type__": "cc.Color", "r": 255, "g": 255, "b": 255, "a": 255 };
|
|
372
|
+
if (def.color) {
|
|
373
|
+
const parsed = parseColor(def.color);
|
|
374
|
+
if (parsed) {
|
|
375
|
+
color = { "__type__": "cc.Color", ...parsed };
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// 解析尺寸和位置
|
|
380
|
+
const width = def.width || 0;
|
|
381
|
+
const height = def.height || 0;
|
|
382
|
+
const anchorX = def.anchorX !== undefined ? def.anchorX : 0.5;
|
|
383
|
+
const anchorY = def.anchorY !== undefined ? def.anchorY : 0.5;
|
|
384
|
+
const rotation = def.rotation || 0;
|
|
385
|
+
const scaleX = def.scaleX !== undefined ? def.scaleX : 1;
|
|
386
|
+
const scaleY = def.scaleY !== undefined ? def.scaleY : 1;
|
|
387
|
+
|
|
205
388
|
// 创建节点
|
|
206
389
|
const node = {
|
|
207
390
|
"__type__": "cc.Node",
|
|
208
|
-
"_name":
|
|
391
|
+
"_name": def.name || 'Node',
|
|
209
392
|
"_objFlags": 0,
|
|
210
393
|
"_parent": { "__id__": parentIndex },
|
|
211
394
|
"_children": [],
|
|
212
|
-
"_active":
|
|
395
|
+
"_active": def.active !== false,
|
|
213
396
|
"_components": [],
|
|
214
397
|
"_prefab": null,
|
|
215
|
-
"_opacity": 255,
|
|
216
|
-
"_color":
|
|
217
|
-
"_contentSize": {
|
|
218
|
-
|
|
219
|
-
"width": nodeDef.options.width || 0,
|
|
220
|
-
"height": nodeDef.options.height || 0
|
|
221
|
-
},
|
|
222
|
-
"_anchorPoint": { "__type__": "cc.Vec2", "x": 0.5, "y": 0.5 },
|
|
398
|
+
"_opacity": def.opacity !== undefined ? def.opacity : 255,
|
|
399
|
+
"_color": color,
|
|
400
|
+
"_contentSize": { "__type__": "cc.Size", width, height },
|
|
401
|
+
"_anchorPoint": { "__type__": "cc.Vec2", "x": anchorX, "y": anchorY },
|
|
223
402
|
"_trs": {
|
|
224
403
|
"__type__": "TypedArray",
|
|
225
404
|
"ctor": "Float64Array",
|
|
226
405
|
"array": [
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
0, 0, 0,
|
|
406
|
+
def.x || 0,
|
|
407
|
+
def.y || 0,
|
|
408
|
+
0, 0, 0,
|
|
409
|
+
rotation * Math.PI / 180,
|
|
410
|
+
1, scaleX, scaleY, 1
|
|
230
411
|
]
|
|
231
412
|
},
|
|
232
|
-
"_eulerAngles": { "__type__": "cc.Vec3", "x": 0, "y": 0, "z":
|
|
413
|
+
"_eulerAngles": { "__type__": "cc.Vec3", "x": 0, "y": 0, "z": rotation },
|
|
233
414
|
"_skewX": 0,
|
|
234
415
|
"_skewY": 0,
|
|
235
416
|
"_is3DNode": false,
|
|
@@ -241,9 +422,10 @@ function createSceneData(rootNodes, sceneName) {
|
|
|
241
422
|
data.push(node);
|
|
242
423
|
|
|
243
424
|
// 添加组件
|
|
244
|
-
for (const
|
|
245
|
-
if (Components[
|
|
246
|
-
const comp = Components[
|
|
425
|
+
for (const { type, props } of compList) {
|
|
426
|
+
if (Components[type]) {
|
|
427
|
+
const comp = Components[type](nodeIndex);
|
|
428
|
+
applyComponentProps(comp, props);
|
|
247
429
|
const compIndex = data.length;
|
|
248
430
|
data.push(comp);
|
|
249
431
|
node._components.push({ "__id__": compIndex });
|
|
@@ -251,213 +433,63 @@ function createSceneData(rootNodes, sceneName) {
|
|
|
251
433
|
}
|
|
252
434
|
|
|
253
435
|
// 更新父节点的 _children
|
|
254
|
-
|
|
255
|
-
if (parent && parent._children) {
|
|
256
|
-
parent._children.push({ "__id__": nodeIndex });
|
|
257
|
-
}
|
|
436
|
+
data[parentIndex]._children.push({ "__id__": nodeIndex });
|
|
258
437
|
|
|
259
438
|
// 递归处理子节点
|
|
260
|
-
|
|
261
|
-
|
|
439
|
+
if (def.children && def.children.length > 0) {
|
|
440
|
+
for (const child of def.children) {
|
|
441
|
+
addNode(child, nodeIndex);
|
|
442
|
+
}
|
|
262
443
|
}
|
|
263
444
|
|
|
264
445
|
return nodeIndex;
|
|
265
446
|
}
|
|
266
447
|
|
|
267
|
-
//
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
} else {
|
|
275
|
-
// 用户定义的是其他节点,直接添加到 Canvas 下
|
|
276
|
-
for (const rootNode of rootNodes) {
|
|
277
|
-
addNode(rootNode, canvasIndex);
|
|
278
|
-
}
|
|
448
|
+
// 支持数组或单个节点
|
|
449
|
+
const nodes = Array.isArray(nodeDefs) ? nodeDefs : [nodeDefs];
|
|
450
|
+
|
|
451
|
+
// 添加用户节点到 Canvas
|
|
452
|
+
for (const nodeDef of nodes) {
|
|
453
|
+
addNode(nodeDef, canvasIndex);
|
|
279
454
|
}
|
|
280
455
|
|
|
281
456
|
return data;
|
|
282
457
|
}
|
|
283
458
|
|
|
284
|
-
/**
|
|
285
|
-
* 创建基础场景模板(当模板文件不存在时使用)
|
|
286
|
-
*/
|
|
287
|
-
function createBasicSceneTemplate() {
|
|
288
|
-
return [
|
|
289
|
-
{
|
|
290
|
-
"__type__": "cc.SceneAsset",
|
|
291
|
-
"_name": "",
|
|
292
|
-
"_objFlags": 0,
|
|
293
|
-
"_native": "",
|
|
294
|
-
"scene": { "__id__": 1 }
|
|
295
|
-
},
|
|
296
|
-
{
|
|
297
|
-
"__type__": "cc.Scene",
|
|
298
|
-
"_objFlags": 0,
|
|
299
|
-
"_parent": null,
|
|
300
|
-
"_children": [{ "__id__": 2 }],
|
|
301
|
-
"_active": true,
|
|
302
|
-
"_components": [],
|
|
303
|
-
"_prefab": null,
|
|
304
|
-
"_opacity": 255,
|
|
305
|
-
"_color": { "__type__": "cc.Color", "r": 255, "g": 255, "b": 255, "a": 255 },
|
|
306
|
-
"_contentSize": { "__type__": "cc.Size", "width": 0, "height": 0 },
|
|
307
|
-
"_anchorPoint": { "__type__": "cc.Vec2", "x": 0, "y": 0 },
|
|
308
|
-
"_trs": { "__type__": "TypedArray", "ctor": "Float64Array", "array": [0, 0, 0, 0, 0, 0, 1, 1, 1, 1] },
|
|
309
|
-
"_is3DNode": true,
|
|
310
|
-
"_groupIndex": 0,
|
|
311
|
-
"groupIndex": 0,
|
|
312
|
-
"autoReleaseAssets": false,
|
|
313
|
-
"_id": ""
|
|
314
|
-
},
|
|
315
|
-
{
|
|
316
|
-
"__type__": "cc.Node",
|
|
317
|
-
"_name": "Canvas",
|
|
318
|
-
"_objFlags": 0,
|
|
319
|
-
"_parent": { "__id__": 1 },
|
|
320
|
-
"_children": [{ "__id__": 3 }],
|
|
321
|
-
"_active": true,
|
|
322
|
-
"_components": [{ "__id__": 5 }, { "__id__": 6 }],
|
|
323
|
-
"_prefab": null,
|
|
324
|
-
"_opacity": 255,
|
|
325
|
-
"_color": { "__type__": "cc.Color", "r": 255, "g": 255, "b": 255, "a": 255 },
|
|
326
|
-
"_contentSize": { "__type__": "cc.Size", "width": 960, "height": 640 },
|
|
327
|
-
"_anchorPoint": { "__type__": "cc.Vec2", "x": 0.5, "y": 0.5 },
|
|
328
|
-
"_trs": { "__type__": "TypedArray", "ctor": "Float64Array", "array": [480, 320, 0, 0, 0, 0, 1, 1, 1, 1] },
|
|
329
|
-
"_eulerAngles": { "__type__": "cc.Vec3", "x": 0, "y": 0, "z": 0 },
|
|
330
|
-
"_skewX": 0,
|
|
331
|
-
"_skewY": 0,
|
|
332
|
-
"_is3DNode": false,
|
|
333
|
-
"_groupIndex": 0,
|
|
334
|
-
"groupIndex": 0,
|
|
335
|
-
"_id": ""
|
|
336
|
-
},
|
|
337
|
-
{
|
|
338
|
-
"__type__": "cc.Node",
|
|
339
|
-
"_name": "Main Camera",
|
|
340
|
-
"_objFlags": 0,
|
|
341
|
-
"_parent": { "__id__": 2 },
|
|
342
|
-
"_children": [],
|
|
343
|
-
"_active": true,
|
|
344
|
-
"_components": [{ "__id__": 4 }],
|
|
345
|
-
"_prefab": null,
|
|
346
|
-
"_opacity": 255,
|
|
347
|
-
"_color": { "__type__": "cc.Color", "r": 255, "g": 255, "b": 255, "a": 255 },
|
|
348
|
-
"_contentSize": { "__type__": "cc.Size", "width": 0, "height": 0 },
|
|
349
|
-
"_anchorPoint": { "__type__": "cc.Vec2", "x": 0.5, "y": 0.5 },
|
|
350
|
-
"_trs": { "__type__": "TypedArray", "ctor": "Float64Array", "array": [0, 0, 0, 0, 0, 0, 1, 1, 1, 1] },
|
|
351
|
-
"_eulerAngles": { "__type__": "cc.Vec3", "x": 0, "y": 0, "z": 0 },
|
|
352
|
-
"_skewX": 0,
|
|
353
|
-
"_skewY": 0,
|
|
354
|
-
"_is3DNode": false,
|
|
355
|
-
"_groupIndex": 0,
|
|
356
|
-
"groupIndex": 0,
|
|
357
|
-
"_id": ""
|
|
358
|
-
},
|
|
359
|
-
{
|
|
360
|
-
"__type__": "cc.Camera",
|
|
361
|
-
"_name": "",
|
|
362
|
-
"_objFlags": 0,
|
|
363
|
-
"node": { "__id__": 3 },
|
|
364
|
-
"_enabled": true,
|
|
365
|
-
"_cullingMask": 4294967295,
|
|
366
|
-
"_clearFlags": 7,
|
|
367
|
-
"_backgroundColor": { "__type__": "cc.Color", "r": 0, "g": 0, "b": 0, "a": 255 },
|
|
368
|
-
"_depth": -1,
|
|
369
|
-
"_zoomRatio": 1,
|
|
370
|
-
"_targetTexture": null,
|
|
371
|
-
"_fov": 60,
|
|
372
|
-
"_orthoSize": 10,
|
|
373
|
-
"_nearClip": 1,
|
|
374
|
-
"_farClip": 4096,
|
|
375
|
-
"_ortho": true,
|
|
376
|
-
"_rect": { "__type__": "cc.Rect", "x": 0, "y": 0, "width": 1, "height": 1 },
|
|
377
|
-
"_renderStages": 1,
|
|
378
|
-
"_alignWithScreen": true,
|
|
379
|
-
"_id": ""
|
|
380
|
-
},
|
|
381
|
-
{
|
|
382
|
-
"__type__": "cc.Canvas",
|
|
383
|
-
"_name": "",
|
|
384
|
-
"_objFlags": 0,
|
|
385
|
-
"node": { "__id__": 2 },
|
|
386
|
-
"_enabled": true,
|
|
387
|
-
"_designResolution": { "__type__": "cc.Size", "width": 960, "height": 640 },
|
|
388
|
-
"_fitWidth": false,
|
|
389
|
-
"_fitHeight": true,
|
|
390
|
-
"_id": ""
|
|
391
|
-
},
|
|
392
|
-
{
|
|
393
|
-
"__type__": "cc.Widget",
|
|
394
|
-
"_name": "",
|
|
395
|
-
"_objFlags": 0,
|
|
396
|
-
"node": { "__id__": 2 },
|
|
397
|
-
"_enabled": true,
|
|
398
|
-
"alignMode": 1,
|
|
399
|
-
"_target": null,
|
|
400
|
-
"_alignFlags": 45,
|
|
401
|
-
"_left": 0,
|
|
402
|
-
"_right": 0,
|
|
403
|
-
"_top": 0,
|
|
404
|
-
"_bottom": 0,
|
|
405
|
-
"_verticalCenter": 0,
|
|
406
|
-
"_horizontalCenter": 0,
|
|
407
|
-
"_isAbsLeft": true,
|
|
408
|
-
"_isAbsRight": true,
|
|
409
|
-
"_isAbsTop": true,
|
|
410
|
-
"_isAbsBottom": true,
|
|
411
|
-
"_isAbsHorizontalCenter": true,
|
|
412
|
-
"_isAbsVerticalCenter": true,
|
|
413
|
-
"_originalWidth": 0,
|
|
414
|
-
"_originalHeight": 0,
|
|
415
|
-
"_id": ""
|
|
416
|
-
}
|
|
417
|
-
];
|
|
418
|
-
}
|
|
419
|
-
|
|
420
459
|
function run(args) {
|
|
421
460
|
if (args.length < 1) {
|
|
422
461
|
console.log(JSON.stringify({
|
|
423
|
-
error: '用法:
|
|
424
|
-
hint: '从 stdin
|
|
462
|
+
error: '用法: cocos2d-cli create-scene <输出路径.fire>',
|
|
463
|
+
hint: '从 stdin 读取 JSON 结构生成场景',
|
|
464
|
+
example: 'type scene.json | cocos2d-cli create-scene assets/scene.fire'
|
|
425
465
|
}));
|
|
426
466
|
return;
|
|
427
467
|
}
|
|
428
468
|
|
|
429
469
|
const outputPath = args[0];
|
|
430
|
-
const sceneName =
|
|
470
|
+
const sceneName = path.basename(outputPath, '.fire');
|
|
431
471
|
|
|
432
|
-
// 从 stdin
|
|
472
|
+
// 从 stdin 读取 JSON
|
|
433
473
|
let input = '';
|
|
434
474
|
|
|
435
|
-
// 检查是否是管道输入
|
|
436
475
|
if (!process.stdin.isTTY) {
|
|
437
|
-
// 同步读取 stdin(简化处理)
|
|
438
|
-
const fs = require('fs');
|
|
439
476
|
input = fs.readFileSync(0, 'utf8');
|
|
440
477
|
}
|
|
441
478
|
|
|
442
479
|
if (!input.trim()) {
|
|
443
480
|
console.log(JSON.stringify({
|
|
444
|
-
error: '请通过 stdin
|
|
445
|
-
example: `echo "Canvas (canvas)\\n├─ TopBar (sprite, widget)\\n│ └─ ScoreLabel (label)" | cocos2.4 create-scene assets/game.fire`
|
|
481
|
+
error: '请通过 stdin 提供 JSON 结构'
|
|
446
482
|
}));
|
|
447
483
|
return;
|
|
448
484
|
}
|
|
449
485
|
|
|
450
486
|
try {
|
|
451
|
-
//
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
if (rootNodes.length === 0) {
|
|
455
|
-
console.log(JSON.stringify({ error: '未能解析出任何节点' }));
|
|
456
|
-
return;
|
|
457
|
-
}
|
|
487
|
+
// 移除 BOM 并解析 JSON
|
|
488
|
+
input = input.replace(/^\uFEFF/, '').trim();
|
|
489
|
+
const nodeDef = JSON.parse(input);
|
|
458
490
|
|
|
459
491
|
// 生成场景数据
|
|
460
|
-
const sceneData = createSceneData(
|
|
492
|
+
const sceneData = createSceneData(nodeDef, sceneName);
|
|
461
493
|
|
|
462
494
|
// 确保输出目录存在
|
|
463
495
|
const outputDir = path.dirname(outputPath);
|
|
@@ -469,11 +501,10 @@ function run(args) {
|
|
|
469
501
|
fs.writeFileSync(outputPath, JSON.stringify(sceneData, null, 2), 'utf8');
|
|
470
502
|
|
|
471
503
|
// 统计信息
|
|
472
|
-
let nodeCount = 0;
|
|
473
|
-
let compCount = 0;
|
|
504
|
+
let nodeCount = 0, compCount = 0;
|
|
474
505
|
for (const item of sceneData) {
|
|
475
506
|
if (item.__type__ === 'cc.Node') nodeCount++;
|
|
476
|
-
else if (item.__type__?.startsWith('cc.') &&
|
|
507
|
+
else if (item.__type__?.startsWith('cc.') && !['cc.Scene', 'cc.SceneAsset'].includes(item.__type__)) {
|
|
477
508
|
compCount++;
|
|
478
509
|
}
|
|
479
510
|
}
|
|
@@ -482,8 +513,7 @@ function run(args) {
|
|
|
482
513
|
success: true,
|
|
483
514
|
path: outputPath,
|
|
484
515
|
nodes: nodeCount,
|
|
485
|
-
components: compCount
|
|
486
|
-
structure: rootNodes.map(n => n.name)
|
|
516
|
+
components: compCount
|
|
487
517
|
}));
|
|
488
518
|
|
|
489
519
|
} catch (err) {
|
|
@@ -491,4 +521,4 @@ function run(args) {
|
|
|
491
521
|
}
|
|
492
522
|
}
|
|
493
523
|
|
|
494
|
-
module.exports = { run };
|
|
524
|
+
module.exports = { run };
|