开发环境与版本锁定
1.1 一次把我逼到重做导入的版本事故
我第一次做 Cocos Creator 项目时没锁版本,谁手上有新版本就用谁的,结果第二周就出事。
那天我拉了同事的分支,编辑器提示"项目版本较低,是否升级"。我点了确认。资源库里的预制体被自动重写,本地图集配置和场景引用跟着错位,打开是一片粉色。回到自己的分支,冲突提示直接指向 .meta 文件。
那次之后我养成了一个习惯:新项目第一天就把编辑器版本锁死,写进 README 第一行,谁都不许擅自升级,除非升级本身是这周的排期任务。
锁版本不等于永远不升级。3.8 这条线我一直在跟,从 3.8.1 用到后面几个补丁版,每次升级都是有意识的动作。比较值得注意的一次是 3.8.7 加了 Sorting2D 组件和排序图层配置,这是新东西,不是破坏性改动。但同一批更新里混了一条真实的破坏性变更:Bloom 特效的强度参数变了,从 3.8.4 之后升上来的项目要把强度从 2.3 改回 1.0,不然画面跟之前完全不一样。同一批还有一条,Spine 要求每个 Slot 必须有对应的 Attachment,否则解析直接失败。
这两条我记了很久,它们有个共同点:升级不是点一下按钮,是要你回头看自己项目里用到的那些功能。
1.2 我的环境清单表
这是我项目根目录 README.md 里一直维护的表,加上来之后被问过好几次,索性直接写进书里。
| 环节 | 我用的版本 / 路径 | 用途 | 为什么是这个 |
|---|---|---|---|
| Cocos Creator | 3.8.6(Windows 版,Dashboard 安装) | 编辑场景、挂组件、预览、构建 | 3.8 是当前长期维护的 3.x 分支,2.x 已停止更新 |
| Node.js | 16.20.2 | 跑构建脚本、CI 辅助脚本 | 3.8 的脚本编译链在 Node 16 上最稳,Node 18/20 我遇到过个别第三方脚本报语法错 |
| TypeScript | 4.9.x(用编辑器自带版本) | 脚本类型检查 | 内置 TS 和编辑器版本绑死,全局装一份只会让 tsconfig 对不上 |
| 编辑器语言 | VS Code 1.9x | 写 TypeScript | 装 Cocos Creator 官方 API 提示插件后,cc. 开头能补全 |
| 微信开发者工具 | 1.06 稳定版 | 导入构建产物、真机预览、看日志 | 唯一的真机验证环境,编辑器预览不算数 |
| Git | 2.43+ | 版本管理 | 只需要基础能力 |
| 截图/录屏 | 系统自带 | 记录玩法验证过程 | 不值得为它装东西 |
有两条经验值得单独说。
第一,TypeScript 我不装全局版本。Creator 有自己的 TS 编译进程,全局再装一份,编辑器里的类型提示和构建时的类型检查可能给出两套不一样的报错。后来我在项目里放个 tsconfig.json,把类型声明路径指对,命令行和编辑器里看到的结果就一致了。
第二,Node 固定在 16.x,不追新。我有个脚本要读构建产物的 JSON,Node 18 上换了个依赖,同一份文件解析出来的字段顺序变了,diff 全红。工具链稳定比工具链新值钱。
1.3 编辑器、命令行、开发者工具,三段各干什么
我把流程拆成三段,每段只干自己那一摊。
编辑器负责"需要人看着画面做"的活。建场景、摆节点、调预制体、连碰撞体,这些必须用编辑器,因为它是唯一能实时看到结果的地方。读输出的活我不在编辑器里做。
命令行负责构建。构建是纯计算,参数固定,结果确定,放到命令行里就能进 CI,能自动化,能出包体统计。我的构建命令长这样:
CocosCreator.exe --project <项目路径> --build "platform=wechatgame;debug=true"
Windows 上路径带空格要加引号。几个常用参数:
platform指定平台,wechatgame 是微信小游戏,web-mobile 是移动端 Web。debug我本地一律 true,出包才 false。debug 模式带完整调试信息,包体会大一大截,但堆栈和日志能看懂。buildPath指定输出目录,默认在项目下的build。md5Cache影响资源是否带哈希,本地开发关掉,能省掉一堆"改了代码没生效"的假象。
还有一个更省事的方式,是用构建面板导出一份配置文件,然后用 --build 传配置路径。这种方式适合放进 CI,参数都在文件里,不用在脚本里拼字符串。我用导出配置这条路,因为微信小游戏的 AppID 这类参数在配置文件里比在命令行里好维护。导出的 json 按平台分,还带版本号,别手删版本号,跨版本导入靠它做数据迁移。
要注意的是,命令行构建仍然走 Creator 编辑器那套引擎,不是纯命令行引擎。所以它需要有图形环境,在 Windows 服务器上跑要保证能开图形会话。CI 机器通常无头,这一层要专门配。
还还有一点我一开始没注意:命令行构建别只看有没有报错,要看退出码。3.8 给了三个明确的码,32 是构建参数不合法,34 是构建过程出错,36 是成功。脚本里只判断"进程跑完了",参数写错也会被当成成功,这是我改过一次的 bug。
开发者工具负责验证。构建产物是个目录,导入微信开发者工具,真机预览,看 Console 里有没有红色报错,看内存和帧率。我坚持一件事:小游戏版本的功能必须在真机上验过。编辑器预览跑得通不代表小游戏跑得通,小游戏环境没有 DOM,WebGL 上下文创建时机也不一样。
三段的顺序是:编辑器改东西,命令行出包,开发者工具验包。中间不跳步。
1.4 改一次影响全局的选项
有些设置看着不起眼,改一次整个项目都跟着变。全部在 项目 → 项目设置 里,配置存在项目的 settings/ 目录,这个目录要进版本库。
这里有个容易混的地方,我自己也搞错过。项目里两处存配置:settings/ 放项目设置面板的东西,设计分辨率、物理、脚本、纹理压缩这些全局项都在这;构建发布面板里配好的各平台构建选项,落在 profiles/v2/packages/builder.json。前者要提交,后者按官方说法可再生,但团队要共用同一套构建参数,得靠导出的 json 走命令行。所以我实际提交两份:settings/ 整个目录,加上导出的构建配置 json。
第一个是默认 Canvas 的设计分辨率和适配策略。设计分辨率 720×1280,适配屏幕宽度和高度都勾上。改这个值,新建 Canvas 都跟着变,已存在的不会自动改,它们各自存了自己的设计分辨率。混着两种分辨率的项目在真机上会歪。
第二个是渲染管线。内置的有前向和延迟两套。纯 2D 用前向就够了,我这套项目从头到尾没碰过延迟管线,2D 用不上它的收益,而内存和带宽开销是实打实的。
第三个是功能裁剪。这一栏能砍掉引擎模块,比如 3D 物理、粒子系统、视频播放。裁掉的模块打包时被移除,能省下可观的主包体积。我裁之前先搜一遍项目,确认没用到。对 2D 小游戏来说,3D 物理和材质变体最值得砍。
第四个是纹理压缩预设。压缩纹理的配置不在图片资源上,而是在项目设置里定义好预设,再回到每张图片的属性检查器里指定用哪个。这个设计有点反直觉,我第一次配置时在图片上找了半天入口。预设里能按平台分开配,小游戏走 ETC2,Web 走 ASTC。
第五个是 Macro Config。引擎宏在这里改,预览和构建时都生效。这里面有个开关我最后动了:ENABLE_TRANSPARENT_CANVAS,默认关。我保持关,因为开了之后 Canvas 支持 Alpha 通道,性能反而更差,我这个游戏也不需要透明背景。
第六个是物理参数。重力、速度、接触事件回调开关。速度迭代次数和物理子步数直接影响手感,是要调的参数,但改全局值会影响所有场景,所以改动要写进提交信息里。
我的做法是,任何一条改完,都在提交信息里单独写一行,写清改了什么、为什么,别人 review 时一眼能看出这是全局改动。
1.5 多人协作时版本不一致会发生什么
我写这一节是因为踩过,而且踩得很难看。
最直接的后果是资源被静默改写。编辑器打开项目时会自动升级项目格式,高版本保存过的场景和预制体,低版本打开可能提示升级,也可能部分字段直接丢掉。我那次的问题不是"提示我升级",是低版本的资源库缓存跟高版本写下的 .meta 对不上,场景加载出来是空的。
第二个后果是构建结果不可复现。同一个 commit,A 机器打出来 1.1 MB,B 机器 1.4 MB,因为两边引擎补丁不一样,压缩和资源处理行为有差别。这种差异在小程序平台上会直接影响审核,你甚至不知道差异从哪来。
第三个后果是 .meta 冲突率飙升。.meta 记录资源的 uuid 和导入配置,高低版本对同一个资源算出的导入参数可能不同,两个人各改各的,合并时每个资源文件都冲突。
我的处理办法:
- 引擎版本写进项目根目录的
package.json,Creator 自己维护的那份creator.version字段。这个字段是编辑器判断"这个项目是谁创建的"的依据,低版本编辑器打开高版本项目会直接拒绝,反过来会提示升级,所以它就是天然的版本锁。 - README 顶部写清三行:编辑器版本、Node 版本、构建命令。谁改版本,三行一起改。
- 升级只升一个补丁版本,升完全量跑一遍测试场景,然后立刻打 tag。我用
v3.8.6这种标签,打完 tag 的构建产物存档一份,作为出包基线。 - 每个新人的第一件事,是拿 tag 版本跑一遍构建,确认产物结构和基线一致。花半小时,能省掉后面一整天的排查。
如果真的已经不一致了,有个补救办法:把项目目录下的 library 删掉重新导入。library 是编辑器生成的缓存,不是源码。它坏了、乱了、版本对不上的时候,删掉重来最省事,比研究缓存里哪条记录不对快得多。我删过至少五次 library,每次都是几分钟后恢复。
顺带说个同样容易踩的:package.json 和 assets/ 缺一个文件夹,就不能作为 Cocos 项目被打开。所以 package.json 一定要提交,哪怕你从没改过它。
