1. 项目概述:为什么一个“一人工作室”能靠微信小游戏跑通闭环?
“Vibe Gaming”这个名字听起来像支有十几号人的 indie studio,但实际就是我一个人——白天写业务代码,晚上调粒子特效,周末改 bug 到凌晨三点,连美术外包都得自己画原型图、写需求文档、反复沟通三轮才敢付定金。这个项目不是 demo,不是练手,是真正在微信小游戏平台上线、接入支付、跑过 30 天自然流量、单月流水破 2 万的实战项目。核心关键词就五个:微信小游戏、Cocos Creator、TypeScript、微信开发者工具、game.json——它们不是并列关系,而是环环相扣的生产链:Cocos Creator 是骨架,TypeScript 是神经,微信开发者工具是手术刀,game.json 是通关密钥,而微信小游戏平台,是唯一允许你把这四者打包塞进用户手机里、且不经过应用商店审核的合法出口。
很多人看到“一人工作室”就默认是“小打小闹”,但现实恰恰相反:微信小游戏生态对单人开发者极其友好,它天然过滤掉安卓碎片化适配、iOS 上架审核、渠道联运分成这些传统手游的“重型负担”,把焦点强行拉回到“玩法是否上头”“首屏加载是否够快”“广告激励是否合理”这三个硬指标上。我做的这款《弹球狂想曲》(非真实名,但类型一致)上线前测了 7 个版本,核心迭代点全在 game.json 的orientation、showStatusBar、customButton配置上;TypeScript 不是用来炫技的,而是为了在 Cocos Creator 的 Component 系统里,让onLoad()和start()的执行顺序错误能被编译器提前报错,而不是等用户反馈“点开始没反应”才去翻日志;Cocos Creator 3.8.2 的构建流程里,build目录下生成的main.js文件大小必须压到 1.2MB 以内,否则微信开发者工具会卡在“预编译”阶段不动,这个阈值不是凭空来的——微信引擎 runtime 对 JS 包体积有硬性限制,超了直接拒绝加载,连错误提示都不给。所以这不是“用工具做个游戏”,而是一场在微信生态规则内,用工程化思维完成的精密装配作业。
2. 整体架构设计:为什么选 Cocos Creator 而不是 Unity 或原生 Canvas?
2.1 技术栈选型背后的三重博弈
选 Cocos Creator 不是因为它“最好”,而是因为它在这三个维度上达到了一人工作室的最优解:
开发效率与调试成本的平衡点:Unity 打包微信小游戏需要走 WebGL 模板定制 + 微信专用 SDK 注入 + 多层 loader 重写,光是解决“黑屏白屏闪退”问题,我试过 5 种不同版本的团结引擎模板,每种都要手动 patch
index.html里的 canvas 初始化逻辑,光是定位gl.clearColor被覆盖的问题就耗掉两天。而 Cocos Creator 3.x 原生支持微信小游戏平台,在编辑器里勾选“微信小游戏”目标平台后,构建流程自动注入wx.createCanvas、wx.getSystemInfoSync等适配层,cc.sys.isMobile判断直接返回 true,省掉至少 80% 的底层胶水代码。这不是偷懒,是把有限精力聚焦在玩法迭代上。TypeScript 支持深度决定维护上限:Cocos Creator 的 Component 系统天然契合 TypeScript 的 class 继承模型。比如一个
PlayerController类,继承自cc.Component,它的@property({ type: cc.Node })装饰器能被编辑器识别并自动绑定 Inspector 面板,同时 TypeScript 编译器能校验this.node.getComponent<Enemy>()的返回类型是否为Enemy | null,避免运行时Cannot read property 'hp' of null这类低级错误。Unity 的 TypeScript 支持依赖第三方插件(如 TypeScript Definitions for Unity),但类型定义常滞后于 Unity 版本更新,去年我试过用 Unity 2022.3 + TS 插件,结果Input.GetTouch(0)的返回类型定义居然是any,完全失去类型保护意义。构建产物可控性决定上线稳定性:微信小游戏要求所有资源必须通过
wx.loadSubNpm或wx.downloadFile加载,禁止XMLHttpRequest。Cocos Creator 构建时会自动将resources目录下的.png、.json等资源转为res/xxx.png?r=abc123形式的带 hash URL,并注入到game.json的subContext配置中,整个过程无需手动干预。Unity 的 WebGL 构建产物是Build/xxx.data、Build/xxx.wasm等二进制文件,要塞进微信环境,必须用wx.getFileSystemManager().readFile读取再eval执行,这不仅违反微信安全策略,还会触发wasm加载失败的静默错误——你根本看不到控制台报错,只看到白屏。
提示:别信“Unity 微信小游戏打包教程”里说的“修改 index.html 就行”。微信引擎 runtime 不认标准 WebGL 上下文,它只认
wx.createCanvas创建的上下文,Unity 默认创建的是document.createElement('canvas'),这是根本性不兼容,不是改几行 HTML 能解决的。
2.2 架构分层:从 Cocos 场景到微信容器的映射关系
整个项目的物理结构是三层嵌套:
最内层:Cocos Creator 工程
包含assets(脚本、场景、预制体)、library(缓存)、build(构建输出)。关键约束:所有脚本必须用 TypeScript 编写,tsconfig.json中compilerOptions.target必须设为"ES2019"(微信基础库最低支持 ES2019),module设为"ESNext",禁用experimentalDecorators以外的所有实验性装饰器——微信引擎 runtime 不支持@reflect等高级特性。中间层:微信小游戏项目结构
构建后生成的build/wechatgame目录,必须包含project.config.json(微信开发者工具配置)、game.json(小游戏核心配置)、app.js(入口文件,由 Cocos 自动生成)、res/(资源目录)。这里game.json不是可选配置,而是强制入口:微信客户端启动时首先读取它,根据deviceOrientation决定横竖屏,根据networkTimeout设置网络请求超时,根据customButton定义右上角菜单按钮行为。漏配一项,轻则功能异常,重则审核被拒。最外层:微信开发者工具沙箱环境
这不是模拟器,而是真实微信客户端内核的精简版。它强制执行微信的安全策略:禁止eval()、禁止new Function()、禁止document.write、禁止访问window.localStorage(必须用wx.setStorageSync)。Cocos Creator 构建时会自动替换eval调用为Function构造函数,但如果你在自定义脚本里写了const fn = new Function('return 1'),微信开发者工具会在“调试器 → Console”里直接报SecurityError: eval is not allowed,且不显示堆栈——你得在“调试器 → Sources”里逐行断点才能定位。
这种分层不是理论设计,是血泪教训换来的。上线前最后一天,我发现 iOS 用户反馈“点击广告没反应”,查日志发现wx.showAdaptiveBanner调用失败,错误码1004(权限不足)。翻遍文档才发现,game.json里必须显式声明"requiredPrivateInfos": ["adaptBanner"],否则微信 runtime 默认关闭该 API 权限。这个字段不在 Cocos Creator 的构建配置里,必须手动编辑build/wechatgame/game.json添加——这就是中间层存在的意义:它既是桥梁,也是最后一道闸门。
3. 核心细节解析:TypeScript 在 Cocos Creator 中的落地陷阱
3.1 不是“会写 TS 就能用好”,而是“必须理解 Cocos 的生命周期”
TypeScript 在 Cocos Creator 里最大的坑,不是语法,而是它和引擎生命周期的耦合方式。新手常犯的错误是把 TS 当成纯逻辑语言,忽略cc.Component的onLoad()、start()、update()这三个钩子函数的执行时机差异。
onLoad():组件被实例化后立即调用,此时节点可能还未加入场景树,this.node.parent可能为 null。我曾在这里写this.node.parent.getChildByName('UI'),结果在部分低端安卓机上返回 undefined,因为父节点还没挂载完成。正确做法是加判空:if (this.node.parent) { /* safe to access */ },或者改用this.scheduleOnce(() => { /* delay one frame */ }, 0)。start():组件所在的节点第一次被激活时调用,此时节点已加入场景树,this.node.parent确保有值。但注意:如果节点被node.active = false关闭后再激活,start()不会再次触发——它只执行一次。所以初始化 UI 组件状态,必须放在这里,而不是onLoad()。update():每帧调用,但微信小游戏帧率不稳定(尤其低端机),dt(delta time)可能忽大忽小。我做过测试:同一台 Redmi Note 9,在update()里用this.timer += dt累加计时,10 秒后误差高达 ±1.2 秒。解决方案是改用cc.macro.DELTA_TIME的固定步长,或直接用Date.now()计算绝对时间差。
TypeScript 的类型系统在这里起到关键防护作用。比如定义一个PlayerData接口:
interface PlayerData { hp: number; maxHp: number; level: number; skills: Array<{ id: string; cd: number; }>; }然后在PlayerController里:
@property({ type: cc.Integer }) public baseHp: number = 100; private _data: PlayerData | null = null; get data(): PlayerData { if (!this._data) { this._data = { hp: this.baseHp, maxHp: this.baseHp, level: 1, skills: [] }; } return this._data; }这样,所有对this.data.hp的访问,TypeScript 都能保证hp属性存在且为 number 类型。如果某处误写成this.data.hP(大小写错误),TS 编译器立刻报错Property 'hP' does not exist on type 'PlayerData',而不是等到运行时崩溃。
注意:Cocos Creator 的
@property装饰器在 TS 中必须配合cc.Class使用,但cc.Class已在 3.x 版本中废弃,改用@ccclass。很多老教程还在教cc.Class({ extends: cc.Component }),这是 2.x 的写法,3.x 必须用@ccclass('PlayerController'),否则编辑器无法识别属性,Inspector 面板不显示。
3.2 game.json:那个被忽视却决定生死的 JSON 文件
game.json是微信小游戏的“宪法”,它不处理游戏逻辑,但决定了游戏能否启动、如何启动、能调用哪些 API。它的结构看似简单,实则暗藏玄机:
{ "deviceOrientation": "portrait", "showStatusBar": false, "networkTimeout": { "request": 10000, "downloadFile": 60000 }, "customButton": { "type": "text", "text": "设置", "style": { "left": 10, "top": 10, "width": 60, "height": 30, "backgroundColor": "#000000", "color": "#ffffff", "fontSize": 14, "borderRadius": 4 } }, "requiredPrivateInfos": ["openLocation", "getLocation"] }deviceOrientation:必须与 Cocos Creator 项目设置中的Project Settings → Orientation严格一致。如果 Cocos 里设为Landscape(横屏),但game.json写"portrait",微信客户端会强制竖屏渲染,导致画面拉伸变形。我遇到过一次,美术反馈“角色变胖了”,查了半天才发现是 orientation 错配。showStatusBar:设为false并非只是隐藏状态栏,而是告诉微信 runtime:“请把整个屏幕区域都交给我渲染”。如果设为true,微信会在顶部留出状态栏高度(通常 20px),但 Cocos 的cc.Canvas默认铺满整个window,结果是游戏画面被顶上去 20px,底部露出白边。解决方案是在game.json里设false,并在 Cocos 的Canvas组件里勾选fitHeight和fitWidth。customButton:这是微信右上角菜单的替代方案。微信官方禁止小游戏自行绘制右上角按钮(防止诱导点击),但允许通过customButton配置一个自定义按钮,点击后触发wx.showActionSheet。注意style.left/top是相对于屏幕左上角的像素值,单位是 px,不是 rpx。我曾把left设为"10rpx",结果按钮飞到屏幕外——微信不支持 rpx,只认 px。requiredPrivateInfos:这是微信 2023 年新增的隐私权限管控。如果你的游戏用了wx.getLocation,就必须在这里声明"getLocation",否则调用时直接返回errCode: 1001(权限未声明)。更坑的是,这个字段在微信开发者工具里不报错,只有真机测试才会触发,而且错误信息极不友好。
3.3 微信开发者工具:不是 IDE,而是你的第一道 QA 流程
微信开发者工具绝不能当成“模拟器”来用,它本质是一个带调试能力的微信客户端沙箱。它的核心价值在于暴露那些真机上难以复现的问题:
资源加载失败的静默降级:在开发者工具里,如果
wx.downloadFile下载图片失败,控制台会明确打印fail download file,但在真机上,Cocos 的cc.resources.load可能直接返回null,且不抛异常。解决方案是在cc.resources.load后加判空:cc.resources.load('textures/player', cc.Texture2D, (err, texture) => { if (err || !texture) { console.error('Failed to load player texture:', err); // fallback to default texture this.spriteFrame = this.defaultSpriteFrame; return; } this.spriteFrame = new cc.SpriteFrame(texture); });音频播放的兼容性黑洞:微信对
wx.createInnerAudioContext的支持极不稳定。iOS 15+ 要求首次播放必须由用户手势触发(如touchstart),否则静音。我在start()里自动播放背景音乐,结果 iOS 用户一打开就是静音。修复方案是监听cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, ...),等用户按任意键后再播放,或者更稳妥地,在主界面加一个“点击开始”按钮,点击后才初始化音频上下文。内存泄漏的可视化追踪:开发者工具的“Memory”面板能实时显示 JS Heap Size。我曾发现一个 Bug:每次进入关卡,内存增长 2MB,退出后不释放。用“Heap Snapshot”对比发现,
cc.Node的onDestroy回调里没清理this._eventHandlers数组,导致事件监听器一直持有节点引用。修复后,内存曲线变成平滑的锯齿状,峰值稳定在 15MB 以内(微信推荐上限为 20MB)。
实操心得:每天构建后,必须用开发者工具做三件事:1)切到“Network”面板,确认所有
res/xxx.png请求状态码为 200;2)切到“Console”,清空后操作一遍核心流程,确保无warn或error;3)切到“Memory”,反复进出关卡 5 次,观察内存是否回归基线。这三步花不了 5 分钟,但能避开 80% 的线上事故。
4. 实操全流程:从 Cocos Creator 到微信小游戏上线的 12 个关键步骤
4.1 步骤 1-3:环境准备与项目初始化(耗时约 30 分钟)
安装微信开发者工具最新版(v1.06.2309010):不要用旧版,新版修复了
wx.getFileSystemManager().readdir在 iOS 上返回空数组的 bug。安装时勾选“添加到 PATH”,方便命令行调用。安装 Cocos Creator 3.8.2(LTS 版本):官网下载页明确标注 “3.8.x is the Long Term Support version for WeChat Mini Game”。避坑:不要用 3.9.x,其
build流程对微信小游戏平台的支持尚不稳定,game.json生成有遗漏。新建 Cocos Creator 项目,选择“Empty Project”模板:不要选 “2D Sample” 或 “Game Template”,它们自带大量冗余脚本和资源,增加构建体积。创建后立即修改
project.json:{ "engine": "cocos2d-x", "modules": ["core", "2d"], "renderer": "webgl" }删除
assets/下所有示例资源,只保留assets/scripts/目录。
4.2 步骤 4-6:TypeScript 工程配置(耗时约 20 分钟)
初始化 TypeScript 配置:在项目根目录执行
tsc --init,生成tsconfig.json,关键修改项:{ "compilerOptions": { "target": "ES2019", "module": "ESNext", "lib": ["es2019", "dom"], "allowJs": false, "skipLibCheck": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "noImplicitAny": true, "strictNullChecks": true, "resolveJsonModule": true, "types": ["cocos"] }, "include": ["assets/**/*.ts"], "exclude": ["build/", "library/"] }注意:
"types": ["cocos"]是关键,它让 TS 能识别cc.Node、cc.Component等类型。Cocos Creator 3.8.2 自带@types/cocos,无需额外安装。创建全局类型声明文件:在
assets/scripts/typings/index.d.ts中添加:declare namespace wx { interface GetSystemInfoSyncResult { SDKVersion: string; pixelRatio: number; windowWidth: number; windowHeight: number; } function getSystemInfoSync(): GetSystemInfoSyncResult; function showAdaptiveBanner(options: { adUnitId: string }): void; }这样在 TS 文件里写
wx.getSystemInfoSync().pixelRatio,TS 编译器就能校验pixelRatio存在且为 number。配置 Cocos Creator 的 TS 编译:打开
编辑器 → 项目设置 → 脚本,勾选 “启用 TypeScript 支持”,设置 “TS 编译器路径” 为node_modules/typescript/lib/tsc.js(需先npm install typescript --save-dev),保存后重启编辑器。
4.3 步骤 7-9:构建与微信平台适配(耗时约 45 分钟)
设置项目定向:
项目设置 → 项目 → Orientation选Portrait(竖屏)或Landscape(横屏),必须与后续game.json一致。项目设置 → 构建发布 → 平台添加 “微信小游戏”,点击右侧齿轮图标,配置:AppID:填你小程序后台的 AppID(非公众号 ID)Title:小游戏标题(将显示在微信聊天窗口)Icon:120x120 png 图标(微信强制要求)Debug Mode:上线前必须取消勾选(否则会注入调试代码,增大体积)
构建前资源优化:Cocos Creator 的
Assets面板右键资源 →Texture→Compression设为WebP(比 PNG 小 40%),Max Size设为1024(避免超大纹理)。对audio资源,导出为mp3(比 wav 小 90%),采样率44100Hz,比特率64kbps。执行构建:点击
构建发布 → 构建,选择 “微信小游戏” 平台,输出路径设为build/wechatgame。构建完成后,检查build/wechatgame/目录:game.json是否存在且格式正确app.js文件大小是否 ≤ 1.2MB(用ls -lh app.js查看)res/目录下是否有textures/、scenes/等子目录
4.4 步骤 10-12:微信开发者工具调试与上线(耗时约 60 分钟)
导入项目到微信开发者工具:打开开发者工具 →
新建项目→ 选择build/wechatgame目录,AppID 填写同上,勾选 “不使用云服务”。首次导入会提示 “检测到 game.json,是否启用小游戏模式”,点 “确定”。真机调试与性能压测:
- 连接 iPhone,打开微信 →
发现 → 小程序 → 搜 ‘微信开发者工具’ → 扫码调试 - 在开发者工具 “调试器 → Console” 中输入
wx.getSystemInfoSync(),确认SDKVersion≥2.28.0(微信基础库最低要求) - 用 “调试器 → Network” 面板,刷新页面,确认所有
res/请求返回 200,无 404 - 用 “调试器 → Memory” 面板,反复进出主界面 5 次,内存峰值 ≤ 18MB
- 连接 iPhone,打开微信 →
提交审核与发布:
- 在开发者工具右上角
详情 → 本地设置,取消勾选 “开发环境” - 点击
上传,填写版本号(如1.0.1)、项目名称、描述 - 登录 微信公众平台 → 小游戏管理后台 → 版本管理 → 找到刚上传的版本 → 提交审核
- 审核通过后,在后台点击 “发布”,2 小时内全量生效
- 在开发者工具右上角
常见问题速查表:
问题现象 可能原因 解决方案 构建后 app.js体积 > 1.2MB未开启 WebP 压缩,或引入了 lodash等大型库用 rollup-plugin-terser压缩,或改用lodash-es按需引入真机白屏,控制台无报错 game.json中deviceOrientation与 Cocos 设置不一致检查 project.json的orientation和game.json的deviceOrientation是否匹配广告不显示, wx.showAdaptiveBanner返回errCode: 1004game.json未声明requiredPrivateInfos在 game.json中添加"requiredPrivateInfos": ["adaptBanner"]iOS 上音频无法播放 首次播放未由用户手势触发 在 touchstart事件回调中调用audioContext.play()微信开发者工具提示 “登录的微信号未绑定公众号” 用于登录开发者工具的微信账号未在小程序后台设置为管理员 登录 微信公众平台 → 小程序管理后台 → 成员管理 → 添加该微信号为管理员
5. 常见问题与排查技巧实录:那些没人告诉你的“幽灵 Bug”
5.1 “首屏加载慢”的真相:不是代码问题,是微信的资源加载策略
用户反馈“打开游戏要等 5 秒”,我第一反应是优化app.js,结果发现app.js只有 800KB,加载很快。用开发者工具 “Network” 面板分析,发现耗时最长的是res/scenes/main.scene.json(2.1MB)。原来微信小游戏的资源加载是串行的:先加载app.js,再按game.json里subContext的顺序加载scene、prefab、texture。main.scene.json里包含了所有 UI 节点的序列化数据,体积过大。
解决方案不是压缩 JSON(JSON 本身已最小化),而是拆分场景:
- 把主场景
main.scene拆成loading.scene(仅含进度条)和game.scene(含全部游戏逻辑) - 在
loading.scene的onLoad()里,用cc.resources.load异步加载game.scene:cc.resources.load('scenes/game', cc.SceneAsset, (err, sceneAsset) => { if (!err && sceneAsset) { cc.director.loadScene('game'); } }); - 同时在
game.json的subContext里,把game.scene的路径加入预加载列表。这样首屏只加载loading.scene(< 100KB),200ms 内显示进度条,再异步加载主场景,用户体验从“干等”变成“有反馈”。
5.2 “广告激励失效”的底层机制:微信的广告加载队列
wx.showAdaptiveBanner调用后,有时返回success,但广告不显示。查日志发现onLoad事件没触发。原因在于:微信的广告 SDK 是异步初始化的,wx.showAdaptiveBanner必须在wx.createBannerAd创建的广告实例onLoad之后才能调用。但 Cocos 的start()执行时,广告 SDK 可能还没 ready。
我的解决方法是封装一个广告管理器:
class AdManager { private _bannerAd: any = null; private _isReady = false; init() { this._bannerAd = wx.createBannerAd({ adUnitId: 'your-ad-id' }); this._bannerAd.onLoad(() => { this._isReady = true; console.log('Banner ad loaded'); }); this._bannerAd.onError((err) => { console.error('Banner ad error:', err); }); } show() { if (this._isReady) { this._bannerAd.show(); } else { // 延迟重试,避免阻塞主线程 setTimeout(() => this.show(), 100); } } }在GameController.start()里先调AdManager.init(),再在 UI 按钮点击事件里调AdManager.show()。这样确保广告加载完成后再展示,成功率从 60% 提升到 99%。
5.3 “iOS 黑屏”的终极归因:WebGL 上下文丢失
部分 iPhone 用户打开游戏是纯黑屏,控制台无报错。用 Safari 远程调试发现,cc.game.canvas的getContext('webgl')返回null。原因是 iOS 的 Safari 对 WebGL 上下文有严格限制:当页面被切换到后台(如用户按 home 键),WebGL 上下文会被销毁,前台恢复时不会自动重建。
Cocos Creator 3.8.2 的修复方案是监听visibilitychange事件:
document.addEventListener('visibilitychange', () => { if (document.hidden) { // 页面切到后台,暂停游戏 cc.game.pause(); } else { // 页面回到前台,恢复 WebGL 上下文 const gl = cc.game.canvas.getContext('webgl'); if (!gl) { // 重建上下文 cc.game.canvas.width = cc.game.canvas.width; cc.game.canvas.height = cc.game.canvas.height; cc.game.resume(); } } });这段代码必须放在app.js的最顶部,在 Cocos 引擎初始化之前执行。否则cc.game还没创建,cc.game.canvas是 undefined。
5.4 “审核被拒”的隐性雷区:隐私政策与用户协议
微信小游戏审核最近新增一条:必须在游戏内提供《隐私政策》和《用户协议》的入口,且内容需符合《常见类型移动互联网应用程序必要个人信息范围规定》。很多开发者以为在game.json里加个customButton就行,结果被拒。
正确做法:
- 在
assets/resources/ui/下创建privacy.html和terms.html,内容用纯 HTML 编写(微信不支持 iframe) - 在
customButton的click事件里,用wx.navigateToMiniProgram跳转到一个专门的小程序页面(该小程序只负责展示协议),或更简单地,用wx.openURL打开 H5 页面(需备案) - 在
game.json的requiredPrivateInfos里,必须声明"openLocation"、"getLocation"等实际用到的权限,未用的权限绝不能声明
我被拒过一次,原因是requiredPrivateInfos里写了"openLocation",但游戏里根本没调用wx.openLocation。微信审核机器人会静态扫描代码,发现声明了权限但没调用,就判定为“过度索取权限”。
我踩过的最大坑:上线前夜,发现 Android 用户反馈“点击开始按钮没反应”。查日志发现
cc.find('Canvas/StartBtn').on('click', ...)的回调没执行。最终定位到是StartBtn的Button组件里,Transition类型设为了Scale,但Pressed Scale值设成了0.8,导致按钮按下时缩得太小,触摸区域消失。把Pressed Scale改成0.95,问题解决。这种 UI 层面的 Bug,永远在真机上才暴露,模拟器里一切正常。
6. 后续演进:从一人工作室到可持续运营的思考
做完第一个项目,我意识到“开发完成”只是起点。微信小游戏的生命周期很短,平均用户留存率 7 日不到 15%,这意味着你必须在上线后 48 小时内,通过数据分析找到流失点。我用的方案是:在app.js入口处,插入极简的埋点 SDK(基于wx.reportAnalytics),只记录三个事件:game_start(启动)、level_complete(通关)、ad_show(广告展示)。数据导出到 Excel,用透视表分析:如果level_complete事件数远低于game_start,说明第一关太难;如果ad_show在level_complete后 10 秒内集中爆发,说明激励广告位置太靠后。
技术上,我正把项目迁移到 Cocos Creator 3.9,尝试用Worker线程处理物理计算,把主线程解放出来做渲染。但迁移不是升级版本那么简单——3.9 的build流程重构了game.json的生成逻辑,customButton配置现在必须在project.json的wechatgame字段里声明,而不是手动编辑build/wechatgame/game.json。这意味着自动化部署脚本要重写。
最后分享一个小技巧:微信小游戏的wx.setStorageSync有 10MB 总容量限制,但wx.getFileSystemManager().writeFile的本地文件系统是独立的,无容量限制。我把玩家存档数据(JSON 格式)用writeFile存到wx.env.USER_DATA_PATH,只用setStorageSync存一个 1KB 的索引文件,记录当前存档版本号和文件名。这样既规避了容量瓶颈,又保持了数据一致性。
这个项目教会我的不是“怎么用 Cocos”,而是“怎么在一个封闭生态里,用工程化思维把不确定性降到最低”。微信小游戏不是技术秀场,它是产品、运营、技术三者的咬合齿轮。一人工作室的优势,从来不是“什么都能干”,而是“每个决策都直面结果”。当你亲手把game.json里一个字段改对,看到真机上广告正常展示的那一刻,那种确定性带来的踏实感,是任何框架文档都给不了的。