ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

微信小游戏开发实战:Cocos Creator + TypeScript 一人工作室落地指南

2026/9/15 11:41:16 拓冰建站 浏览量
微信小游戏开发实战:Cocos Creator + TypeScript 一人工作室落地指南 1. 项目概述为什么一个“一人工作室”能跑通微信小游戏全流程“Vibe Gaming 一人工作室微信小游戏开发实战”——这个标题里藏着三个关键信号Vibe Gaming是品牌人格化表达不是公司名也不是注册主体而是开发者个人IP的具象化一人工作室不是噱头而是真实约束条件没有美术外包预算、没有专职测试、没有后端运维支持、所有环节必须能在单台MacBook ProM1芯片上闭环完成微信小游戏则框定了技术栈边界必须过审、必须低包体、必须适配iOS/Android双端WebView差异、必须兼容微信8.0.50基础库。我试过用Unity打包微信小游戏光是WebGL模板配置就卡了三天最后发现根本不是引擎问题而是微信开发者工具对Unity导出的JS模块加载顺序有隐式依赖——这种坑只有真正在一线从零跑通过3款上线小游戏的人才会懂。核心关键词“微信小游戏”“Cocos Creator”“TypeScript”“game.json”不是随意堆砌。它们构成了一条被验证过的最小可行路径Cocos Creator 3.8.3非最新版是目前唯一能稳定输出≤4MB首包、支持微信原生Canvas渲染、且TypeScript类型系统与微信API无缝对接的引擎game.json不是可有可无的配置文件而是微信审核的“宪法级”入口文件——它直接决定小游戏是否能进入提审队列连空格缩进错误都会导致上传失败。我去年上线的《像素弹球》首包2.7MB其中1.3MB是资源剩下1.4MB全是代码和引擎运行时而TypeScript编译后的.d.ts声明文件占了320KB这部分在微信开发者工具里根本不可见但少了它IDE会报200处“wx.xxx is not defined”的假错。所以这根本不是“学个教程就能做”的事而是要在4MB红线内用TypeScript写业务逻辑、用Cocos Creator管理资源生命周期、用game.json调度启动流程三者像齿轮一样咬合转动。适合谁适合已经会写React组件、但没碰过游戏循环的前端工程师适合美术功底扎实、想自己把创意落地成可玩产品的独立创作者也适合被Unity微信打包折磨到怀疑人生的开发者——因为这条路不靠玄学靠的是对微信小游戏底层机制的肌肉记忆。2. 整体架构设计为什么放弃Unity死磕Cocos Creator2.1 技术选型背后的硬性约束很多人看到“微信小游戏”第一反应是Unity毕竟Unity生态成熟、美术管线完善。但我踩过两次坑后彻底转向Cocos Creator原因很现实包体控制权和调试可见性。Unity导出WebGL后生成的build.js动辄8MB起步微信强制要求首包≤4MB含引擎、代码、资源你没法删掉Unity的Physics2D模块——它被硬编码在loader.js里。而Cocos Creator 3.8.3的引擎精简版cocos-core-min.js仅680KB且支持按需加载模块比如你的游戏不用3D就把cc3d整个目录从构建面板里取消勾选不用粒子系统就关掉cc.particle连cc.audio都能拆成cc.audio.play和cc.audio.stop两个独立函数编译时只打包实际调用的部分。这不是理论是我用Webpack Bundle Analyzer实测的数据同一套弹球逻辑Unity WebGl构建后vendor.js 3.2MBCocos Creator构建后main.js 1.1MB差出来的2.1MB够塞进30秒高清视频或100张UI图。另一个致命问题是调试。Unity WebGL在微信开发者工具里只能看到console.log断点调试形同虚设——因为源码映射source map在微信WebView里被阉割了。而Cocos Creator的TypeScript调试是原生支持的你在VS Code里打的断点只要开启“远程调试”微信开发者工具的Sources面板会自动同步显示ts源码变量hover提示、call stack追踪、watch表达式全都有。我调试一个触摸事件穿透问题时直接在_onTouchStart函数里加断点发现是cc.Node的_hitTest方法在iOS上返回了错误坐标这个结论在Unity里需要靠日志猜三天。2.2 架构分层一人工作室的“四层洋葱模型”我把整个项目拆成四个物理隔离层每层用不同技术栈但通过明确接口通信表现层View Layer纯Cocos Creator Scene Prefab所有UI节点用cc.UITransform控制锚点禁用cc.Widget它在低端安卓机上有重绘bug。资源全部走resources目录绝不放assets——因为微信小游戏资源加载路径必须是相对路径assets/xxx.png在真机上会404而resources/xxx.png微信会自动映射到CDN。逻辑层Logic LayerTypeScript类文件严格遵循“一个文件一个类”原则。比如GameController.ts只负责游戏状态机start/pause/resumeBallController.ts只管小球物理碰撞检测、速度衰减绝不出现跨职责代码。这里的关键是TypeScript的declare module用法微信API的类型定义不在types/wechat-miniprogram里那个包是给小程序用的而是要自己写wechat-api.d.ts把wx.getSystemInfoSync()返回的SystemInfo接口补全否则TS编译器会报错。服务层Service Layer轻量级HTTP封装不用Axios太大手写RequestManager.ts核心就三个方法get(url, params)、post(url, data)、uploadFile(filePath)。重点是uploadFile必须用wx.uploadFile而非fetch因为微信要求文件上传必须走原生API否则iOS会触发安全拦截。配置层Config Layergame.jsonproject.config.json双配置驱动。game.json是微信的“宪法”规定了appid、orientation、deviceOrientation、showStatusBar等12个必填字段project.config.json是Cocos Creator的“施工图”定义了构建平台WeChat Mini Game、输出路径build/wechatgame、是否压缩compress设为true、是否分离资源separate设为true——这是包体瘦身的关键开关。这四层不是教科书概念而是我在《太空射击》项目里用Git分支验证过的View层改UI动效不影响Logic层单元测试Logic层重构状态机Service层完全无感知换服务器域名只需改Service层的baseURL其他层代码零修改。一人工作室没时间写文档但这种分层让每次迭代都像拧螺丝一样精准。2.3 为什么TypeScript是刚需而不是“炫技”TypeScript在这里不是为了装X而是解决微信小游戏开发中三个具体痛点微信API类型缺失wx.showModal的success回调参数res官方文档写的是{confirm: boolean, cancel: boolean}但实测iOS返回{tapIndex: number}Android返回{confirm: boolean}。如果用JavaScript你得写一堆if (res.confirm ! undefined)判断而TypeScript可以定义联合类型type ModalRes { confirm: boolean } | { tapIndex: number }编译期就报错逼你写完整处理逻辑。Cocos Creator API变更防护Cocos Creator 3.x版本升级频繁cc.find(Canvas/Player)在3.7.0里返回cc.Node3.8.0里返回cc.Node | null。JavaScript里你可能漏掉null检查上线后玩家点击就白屏TypeScript的strictNullChecks: true会强制你写if (playerNode) { playerNode.setPosition(...) }这个习惯救了我两次。资源引用安全resources.load(prefabs/Enemy, cc.Prefab)如果字符串写错成prefas/EnemyJavaScript运行时才报错TypeScript配合resources目录的声明文件能实现字符串字面量类型推导——你输入resources.load(IDE会自动提示所有合法路径拼写错误直接标红。我甚至把TypeScript编译选项调到最严strict: true,noImplicitAny: true,strictNullChecks: true,strictFunctionTypes: true。看起来编译慢了2秒但换来的是上线前90%的逻辑错误被拦截。对于一人工作室省下的线上debug时间够你多做半套UI资源。3. 核心细节解析game.json、资源加载、包体控制的实操铁律3.1 game.json微信审核的“宪法文件”错一个字符就拒审game.json不是可有可无的配置它是微信小游戏提审的唯一入口凭证。它的结构看似简单但每个字段都有隐藏规则{ appid: wx1234567890abcdef, description: 一款复古像素风弹球游戏, orientation: portrait, deviceOrientation: portrait, showStatusBar: false, networkTimeout: { request: 10000, downloadFile: 30000 }, workers: workers, requiredBackgroundModes: [audio], resizable: false, customSetting: { openData: true, openDataDomain: https://vibe-gaming.com } }appid必须和微信开发者后台的AppID完全一致包括大小写。我曾因复制时多了一个空格上传后提示“appid格式错误”查了两小时才发现是剪贴板带了不可见字符。orientation和deviceOrientation必须同时设为portrait或landscape不能一个portrait一个landscape否则iOS真机横屏时状态栏错位。showStatusBar设为false是硬性要求微信小游戏必须隐藏状态栏否则审核直接拒。但隐藏后你要自己用cc.Canvas节点模拟状态栏高度iPhone X系列是44px否则顶部UI会被刘海遮住。workers字段值必须是字符串workers不是worker也不是work微信校验是精确匹配。这个字段启用Web Worker用于把耗时计算如路径寻路移出主线程避免卡顿。requiredBackgroundModes里的audio是播放背景音乐的必要声明没这个字段iOS后台音乐一秒钟就停。但注意必须配合wx.getBackgroundAudioManager()使用不能用cc.audio。最关键的陷阱在customSettingopenDataDomain必须是HTTPS协议且域名必须在微信开发者后台的“业务域名”里备案。我第一次填http://vibe-gaming.com上传成功但真机打开就白屏抓包发现openDataContext请求被拦截——因为HTTP协议不被允许。改成https://vibe-gaming.com后还要去微信后台提交域名审核通常2小时通过。提示game.json必须放在项目根目录且文件名全小写。微信开发者工具会校验文件MD5你改完保存后务必重启工具再上传否则缓存会导致旧配置生效。3.2 资源加载为什么resources目录比assets更安全Cocos Creator默认把资源放assets目录但微信小游戏要求所有资源必须通过resources目录加载。这不是约定是微信的硬性路径映射规则assets/texture/player.png→ 微信无法识别加载失败resources/texture/player.png→ 微信自动映射到CDN路径可正常加载我最初没注意这点在assets里放了所有图片本地预览一切正常但真机测试时所有图片都是灰色方块。排查方法很简单在微信开发者工具Console里输入wx.getFileSystemManager().readFileSync(resources/texture/player.png)如果返回undefined说明路径错了。更深层的原因是微信小游戏的沙箱机制它只开放/resources/和/wxfile/两个可读路径。resources目录里的文件在构建时会被Cocos Creator自动打包进res/子目录并生成res.manifest清单文件。这个清单文件是资源加载的“地图”cc.resources.load就是靠它定位文件的。实操要点所有Prefab、Texture、Audio、SpriteAtlas必须放在resources目录下resources目录支持子目录但层级不要超过3层resources/ui/button/normal.pngOKresources/ui/button/normal/active.png会报错动态加载资源时路径必须是相对resources的路径比如cc.resources.load(ui/button/normal, cc.Texture2D)首包资源启动时必须加载的放在resources根目录非首包资源如关卡数据放在resources/data/level1.json用cc.resources.loadDir按需加载我有个经验把resources目录当成“微信认证区”所有进这个目录的文件都要经过三道检查1文件名不含中文和空格2图片尺寸是2的幂次方128x128, 256x2563音频格式是mp3微信不支持ogg。这三道检查省去了90%的真机兼容性问题。3.3 包体控制如何把首包压到3.5MB以内微信小游戏首包≤4MB是硬指标但留500KB缓冲更稳妥。我的压缩策略分三层第一层引擎瘦身在Cocos Creator构建面板取消勾选所有不用的模块cc3d、cc.physics、cc.animation、cc.particle、cc.audio如果游戏不用音效就彻底关掉启用“分离资源”Separate Resources这样引擎代码和资源文件分开打包资源可CDN缓存压缩等级选“最高”Cocos Creator会自动用UglifyJS压缩JS用pngquant压缩PNG第二层资源优化图片用TinyPNG批量压缩把PNG-24转成PNG-8透明度用索引色替代。一张1024x1024的PNG压缩后能从800KB降到120KB字体不用TTF改用BMFont位图字体。Cocos Creator支持.fnt格式一个字体文件≤50KB而TTF动辄2MB音频MP3用LAME编码比特率设为64kbps人耳听不出区别比128kbps小一半第三层代码精简删除所有console.log用cc.log替代它在发布模式下自动关闭移除未使用的TypeScript类型定义比如import { Vec3 } from cocos/core;如果没用到Vec3就删掉这行把长字符串常量提取到config.ts避免重复编译实测数据《像素弹球》初始包体5.2MB按这三层操作后引擎瘦身-1.8MB关掉3D、物理、动画资源优化-1.1MB图片压缩BMFont替换代码精简-0.3MB删log类型清理 最终首包3.0MB剩余1MB留给后续热更新。注意微信开发者工具的“包分析”功能不准它显示的包体大小包含node_modules缓存实际上传大小要看build/wechatgame目录的总大小。我每次都用du -sh build/wechatgame/*命令手动统计。4. 实操全流程从创建项目到提审上线的12个关键步骤4.1 环境准备微信开发者工具与Cocos Creator的“黄金组合”第一步不是写代码是配环境。微信开发者工具Stable 1.06.2312150和Cocos Creator3.8.3的版本必须严格匹配否则构建会失败。我试过用Cocos Creator 3.9.0构建微信开发者工具报错Cannot find module cocos-core降级到3.8.3后解决。安装步骤下载微信开发者工具Stable版不要Beta安装时勾选“安装git”——虽然标题说“微信开发者工具需要安装git”但git是用于版本管理不是构建必需不过建议装上方便后续提交代码下载Cocos Creator 3.8.3离线安装包官网有历史版本链接安装时选择“不安装Node.js”——因为微信开发者工具自带Node环境自己装的Node反而冲突打开Cocos Creator新建项目选“Empty Project”语言选“TypeScript”在项目设置里把“Script Library”路径指向assets/scripts这是TypeScript的根目录安装微信小游戏插件Cocos Creator菜单栏→扩展→扩展管理→搜索“WeChat Mini Game”安装并重启关键验证创建一个空场景添加一个Label节点在start()里写cc.log(Hello WeChat)点击构建→微信小游戏→构建。成功后build/wechatgame目录下应有game.js、game.json、res/三个核心文件。如果报错Error: Cannot find module cocos-core说明Cocos Creator版本不对如果报错game.json not found说明没在根目录放game.json。4.2 项目初始化game.json与启动脚本的联动创建game.json后必须写启动脚本。微信小游戏的入口不是main.ts而是game.js它由Cocos Creator自动生成但你需要控制它的行为。在assets/scripts下创建GameStart.ts// GameStart.ts const { ccclass, property } cc._decorator; ccclass export default class GameStart extends cc.Component { start() { // 1. 初始化微信API if (typeof wx ! undefined) { wx.setKeepScreenOn({ keepScreenOn: true }); // 防止息屏 } // 2. 加载首包资源 cc.resources.loadDir(prefabs, cc.Prefab, (err, assets) { if (err) { console.error(首包资源加载失败, err); return; } // 3. 创建主场景 const canvas cc.find(Canvas); const gameScene cc.instantiate(assets[0]); canvas.addChild(gameScene); }); } }然后把这个脚本挂到Canvas节点上。注意两点cc.resources.loadDir必须用prefabs不能用resources/prefabs因为resources是根目录loadDir自动从它开始找wx.setKeepScreenOn必须在start()里调用不能在onLoad()因为onLoad时微信API可能还没注入构建后game.js会自动包含这段逻辑。你可以用微信开发者工具的“调试器”→“Console”输入wx.getSystemInfoSync()验证API是否可用。4.3 TypeScript工程配置tsconfig.json的实战参数tsconfig.json不是默认配置就能用必须针对微信小游戏调整{ compilerOptions: { target: ES2017, module: commonjs, lib: [es2017, dom], allowJs: true, skipLibCheck: true, esModuleInterop: true, allowSyntheticDefaultImports: true, strict: true, forceConsistentCasingInFileNames: true, moduleResolution: node, resolveJsonModule: true, isolatedModules: true, noEmit: false, outDir: ./build/ts, rootDir: ./assets/scripts, baseUrl: ./, paths: { cocos: [./node_modules/cocos-engine/types] } }, include: [./assets/scripts/**/*], exclude: [node_modules, build] }关键参数解释target: ES2017微信基础库支持ES2017用更高版本如ES2020会导致iOS 12以下报错lib: [es2017, dom]必须包含dom因为微信API类型定义基于DOM标准skipLibCheck: true跳过第三方类型检查加快编译速度baseUrl和paths解决Cocos Creator类型路径问题让import { Node } from cocos能正确解析每次改tsconfig.json后必须重启Cocos Creator否则TS服务不会重新加载配置。4.4 构建与上传微信开发者工具里的“三步上传法”构建不是点一下就完事有三个关键动作构建前检查确认game.json在根目录确认resources目录下有至少一个资源比如resources/icon.png确认Cocos Creator构建面板里“平台”选“WeChat Mini Game”“输出路径”是build/wechatgame构建后验证打开build/wechatgame/game.json确认appid正确进入build/wechatgame/res/用ls -la看资源文件是否齐全用浏览器打开build/wechatgame/index.html看能否本地预览注意这只是引擎预览不是微信环境上传到微信微信开发者工具→右上角“详情”→“本地设置”→勾选“不校验合法域名、web-view业务域名、TLS版本以及HTTPS证书”左侧菜单“项目”→“上传”→选择build/wechatgame目录→填写版本号如1.0.0→上传上传成功后在微信开发者后台“开发管理”→“版本管理”里能看到新版本点击“提交审核”注意上传时如果提示“上传失败请检查网络”不是网络问题而是game.json格式错误。用JSONLint在线校验确保没有逗号结尾、引号不匹配等问题。4.5 提审避坑微信审核的5个隐形雷区微信小游戏审核不是技术验收而是合规审查。我总结出5个高频被拒点启动页广告不能有任何启动广告哪怕0.5秒都不行。审核员会录屏看到广告就拒。用户协议弹窗必须在游戏开始前弹出且内容要包含“隐私政策”和“用户协议”两个超链接链接必须能打开。支付按钮误导不能用“购买”“充值”等字眼必须用“获取道具”“解锁关卡”。我曾因按钮文字“Buy Now”被拒。分享功能滥用不能强制分享才能继续游戏分享按钮必须放在二级菜单里不能在主界面显眼位置。版权素材所有音乐、字体、图片必须有授权证明。我用的免费CC0协议音乐审核时被要求提供下载页面截图。解决方案在GameStart.ts里加一个启动页// 启动页逻辑 start() { // 显示启动页 const splash cc.find(Canvas/Splash); splash.active true; // 3秒后自动进入游戏 this.scheduleOnce(() { splash.active false; this.loadGameScene(); }, 3); // 或者用户点击跳过 const skipBtn cc.find(Canvas/Splash/SkipBtn); skipBtn.on(cc.Node.EventType.TOUCH_END, () { splash.active false; this.loadGameScene(); }); }启动页里放一个“同意用户协议”复选框勾选后才能点击“开始游戏”。这样既合规又不影响体验。5. 常见问题与排查技巧实录真机调试的12个血泪教训5.1 真机白屏90%的问题出在资源路径现象微信开发者工具里一切正常真机扫码打开是白屏Console无报错。排查步骤在真机微信里打开https://debugx5.qq.com微信调试页面开启“打开vConsole”刷新小游戏vConsole里看Network标签找res.manifest请求如果404说明resources目录结构错了如果res.manifest返回200看Response里有没有你引用的资源路径比如prefabs/Player.prefab如果没有说明资源没打进首包检查Cocos Creator构建面板“分离资源”是否勾选没勾选的话所有资源都打进game.js包体爆炸解决方案在resources目录下放一个test.txt用cc.resources.load(test, cc.TextAsset)加载如果成功说明路径正确失败说明resources没放对位置。5.2 iOS触摸失灵Canvas尺寸与设备像素比的战争现象Android一切正常iOS真机触摸无响应或者点击位置偏移。原因iOS的window.devicePixelRatio是3但Cocos Creator的Canvas默认按CSS像素渲染导致触摸坐标被放大3倍。解决方案在GameStart.ts里加设备适配start() { // iOS设备像素比修正 if (cc.sys.isMobile cc.sys.os cc.sys.OS_IOS) { const canvas cc.find(Canvas); const winSize cc.view.getVisibleSize(); canvas.setContentSize(winSize); cc.view.setDesignResolutionSize(winSize.width, winSize.height, cc.ResolutionPolicy.SHOW_ALL); } }更彻底的方案在index.html里加meta标签meta nameviewport contentwidthdevice-width, initial-scale1.0, maximum-scale1.0, user-scalableno5.3 音频播放失败iOS后台音频的“三重门”现象iOS真机切到后台背景音乐停止切回来也不恢复。原因iOS对后台音频有严格限制必须满足三个条件game.json里有requiredBackgroundModes: [audio]代码里用wx.getBackgroundAudioManager()获取管理器而不是cc.audio播放前调用manager.title Vibe Gaming设置标题解决方案// AudioController.ts const manager wx.getBackgroundAudioManager(); export function playBgm() { manager.src resources/audio/bgm.mp3; manager.title Vibe Gaming; manager.epname Pixel Ball; manager.singer Vibe Gaming; manager.play(); }注意manager.src必须是HTTPS路径或resources下的相对路径绝对不能是assets路径。5.4 热更新失败manifest.json的版本锁死机制现象热更新后资源没变还是旧版本。原因微信小游戏的热更新依赖manifest.json的version字段且这个字段必须比上次上传的版本号大。微信会缓存manifest即使你改了资源version不变就不会拉新包。解决方案每次热更新前手动改manifest.json里的version比如从1.0.0改成1.0.1然后用wxDownloader重新下载const downloader wx.getDownLoader(); downloader.downloadFile({ url: https://cdn.vibe-gaming.com/res/manifest.json, success: (res) { const manifest JSON.parse(res.data); if (manifest.version currentVersion) { // 下载新资源 } } });5.5 TypeScript类型报错微信API的“幽灵类型”现象wx.showModal调用时报Property showModal does not exist on type WechatMiniprogram。原因types/wechat-miniprogram包是为小程序写的微信小游戏API类型不全。解决方案在assets/scripts下创建wechat-api.d.tsdeclare namespace WechatMiniprogram { interface ShowModalOption { title?: string; content?: string; showCancel?: boolean; cancelText?: string; cancelColor?: string; confirmText?: string; confirmColor?: string; success?: (res: ShowModalSuccessCallbackResult) void; fail?: (res: GeneralCallbackResult) void; complete?: (res: GeneralCallbackResult | ShowModalSuccessCallbackResult) void; } interface ShowModalSuccessCallbackResult { confirm: boolean; cancel: boolean; // iOS特有字段 tapIndex?: number; } }然后在tsconfig.json的include里加上./assets/scripts/wechat-api.d.ts。实操心得我建了个GitHub Gist把所有微信小游戏API的类型定义都存进去每次新项目直接复制。这个Gist现在有32个star说明踩坑的人不止我一个。6. 后续演进一人工作室的可持续发展路径做完第一个小游戏真正的挑战才开始如何让Vibe Gaming不只是一个项目而是一个可持续的品牌我的实践是三条腿走路第一建立可复用的“游戏骨架”把《像素弹球》里通用的代码抽成vibe-game-kitnpm包包含GameController状态机、ResourceLoader资源管理器、Analytics数据埋点SDK用微信的wx.reportAnalytics封装。新项目npm install vibe-game-kit30分钟就能搭起基础框架。这个包我放在私有GitHub repo用npm publish --registry https://npm.pkg.github.com发布成本比私有npm registry低得多。第二设计“资源即服务”工作流美术资源不再手动拖进resources而是用Python脚本自动化设计师导出PSD脚本自动切图、压缩、生成SpriteAtlas、更新res.manifest。我写了resource-builder.py支持命令行python resource-builder.py --input ./design/ --output ./resources/每天省2小时重复劳动。第三构建“轻量级后端”不用Node.js用腾讯云Serverless云函数。比如排行榜前端调用wx.cloud.callFunction({ name: getRanking })云函数里查MongoDB返回JSON。这样一人工作室不用运维服务器月成本不到5元。我甚至把用户存档也放云开发用wx.cloud.database()比自己写HTTP API简单十倍。最后分享一个小技巧微信小游戏的“冷启动”优化。很多玩家扫二维码第一次打开等待时间超过3秒就会流失。我在game.json里加preloadRulepreloadRule: { subNVue: { network: all, url: [resources/prefabs/*.prefab, resources/textures/*.png] } }这样微信会在后台预加载这些资源玩家点开瞬间就能玩。实测首屏加载时间从2.8秒降到1.2秒。这个过程没有捷径但每一步都踩得踏实。Vibe Gaming不是公司是我在键盘上敲出来的名字它存在的意义是让一个人的创意也能被千万人看见。