cocos2d-cli 1.2.1 → 1.5.0

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.
Files changed (39) hide show
  1. package/README.md +142 -0
  2. package/bin/{cocos-cli.js → cocos2d-cli.js} +36 -22
  3. package/package.json +3 -3
  4. package/src/commands/add-component.js +75 -114
  5. package/src/commands/add.js +115 -294
  6. package/src/commands/build.js +1 -1
  7. package/src/commands/create-scene.js +133 -488
  8. package/src/commands/get.js +104 -158
  9. package/src/commands/prefab-create.js +57 -425
  10. package/src/commands/remove-component.js +81 -33
  11. package/src/commands/remove.js +66 -65
  12. package/src/commands/set.js +105 -253
  13. package/src/commands/tree.js +7 -11
  14. package/src/lib/cc/CCButton.js +122 -0
  15. package/src/lib/cc/CCCamera.js +93 -0
  16. package/src/lib/cc/CCCanvas.js +64 -0
  17. package/src/lib/cc/CCColor.js +32 -0
  18. package/src/lib/cc/CCComponent.js +60 -0
  19. package/src/lib/cc/CCLabel.js +109 -0
  20. package/src/lib/cc/CCNode.js +242 -0
  21. package/src/lib/cc/CCObject.js +23 -0
  22. package/src/lib/cc/CCPrefab.js +242 -0
  23. package/src/lib/cc/CCRect.js +32 -0
  24. package/src/lib/cc/CCScene.js +42 -0
  25. package/src/lib/cc/CCSceneAsset.js +271 -0
  26. package/src/lib/cc/CCSize.js +26 -0
  27. package/src/lib/cc/CCSprite.js +82 -0
  28. package/src/lib/cc/CCTrs.js +74 -0
  29. package/src/lib/cc/CCVec2.js +26 -0
  30. package/src/lib/cc/CCVec3.js +29 -0
  31. package/src/lib/cc/CCWidget.js +98 -0
  32. package/src/lib/cc/index.js +40 -0
  33. package/src/lib/fire-utils.js +58 -392
  34. package/src/lib/json-parser.js +166 -0
  35. package/src/lib/node-utils.js +395 -0
  36. package/src/lib/templates.js +49 -0
  37. package/src/lib/utils.js +202 -0
  38. package/src/commands/delete.js +0 -74
  39. package/src/lib/components.js +0 -404
package/README.md ADDED
@@ -0,0 +1,142 @@
1
+ # cocos2d-cli
2
+
3
+ Cocos Creator 场景/预制体命令行操作工具,支持通过 CLI 或 AI 自动化创建和编辑游戏界面。
4
+
5
+ ## 功能
6
+
7
+ - 创建场景和预制体
8
+ - 添加/删除节点和组件
9
+ - 修改节点和组件属性
10
+ - 查看节点树结构
11
+ - 从简化 JSON 创建复杂界面
12
+
13
+ ## 安装
14
+
15
+ ```bash
16
+ npm install -g cocos2d-cli
17
+ ```
18
+
19
+ ## 使用
20
+
21
+ ```bash
22
+ cocos2d-cli help # 查看帮助
23
+ cocos2d-cli --help # 同上
24
+ ```
25
+
26
+ ### 创建预制体
27
+
28
+ ### 创建预制体
29
+
30
+ ```bash
31
+ # 创建空预制体
32
+ cocos2d-cli create-prefab ./MyPrefab.prefab
33
+
34
+ # 从 JSON 创建预制体
35
+ cocos2d-cli create-prefab ./ui.json ./MyPrefab.prefab
36
+ ```
37
+
38
+ ### 创建场景
39
+
40
+ ```bash
41
+ # 创建默认场景(含 Canvas 和 Main Camera)
42
+ cocos2d-cli create-scene ./MyScene.fire
43
+
44
+ # 从 JSON 创建场景
45
+ cocos2d-cli create-scene ./ui.json ./MyScene.fire
46
+ ```
47
+
48
+ ### 节点操作
49
+
50
+ ```bash
51
+ # 添加节点
52
+ cocos2d-cli add ./MyPrefab.prefab Root NewNode --type=sprite --width=100 --height=100
53
+
54
+ # 删除节点
55
+ cocos2d-cli remove ./MyPrefab.prefab Root/NewNode
56
+
57
+ # 查看节点树
58
+ cocos2d-cli tree ./MyPrefab.prefab
59
+ ```
60
+
61
+ ### 组件操作
62
+
63
+ ```bash
64
+ # 添加组件
65
+ cocos2d-cli add-component ./MyPrefab.prefab Root label
66
+
67
+ # 删除组件
68
+ cocos2d-cli remove-component ./MyPrefab.prefab Root label
69
+ ```
70
+
71
+ ### 属性操作
72
+
73
+ ```bash
74
+ # 获取属性
75
+ cocos2d-cli get ./MyPrefab.prefab Root width
76
+ cocos2d-cli get ./MyPrefab.prefab Root label.string
77
+
78
+ # 设置属性
79
+ cocos2d-cli set ./MyPrefab.prefab Root width 200
80
+ cocos2d-cli set ./MyPrefab.prefab Root label.string "Hello"
81
+ ```
82
+
83
+ ## 简化 JSON 格式
84
+
85
+ AI 可以通过简化 JSON 描述界面结构:
86
+
87
+ ```json
88
+ {
89
+ "name": "MyButton",
90
+ "width": 200,
91
+ "height": 60,
92
+ "components": ["sprite", "button"],
93
+ "children": [
94
+ {
95
+ "name": "Label",
96
+ "components": [
97
+ {
98
+ "type": "label",
99
+ "string": "Click Me",
100
+ "fontSize": 24
101
+ }
102
+ ]
103
+ }
104
+ ]
105
+ }
106
+ ```
107
+
108
+ ### 支持的组件类型
109
+
110
+ - `canvas` - Canvas
111
+ - `widget` - Widget
112
+ - `sprite` - Sprite
113
+ - `label` - Label
114
+ - `button` - Button
115
+ - `camera` - Camera
116
+
117
+ ### 节点属性
118
+
119
+ | 属性 | 说明 |
120
+ |------|------|
121
+ | `name` | 节点名称 |
122
+ | `active` | 是否激活 |
123
+ | `x`, `y` | 位置 |
124
+ | `width`, `height` | 尺寸 |
125
+ | `scaleX`, `scaleY` | 缩放 |
126
+ | `rotation` | 旋转角度 |
127
+ | `anchorX`, `anchorY` | 锚点 |
128
+ | `opacity` | 透明度 |
129
+ | `color` | 颜色 (十六进制如 "#ff0000") |
130
+
131
+ ## 架构
132
+
133
+ ```
134
+ 输入 内存模型 输出
135
+ ───── ──────── ─────
136
+ 简化JSON ──→ json-parser ──→ CCNode树 ─┬─→ CCSceneAsset ──→ .fire
137
+ 编辑器文件 ──→ fromJSON ──→ CC对象树 ──┘─→ CCPrefab ──→ .prefab
138
+ ```
139
+
140
+ ## License
141
+
142
+ MIT
@@ -13,8 +13,8 @@ const commands = {
13
13
  set: '../src/commands/set',
14
14
  add: '../src/commands/add',
15
15
  'add-component': '../src/commands/add-component',
16
+ 'remove-component': '../src/commands/remove-component',
16
17
  'remove': '../src/commands/remove',
17
- delete: '../src/commands/delete',
18
18
  build: '../src/commands/build',
19
19
  'create-prefab': '../src/commands/prefab-create',
20
20
  'create-scene': '../src/commands/create-scene'
@@ -29,16 +29,21 @@ Cocos Creator CLI - 场景/预制体操作工具集
29
29
  cocos2d-cli <command> [options]
30
30
 
31
31
  命令:
32
- tree <场景.fire | 预制体.prefab> 查看节点树(获取索引)
33
- get <场景.fire | 预制体.prefab> <索引> 获取节点属性
34
- set <场景.fire | 预制体.prefab> <索引> [选项] 修改节点属性
35
- add <场景.fire | 预制体.prefab> <父索引> <名称> 添加节点
36
- add-component <文件> <节点索引> <类型> 给节点添加组件
37
- remove <文件> <索引> 删除节点或组件
38
- delete <文件> <节点索引> 删除节点
32
+ tree <场景.fire | 预制体.prefab> 查看节点树
33
+ get <场景.fire | 预制体.prefab> <节点路径> 获取节点属性
34
+ set <场景.fire | 预制体.prefab> <节点路径> [选项] 修改节点属性
35
+ add <场景.fire | 预制体.prefab> <父节点路径> <名称> 添加节点
36
+ add-component <文件> <节点路径> <类型> 给节点添加组件
37
+ remove-component <文件> <节点路径> <类型> 删除节点组件
38
+ remove <文件> <节点路径> 删除节点
39
39
  build <项目目录> 构建组件映射
40
- create-prefab <输出.prefab> 从 stdin(JSON) 创建预制体
41
- create-scene <输出.fire> 从 stdin(JSON) 创建场景
40
+ create-prefab [JSON文件] <输出.prefab> 创建预制体(不传JSON则创建默认)
41
+ create-scene [JSON文件] <输出.fire> 创建场景(不传JSON则创建默认)
42
+
43
+ 节点路径格式:
44
+ Canvas - 根节点下的 Canvas
45
+ Canvas/MidNode - Canvas 下的 MidNode
46
+ Canvas/GameScene/NodeA - 多层嵌套路径
42
47
 
43
48
  选项:
44
49
  --name=<名称> 修改节点名称
@@ -58,7 +63,6 @@ Cocos Creator CLI - 场景/预制体操作工具集
58
63
  --fontSize=<数值> 修改 Label 字体大小
59
64
  --lineHeight=<数值> 修改 Label 行高
60
65
  --type=sprite/label/button 添加节点时指定组件类型
61
- --at=<索引> 添加节点时插入到子节点的指定位置(0=第一个)
62
66
 
63
67
  JSON 格式 (create-prefab / create-scene):
64
68
  {
@@ -79,8 +83,13 @@ JSON 格式 (create-prefab / create-scene):
79
83
 
80
84
  节点属性: name, width, height, x, y, color, opacity, anchorX, anchorY, rotation, scaleX, scaleY, active
81
85
 
86
+ 组件写法:
87
+ 简写: "sprite" 或 "label"
88
+ 完整: { "type": "sprite", "sizeMode": 1 }
89
+ 完整: { "type": "label", "string": "文本", "fontSize": 32, "color": "#fff" }
90
+
82
91
  组件类型:
83
- sprite - 精灵���默认白色方块,节点设置什么颜色就显示什么颜色
92
+ sprite - 精灵(默认白色方块,节点设置什么颜色就显示什么颜色)
84
93
  label - 文本,支持 string, fontSize, color(兼容)
85
94
  button - 按钮,通常配合 sprite 使用才能看见
86
95
  widget - 对齐,支持 top, bottom, left, right
@@ -92,26 +101,31 @@ JSON 格式 (create-prefab / create-scene):
92
101
  注意:
93
102
  - color 写在节点或 label 组件均可
94
103
  - button 需要配合 sprite 才能看见按钮外观
95
- - 必须通过 JSON 文件输入: type panel.json | cocos2d-cli create-prefab xxx.prefab
96
104
 
97
105
  示例:
98
106
  cocos2d-cli tree assets/main.fire
99
- cocos2d-cli get assets/main.fire 5
100
- cocos2d-cli set assets/main.fire 8 --x=100 --y=200 --color=#ff0000
101
- cocos2d-cli add assets/main.fire 5 NewSprite --type=sprite --x=100
107
+ cocos2d-cli get assets/main.fire Canvas/MidNode
108
+ cocos2d-cli set assets/main.fire Canvas/MidNode --x=100 --y=200 --color=#ff0000
109
+ cocos2d-cli add assets/main.fire Canvas NewSprite --type=sprite --x=100
110
+ cocos2d-cli add-component assets/main.fire Canvas/MidNode label
111
+ cocos2d-cli remove-component assets/main.fire Canvas/MidNode label
112
+ cocos2d-cli remove assets/main.fire Canvas/MidNode
102
113
 
103
- # 从 JSON 创建场景
104
- type scene.json | cocos2d-cli create-scene assets/scene.fire
114
+ # 从 JSON 文件创建场景
115
+ cocos2d-cli create-scene scene.json assets/scene.fire
105
116
 
106
- # 从 JSON 创建预制体
107
- type panel.json | cocos2d-cli create-prefab assets/panel.prefab
117
+ # 从 JSON 文件创建预制体
118
+ cocos2d-cli create-prefab panel.json assets/panel.prefab
119
+
120
+ # 创建默认预制体(不传JSON)
121
+ cocos2d-cli create-prefab assets/NewNode.prefab
108
122
  `);
109
123
  }
110
124
 
111
125
  // 解析参数
112
126
  const args = process.argv.slice(2);
113
127
 
114
- if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
128
+ if (args.length === 0 || args[0] === '--help' || args[0] === '-h' || args[0] === 'help') {
115
129
  showHelp();
116
130
  process.exit(0);
117
131
  }
@@ -132,4 +146,4 @@ try {
132
146
  } catch (err) {
133
147
  console.error(`命令执行失败: ${err.message}`);
134
148
  process.exit(1);
135
- }
149
+ }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "cocos2d-cli",
3
- "version": "1.2.1",
3
+ "version": "1.5.0",
4
4
  "description": "Command-line tools for AI to read and manipulate Cocos Creator 2.4.x project scenes",
5
- "main": "bin/cocos-cli.js",
5
+ "main": "bin/cocos2d-cli.js",
6
6
  "bin": {
7
- "cocos2d-cli": "./bin/cocos-cli.js"
7
+ "cocos2d-cli": "./bin/cocos2d-cli.js"
8
8
  },
9
9
  "files": [
10
10
  "bin",
@@ -1,151 +1,112 @@
1
1
  /**
2
- * add-component 命令 - 给已存在的节点添加组件
2
+ * add-component 命令 - 添加组件
3
3
  */
4
4
 
5
- const { loadScene, saveScene, buildMaps, findNodeIndex, refreshEditor } = require('../lib/fire-utils');
6
- const { Components, generateId } = require('../lib/components');
7
- const fs = require('fs');
8
5
  const path = require('path');
6
+ const fs = require('fs');
7
+ const { CCSceneAsset, CCPrefab, CCCanvas, CCWidget, CCSprite, CCLabel, CCButton, CCCamera } = require('../lib/cc');
8
+ const { buildTree } = require('../lib/node-utils');
9
+ const { loadScriptMap, isPrefab } = require('../lib/fire-utils');
9
10
 
10
- // 加载脚本映射
11
- function loadScriptMap(projectPath) {
12
- const mapPath = path.join(projectPath, 'data', 'script_map.json');
13
- try {
14
- if (fs.existsSync(mapPath)) {
15
- return JSON.parse(fs.readFileSync(mapPath, 'utf-8'));
16
- }
17
- } catch (e) {
18
- // 忽略错误
11
+ /**
12
+ * 创建组件
13
+ */
14
+ function createComponent(type) {
15
+ switch (type.toLowerCase()) {
16
+ case 'canvas': return new CCCanvas();
17
+ case 'widget': return new CCWidget();
18
+ case 'sprite': return new CCSprite();
19
+ case 'label': return new CCLabel();
20
+ case 'button': return new CCButton();
21
+ case 'camera': return new CCCamera();
22
+ default: return null;
19
23
  }
20
- return {};
21
24
  }
22
25
 
23
- // 创建自定义脚本组件
24
- function createScriptComponent(scriptUuid, nodeId, scriptMap) {
25
- const scriptInfo = scriptMap[scriptUuid];
26
- const typeName = scriptInfo ? scriptInfo.name : scriptUuid;
26
+ /**
27
+ * 查找节点
28
+ */
29
+ function findNode(root, path) {
30
+ if (!path) return root;
31
+
32
+ const parts = path.split('/').filter(p => p);
33
+ if (parts.length === 0) return root;
34
+
35
+ let current = root;
36
+
37
+ if (parts[0] === root._name) {
38
+ parts.shift();
39
+ }
27
40
 
28
- return {
29
- "__type__": typeName,
30
- "_name": "",
31
- "_objFlags": 0,
32
- "node": { "__id__": nodeId },
33
- "_enabled": true,
34
- "_id": generateId()
35
- };
41
+ for (const part of parts) {
42
+ if (!current._children || current._children.length === 0) return null;
43
+ const found = current._children.find(c => c._name === part);
44
+ if (!found) return null;
45
+ current = found;
46
+ }
47
+
48
+ return current;
36
49
  }
37
50
 
38
51
  function run(args) {
39
52
  if (args.length < 3) {
40
- console.log(JSON.stringify({
41
- error: '用法: cocos2.4 add-component <场景文件路径> <节点路径> <组件类型>'
42
- }));
53
+ console.log(JSON.stringify({ error: '用法: cocos2d-cli add-component <场景.fire|预制体.prefab> <节点路径> <组件类型>' }));
43
54
  return;
44
55
  }
45
56
 
46
- const scenePath = args[0];
47
- const nodeRef = args[1];
48
- const componentType = args[2];
57
+ const filePath = args[0];
58
+ const nodePath = args[1];
59
+ const compType = args[2];
60
+
61
+ const ext = path.extname(filePath).toLowerCase();
49
62
 
50
63
  try {
51
- const data = loadScene(scenePath);
52
- const { indexMap } = buildMaps(data);
64
+ let root;
65
+ let asset;
66
+ const json = JSON.parse(fs.readFileSync(filePath, 'utf8'));
53
67
 
54
- // 查找节点
55
- const nodeIndex = findNodeIndex(data, indexMap, nodeRef);
56
-
57
- if (nodeIndex === null || !data[nodeIndex]) {
58
- console.log(JSON.stringify({ error: `找不到节点: ${nodeRef}` }));
68
+ if (ext === '.fire') {
69
+ asset = CCSceneAsset.fromJSON(json);
70
+ root = asset._scene;
71
+ } else if (ext === '.prefab') {
72
+ asset = CCPrefab.fromJSON(json);
73
+ root = asset._root;
74
+ } else {
75
+ console.log(JSON.stringify({ error: '不支持的文件类型,仅支持 .fire 和 .prefab' }));
59
76
  return;
60
77
  }
61
78
 
62
- const node = data[nodeIndex];
63
-
64
- // 检查是否已有该类型组件
65
- const existingComp = node._components?.find(comp => {
66
- const compData = data[comp.__id__];
67
- if (!compData) return false;
68
- const compType = compData.__type__;
69
- return compType === componentType || compType === 'cc.' + componentType.charAt(0).toUpperCase() + componentType.slice(1);
70
- });
79
+ const node = findNode(root, nodePath);
71
80
 
72
- if (existingComp) {
73
- console.log(JSON.stringify({
74
- error: `节点 "${node._name}" 已有 ${componentType} 组件`,
75
- nodeIndex,
76
- nodeName: node._name
77
- }));
81
+ if (!node) {
82
+ console.log(JSON.stringify({ error: `节点不存在: ${nodePath}` }));
78
83
  return;
79
84
  }
80
85
 
81
- // 加载脚本映射(从场景文件所在项目的 data 目录)
82
- const projectPath = path.dirname(scenePath);
83
- const scriptMap = loadScriptMap(projectPath);
84
-
85
86
  // 创建组件
86
- let componentData;
87
- const compIndex = data.length;
88
-
89
- // 检查是否是内置组件
90
- const builtInTypes = ['sprite', 'label', 'button', 'layout', 'widget', 'camera', 'canvas', 'particleSystem'];
91
-
92
- if (builtInTypes.includes(componentType.toLowerCase())) {
93
- // 内置组件
94
- const typeKey = componentType.toLowerCase();
95
- componentData = Components[typeKey]?.(nodeIndex);
96
-
97
- if (!componentData) {
98
- console.log(JSON.stringify({ error: `不支持的组件类型: ${componentType}` }));
99
- return;
100
- }
101
- } else {
102
- // 自定义脚本组件 - 查找脚本UUID
103
- let scriptUuid = null;
104
-
105
- // 在 scriptMap 中查找
106
- for (const [uuid, info] of Object.entries(scriptMap)) {
107
- if (info.name === componentType) {
108
- scriptUuid = uuid;
109
- break;
110
- }
111
- }
112
-
113
- // 如果没找到,尝试直接使用 componentType 作为类型名
114
- if (!scriptUuid) {
115
- // 检查是否是有效的 UUID 格式
116
- const uuidRegex = /^[a-f0-9-]{36}$/i;
117
- if (uuidRegex.test(componentType)) {
118
- scriptUuid = componentType;
119
- }
120
- }
121
-
122
- componentData = createScriptComponent(scriptUuid || componentType, nodeIndex, scriptMap);
87
+ const comp = createComponent(compType);
88
+ if (!comp) {
89
+ console.log(JSON.stringify({ error: `不支持的组件类型: ${compType}` }));
90
+ return;
123
91
  }
124
92
 
125
- // 添加组件到数组
126
- data.push(componentData);
127
-
128
- // 更新节点的 _components
129
- if (!node._components) node._components = [];
130
- node._components.push({ "__id__": compIndex });
93
+ comp.node = node;
94
+ node._components = node._components || [];
95
+ node._components.push(comp);
131
96
 
132
- // 保存场景
133
- saveScene(scenePath, data);
97
+ // 保存
98
+ const data = asset.toJSON();
99
+ fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
134
100
 
135
- // 触发编辑器刷新(传入场景路径以重新打开场景)
136
- refreshEditor(scenePath);
101
+ // 输出节点树
102
+ const scriptMap = loadScriptMap(filePath);
103
+ const prefab = isPrefab(data);
104
+ const startIndex = prefab ? 0 : 1;
105
+ console.log(buildTree(data, scriptMap, startIndex).trim());
137
106
 
138
- console.log(JSON.stringify({
139
- success: true,
140
- componentIndex: compIndex,
141
- componentType: componentData.__type__,
142
- nodeIndex,
143
- nodeName: node._name,
144
- message: `组件 "${componentData.__type__}" 已添加到节点 "${node._name}"`
145
- }, null, 2));
146
107
  } catch (err) {
147
108
  console.log(JSON.stringify({ error: err.message }));
148
109
  }
149
110
  }
150
111
 
151
- module.exports = { run };
112
+ module.exports = { run };