# 报恩榴莲 - 完整项目开发指南 > 从零基础到微信小游戏上架的完整开发流程文档 --- ## 📋 目录 1. [项目概述](#一项目概述) 2. [开发环境准备](#二开发环境准备) 3. [项目结构说明](#三项目结构说明) 4. [快速开始(5分钟运行)](#四快速开始5分钟运行) 5. [核心系统详解](#五核心系统详解) 6. [美术资源替换](#六美术资源替换) 7. [音频资源配置](#七音频资源配置) 8. [微信小游戏集成](#八微信小游戏集成) 9. [调试与测试](#九调试与测试) 10. [性能优化](#十性能优化) 11. [打包发布](#十一打包发布) 12. [常见问题FAQ](#十二常见问题faq) --- ## 一、项目概述 ### 1.1 游戏简介 **报恩榴莲**是一款三三合成休闲小游戏,玩家通过点击屏幕掉落水果,三个相同等级的水果自动合成为更高等级的水果,最终目标是合成传说中的"报恩榴莲"来投喂Boss。 - **平台**:微信小游戏 - **引擎**:Cocos Creator 3.8.x + TypeScript - **类型**:休闲 / 合成 / 物理模拟 - **时长**:单局 1-3 分钟 - **变现**:纯广告(激励视频 + 插屏) ### 1.2 核心玩法 ``` 1. 点击屏幕顶部 → 水果从指定X坐标掉落 2. 三个相同等级水果接触 → 自动合成为高一级水果 3. 合成高等级水果 → Boss饱食度增加 4. Boss饱食度满 → 通关,进入下一关 5. 水果超过警戒线 → 失败,可选择看广告复活 ``` ### 1.3 技术亮点 - ✅ **纯逻辑层分离**:MergeCore 无任何 Cocos 依赖,可独立单元测试 - ✅ **组件化架构**:Fruit、BossManager、GoldenLegendEffect 等独立组件 - ✅ **单例模式**:AudioManager、SaveManager 全局唯一实例 - ✅ **对象池优化**:音效 AudioSource 复用,避免频繁创建销毁 - ✅ **异步加载**:音频资源按需加载,减少首屏加载时间 - ✅ **存档系统**:localStorage 持久化,支持断点续玩 --- ## 二、开发环境准备 ### 2.1 必需软件 | 软件 | 版本要求 | 下载地址 | |------|----------|----------| | Cocos Creator | 3.8.0+ | https://www.cocos.com/creator-download | | Node.js | 14.x+ | https://nodejs.org/ | | VS Code | 最新版 | https://code.visualstudio.com/ | | 微信开发者工具 | 稳定版 | https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html | ### 2.2 Cocos Creator 安装 1. 下载 Cocos Creator 3.8.x 安装包 2. 运行安装程序,选择安装路径 3. 首次启动需登录 Cocos 账号(可使用 GitHub 快捷登录) 4. 在 Dashboard 中确认版本号 ≥ 3.8.0 ### 2.3 VS Code 插件推荐 安装以下插件提升开发效率: - **Cocos Creator API** - Cocos API 智能提示 - **TypeScript Importer** - 自动导入 TS 模块 - **ESLint** - 代码规范检查 - **Prettier** - 代码格式化 ### 2.4 环境变量配置(可选) 如果需要调用外部 API(如排行榜),在项目根目录创建 `.env` 文件: ```bash API_BASE_URL=https://your-api.com APP_ID=wx1234567890abcdef ``` --- ## 三、项目结构说明 ### 3.1 目录树 ``` cocos-prototype/ ├── assets/ # ★ 资源目录(Cocos 识别) │ ├── scripts/ # TypeScript 脚本 │ │ ├── config/ # 配置文件 │ │ │ └── GameConfig.ts # 游戏数值配置(水果链、关卡、物理参数) │ │ ├── core/ # 核心系统 │ │ │ ├── GameManager.ts # 游戏主控制器 │ │ │ ├── MergeCore.ts # 纯逻辑合成引擎 │ │ │ ├── AudioManager.ts # 音频管理器 │ │ │ ├── SaveManager.ts # 存档管理器 │ │ │ └── AdManager.ts # 广告管理器 │ │ ├── components/ # 组件脚本 │ │ │ ├── Fruit.ts # 水果组件 │ │ │ ├── BossManager.ts # Boss管理组件 │ │ │ └── GoldenLegendEffect.ts # 金色传说特效组件 │ │ └── ui/ # UI脚本 │ │ ├── MainMenuUI.ts # 主菜单 │ │ ├── ResultPanel.ts # 结算面板 │ │ └── CollectionUI.ts # 图鉴界面 │ ├── textures/ # 图片资源 │ │ ├── fruits/ # 9个水果精灵 │ │ ├── boss/ # Boss图片 │ │ ├── ui/ # UI元素 │ │ └── effects/ # 特效图片 │ ├── audio/ # 音频资源 │ │ ├── bgm_*.mp3 # BGM │ │ ├── sfx_*.mp3 # 音效 │ │ └── voice_*.mp3 # 语音 │ ├── prefabs/ # 预制体 │ │ ├── Fruit.prefab # 水果预制体 │ │ └── Boss.prefab # Boss预制体 │ └── scenes/ # 场景文件 │ └── MainGame.scene # 主游戏场景 │ ├── settings/ # 项目设置 │ └── v2/packages/... # Cocos 内部配置 │ ├── build/ # 构建输出(自动生成) │ ├── SCENE_SETUP_GUIDE.md # 场景搭建指南 ├── PROJECT_GUIDE.md # 本文档 └── README.md # 快速入门 ``` ### 3.2 关键文件职责 | 文件 | 职责 | 修改频率 | |------|------|----------| | GameConfig.ts | 所有数值配置(水果属性、关卡数据、物理参数) | 低(调优时修改) | | GameManager.ts | 游戏流程控制、状态切换 | 中 | | MergeCore.ts | 合成逻辑核心 | 极低(稳定后不改) | | AudioManager.ts | 音频播放管理 | 低 | | SaveManager.ts | 存档读写 | 极低 | | AdManager.ts | 广告SDK封装 | 低 | | Fruit.ts | 水果动画表现 | 中 | | BossManager.ts | Boss饱食度逻辑 | 低 | --- ## 四、快速开始(5分钟运行) ### 步骤 1:导入项目 1. 打开 Cocos Creator 3.8 2. 点击 **"打开其他项目"** 3. 选择 `cocos-prototype` 文件夹 4. 等待资源导入完成(首次约 1-2 分钟) ### 步骤 2:创建场景 1. 在资源管理器中右键 `assets/scenes/` → 新建 → Scene 2. 命名为 `MainGame` 3. 双击打开场景编辑 ### 步骤 3:搭建场景节点 按照 `SCENE_SETUP_GUIDE.md` 中的节点层级结构创建节点: **最简版本(仅测试核心玩法):** ``` Canvas └── GameScene ├── GameContainer (Node) │ ├── LeftWall (Node + BoxCollider2D) │ ├── RightWall (Node + BoxCollider2D) │ ├── BottomWall (Node + BoxCollider2D) │ └── FruitLayer (Node) ├── DropArea (Node + UITransform) └── GameManagerNode (空节点,挂载 GameManager.ts) ``` ### 步骤 4:制作 Fruit 预制体 1. 右键 `assets/prefabs/` → 新建 → Prefab → 命名 `Fruit` 2. 双击进入预制体编辑 3. 创建节点结构: ``` FruitRoot ├── FruitSprite (Sprite) ├── CircleCollider2D ├── RigidBody2D (Type=Dynamic, Fixed Rotation=true) └── Fruit.ts (脚本组件) ``` 4. 为 FruitSprite 指定一个临时图片(可用 Cocos 默认 spriteFrame) 5. 保存预制体 ### 步骤 5:绑定 GameManager 属性 1. 在场景中选中 `GameManagerNode` 2. 在属性检查器中点击 **"添加组件"** → 搜索 `GameManager` 3. 将以下节点拖拽到对应属性槽: - `gameContainer` → GameContainer 节点 - `dropArea` → DropArea 节点 - `fruitLayer` → FruitLayer 节点 - `fruitPrefab` → Fruit.prefab 资源 4. 暂时留空其他属性(Boss、UI等后续补充) ### 步骤 6:运行测试 1. 点击编辑器顶部的 **"预览"** 按钮(或按 Ctrl+P) 2. 浏览器自动打开游戏页面 3. 点击 DropArea 区域(场景顶部) 4. 观察水果掉落和物理碰撞 **如果看到水果掉落并堆积在底部,恭喜!核心玩法已跑通!** --- ## 五、核心系统详解 ### 5.1 MergeCore 合成引擎 **位置**:`assets/scripts/core/MergeCore.ts` **设计理念**:纯逻辑层,无任何 Cocos 依赖,便于单元测试和移植。 **核心数据结构**: ```typescript interface FruitData { id: string; // 唯一ID(如 "fruit_001") level: number; // 等级(1-9) x: number; // X坐标 y: number; // Y坐标 } ``` **合成算法流程**: ``` tryMerge() 被调用(通常在 Fruit 落地静止后) ↓ 遍历所有水果,按 level 分组 ↓ 对每个等级,检查数量是否 ≥ 3 ↓ 如果是,取出3个水果(优先取高等级) ↓ 计算3个水果的质心坐标(centroid) ↓ 生成 MergeEvent 事件: - removeIds: 要删除的3个水果ID - newLevel: 新水果等级(原等级+1) - newX, newY: 新水果位置(质心) - score: 得分 = 3^(level-1) × comboMultiplier ↓ 返回 MergeEvent[] 数组 ``` **Combo 连击系统**: ```typescript // 在 GameManager 中维护 private _comboCount: number = 0; private _lastMergeTime: number = 0; private readonly COMBO_WINDOW = 2.0; // 2秒窗口 handleMergeEvent(event: MergeEvent) { const now = Date.now() / 1000; if (now - this._lastMergeTime < this.COMBO_WINDOW) { this._comboCount++; } else { this._comboCount = 1; } this._lastMergeTime = now; // 根据连击数获取倍率 const multiplier = getComboConfig(this._comboCount)?.multiplier || 1.0; event.score *= multiplier; } ``` **连击倍率表**: | 连击数 | 倍率 | 音效 | |--------|------|------| | 1 | 1.0x | sfx_merge_success | | 2 | 1.2x | sfx_combo_2 | | 3 | 1.5x | sfx_combo_3 | | 4 | 2.0x | sfx_combo_4 | | 5 | 3.0x | sfx_combo_5 | | 6+ | 5.0x | sfx_combo_legend | ### 5.2 GameManager 主控制器 **位置**:`assets/scripts/core/GameManager.ts` **职责**: 1. 管理游戏状态(MENU / PLAYING / PAUSED / GAMEOVER / CLEARED) 2. 处理玩家点击掉落水果 3. 监听 MergeCore 的合成事件 4. 检测失败条件(水果超过警戒线) 5. 协调各子系统(AudioManager、SaveManager、BossManager等) **关键方法**: ```typescript // 开始关卡 startLevel(level: number): void { this._currentLevel = level; this._state = GameState.PLAYING; // 初始化各系统 AudioManager.getInstance().playBGM(BGM.MAIN); SaveManager.getInstance().load(); this.mergeCore = new MergeCore(); this.bossManager.initBoss(...); // 记录开始时间 this._levelStartTime = Date.now(); } // 处理玩家点击 onDropAreaClick(event: EventTouch): void { if (this._state !== GameState.PLAYING) return; // 获取点击X坐标 const touchPos = event.getUILocation(); const x = touchPos.x - this.gameContainer.position.x; // 在顶部生成水果 this.spawnFruitAt(x, this.dropArea.position.y); // 播放掉落音效 AudioManager.getInstance().playSFX(SFX.DROP); } // 处理合成事件 handleMergeEvent(event: MergeEvent): void { // 播放合成音效 AudioManager.getInstance().playSFX(SFX.MERGE); // 更新连击 this.updateCombo(event); // 检查是否是金色传说(level 9) if (event.newLevel === 9) { this.triggerGoldenLegend(); } // 尝试投喂Boss this.bossManager.tryFeed(event.newLevel); } // 触发金色传说 triggerGoldenLegend(): void { // 切换BGM AudioManager.getInstance().stopBGM(); AudioManager.getInstance().playBGM(BGM.GOLDEN); // 播放语音 AudioManager.getInstance().playVoice(VOICE.GOLDEN_A); // 播放特效 this.goldenEffectNode.getComponent(GoldenLegendEffect).play( this.fruitLayer.position, () => { // 特效结束后恢复BGM AudioManager.getInstance().stopBGM(); AudioManager.getInstance().playBGM(BGM.MAIN); } ); } // 关卡通关 handleLevelClear(): void { this._state = GameState.CLEARED; // 计算星星 const stars = this.calculateStars(); // 奖励金币 const rewardCoins = stars * 10; SaveManager.getInstance().addCoins(rewardCoins); // 更新最佳成绩 SaveManager.getInstance().updateLevelBestScore(this._currentLevel, this._score); // 显示结算面板 this.showResultPanel(true, stars); } // 游戏失败 handleGameOver(): void { this._state = GameState.GAMEOVER; // 播放失败音效 AudioManager.getInstance().playSFX(SFX.GAME_OVER); // 显示结算面板(带复活按钮) this.showResultPanel(false); } ``` ### 5.3 AudioManager 音频管理 **位置**:`assets/scripts/core/AudioManager.ts` **单例模式**: ```typescript const audioMgr = AudioManager.getInstance(); audioMgr.playBGM(BGM.MAIN); audioMgr.playSFX(SFX.MERGE); ``` **音频池设计**: 为了避免同时播放多个音效时的冲突,使用对象池复用 AudioSource: ```typescript private _sfxSources: AudioSource[] = []; init(rootNode: any): void { // 预创建3个音效音频源 for (let i = 0; i < 3; i++) { const source = rootNode.addComponent(AudioSource); source.loop = false; this._sfxSources.push(source); } } playSFX(sfxName: string): void { // 从池中获取空闲的音频源 const source = this._sfxSources.find(s => !s.isPlaying); if (!source) { console.warn('[AudioManager] 音效音频源池已满'); return; } source.clip = loadedClip; source.volume = this._sfxVolume; source.play(); } ``` **淡入淡出效果**: ```typescript playBGM(bgmName: string, fadeIn: boolean = true): void { if (fadeIn) { this._bgmSource.volume = 0; this._bgmSource.clip = clip; this._bgmSource.play(); // 线性淡入 let volume = 0; const targetVolume = this._bgmVolume; const duration = 1.0; const startTime = Date.now(); const fadeUpdate = () => { const elapsed = (Date.now() - startTime) / 1000; const progress = Math.min(elapsed / duration, 1); volume = targetVolume * progress; if (this._bgmSource) { this._bgmSource.volume = volume; } if (progress < 1) { requestAnimationFrame(fadeUpdate); } }; fadeUpdate(); } else { this._bgmSource.clip = clip; this._bgmSource.volume = this._bgmVolume; this._bgmSource.play(); } } ``` ### 5.4 SaveManager 存档系统 **位置**:`assets/scripts/core/SaveManager.ts` **数据存储结构**: ```typescript interface GameSaveData { currentLevel: number; // 当前关卡 coins: number; // 金币数量 itemCounts: number[]; // 道具数量 [后悔药, 缩小灯, 万能果, 炸弹] unlockedFruits: number[]; // 已解锁水果等级 levelBestScores: { [level: number]: number }; // 各关最佳分数 totalClears: number; // 总通关次数 totalFails: number; // 总失败次数 totalMerges: number; // 总合成次数 maxComboRecord: number; // 历史最大连击 lastPlayTime: string; // 最后游玩时间 } ``` **读写操作**: ```typescript // 加载存档 const data = SaveManager.getInstance().load(); console.log(`当前关卡: ${data.currentLevel}`); console.log(`金币: ${data.coins}`); // 保存存档 SaveManager.getInstance().save(); // 更新特定字段 SaveManager.getInstance().addCoins(100); SaveManager.getInstance().recordClear(); SaveManager.getInstance().updateLevelBestScore(5, 9999); ``` **底层实现**: ```typescript load(): GameSaveData { try { const json = localStorage.getItem('grateful_durian_save'); if (json) { return JSON.parse(json); } } catch (e) { console.error('[SaveManager] 加载存档失败', e); } // 返回默认数据 return this.getDefaultData(); } save(): void { try { const json = JSON.stringify(this._data); localStorage.setItem('grateful_durian_save', json); } catch (e) { console.error('[SaveManager] 保存存档失败', e); } } ``` **注意事项**: - 微信小游戏中 localStorage 有 10MB 限制 - 建议每次关键操作后立即 save()(如通关、购买道具) - 不要在高频操作中频繁 save()(如每帧更新分数) ### 5.5 AdManager 广告集成 **位置**:`assets/scripts/core/AdManager.ts` **支持的广告类型**: 1. **激励视频广告**(Rewarded Video) - 复活(game over 时) - 移除一个水果(道具) - 双倍分数(结算时) 2. **插屏广告**(Interstitial) - 每3关显示一次 - 从图鉴返回时 **使用方法**: ```typescript // 初始化(游戏启动时调用一次) AdManager.init(); // 显示复活广告 AdManager.showReviveAd((success) => { if (success) { // 玩家观看了广告,执行复活逻辑 GameManager.getInstance().revive(); } }); // 显示插屏广告 AdManager.showInterstitial(); ``` **广告单元ID配置**: 在 `AdManager.ts` 顶部修改为你的真实广告位ID: ```typescript private static readonly AD_UNIT_IDS = { REVIVE: 'revive_ad_unit_id_123', // 替换为你的ID REMOVE_FRUIT: 'remove_ad_unit_id_456', // 替换为你的ID INTERSTITIAL: 'interstitial_ad_id_789' // 替换为你的ID }; ``` **获取广告位ID**: 1. 登录微信公众平台 https://mp.weixin.qq.com/ 2. 进入小程序后台 → 推广 → 流量主 3. 创建广告位,复制广告位ID --- ## 六、美术资源替换 ### 6.1 水果精灵图 **规格要求**: - 格式:PNG(带透明通道) - 尺寸:见下方表格 - 命名:`fruit_1.png` ~ `fruit_9.png` | 等级 | 名称 | 推荐尺寸 | 颜色主题 | |------|------|----------|----------| | 1 | 果切丁 | 36x36 | 浅黄色 | | 2 | 西瓜片 | 50x50 | 红绿色 | | 3 | 紫葡萄 | 64x64 | 紫色 | | 4 | 黄柠檬 | 80x80 | 黄色 | | 5 | 红苹果 | 96x96 | 红色 | | 6 | 甜橙 | 112x112 | 橙色 | | 7 | 粉桃子 | 128x128 | 粉色 | | 8 | 金菠萝 | 152x152 | 金黄色 | | 9 | 报恩榴莲 | 180x180 | 金棕色带刺 | **替换步骤**: 1. 将9张图片放入 `assets/textures/fruits/` 目录 2. 在 Cocos Creator 中刷新资源面板 3. 打开 `Fruit.prefab` 预制体 4. 在代码中通过 `resources.load` 动态加载,或使用图集 **使用图集(推荐)**: 1. 选中9张水果图片 2. 右键 → 创建 → Sprite Atlas 3. 命名为 `fruits_atlas` 4. 在 Fruit.ts 中加载图集: ```typescript import { resources, SpriteAtlas } from 'cc'; resources.load('textures/fruits_atlas', SpriteAtlas, (err, atlas) => { if (err) return; // 根据等级获取精灵帧 const frameName = `fruit_${this.level}`; const spriteFrame = atlas.getSpriteFrame(frameName); this.fruitSprite.spriteFrame = spriteFrame; }); ``` ### 6.2 Boss 图片 **规格**: - 格式:PNG - 尺寸:200x200 px - 数量:1张(或20张对应20个关卡) **命名**: - 通用Boss:`boss_default.png` - 分关卡:`boss_1.png` ~ `boss_20.png` **替换步骤**: 1. 放入 `assets/textures/boss/` 2. 在 BossManager 中加载: ```typescript const bossPath = `textures/boss/boss_${this.currentLevel}`; resources.load(bossPath, SpriteFrame, (err, spriteFrame) => { if (err) { // 降级使用默认Boss resources.load('textures/boss/boss_default', SpriteFrame, ...); return; } this.bossSprite.spriteFrame = spriteFrame; }); ``` ### 6.3 UI 元素 **必需UI图片**: - `bg_main.png` - 主菜单背景(750x1334) - `bg_game.png` - 游戏背景(750x1334) - `button_start.png` - 开始按钮(300x100) - `progress_bar_bg.png` - 进度条背景(200x20) - `progress_bar_fill.png` - 进度条填充(200x20,九宫格拉伸) - `star.png` - 星星图标(50x50) - `danger_line.png` - 警戒线(600x4,红色虚线) **可选UI图片**: - 图标:暂停、主页、下一关、双倍分数等 - 装饰:粒子、光效、边框 ### 6.4 AI 绘图提示词 如需使用 Midjourney 或 DALL-E 3 生成素材,参考 `04_报恩榴莲_UI界面设计描述.md` 中的提示词。 **示例(水果精灵)**: ``` Prompt: "Cute cartoon watermelon slice, round shape, vibrant red and green colors, glossy surface, mobile game asset, flat design, transparent background, 512x512" Negative prompt: "realistic, photorealistic, complex details, text, watermark" ``` --- ## 七、音频资源配置 ### 7.1 音频文件清单 **BGM(背景音乐)**: - `bgm_main.mp3` - 主游戏BGM(轻快活泼,60秒循环) - `bgm_golden.mp3` - 金色传说BGM(史诗感,30秒) - `bgm_result.mp3` - 结算BGM(欢快胜利,20秒) **SFX(音效)**: - `sfx_drop_fruit.mp3` - 水果掉落 - `sfx_land_soft.mp3` - 轻柔落地 - `sfx_land_hard.mp3` - 重重落地 - `sfx_merge_success.mp3` - 合成成功 - `sfx_merge_chain.mp3` - 连锁合成 - `sfx_combo_2.mp3` ~ `sfx_combo_5.mp3` - 连击音效 - `sfx_combo_legend.mp3` - 传奇连击 - `sfx_feed_boss.mp3` - 投喂Boss - `sfx_satiety_full.mp3` - 饱食度满 - `sfx_game_over.mp3` - 失败 - `sfx_revive_success.mp3` - 复活成功 - `sfx_button_click.mp3` - 按钮点击 - `sfx_panel_open.mp3` - 面板打开 - `sfx_panel_close.mp3` - 面板关闭 **Voice(语音)**: - `voice_golden_legend_a.mp3` - 金色传说台词A - `voice_golden_legend_b.mp3` - 金色传说台词B - `voice_golden_legend_c.mp3` - 金色传说台词C ### 7.2 音频格式建议 **微信小游戏推荐格式**: - BGM:MP3,128kbps,立体声 - SFX:OGG,64kbps,单声道(体积更小) - Voice:OGG,96kbps,单声道 **转换工具**: - Audacity(免费开源) - FFmpeg(命令行) - Online Audio Converter(在线) **FFmpeg 转换示例**: ```bash # MP3 转 OGG ffmpeg -i input.mp3 -codec:a libvorbis -qscale:a 4 output.ogg # 降低比特率 ffmpeg -i input.wav -codec:a libvorbis -qscale:a 6 output_low.ogg ``` ### 7.3 音频加载策略 **预加载(BGM)**: 在 GameManager.start() 中预加载: ```typescript resources.load('audio/bgm_main', AudioClip, (err, clip) => { if (err) return; // 缓存到 AudioManager AudioManager.getInstance().preloadClip('bgm_main', clip); }); ``` **按需加载(SFX/Voice)**: AudioManager 已实现自动按需加载,首次播放时异步加载并缓存。 ### 7.4 使用 Suno AI 生成 BGM 如果需要原创音乐,可使用 Suno AI: **Prompt 示例(主游戏BGM)**: ``` Style: Upbeat casual mobile game music Instruments: Piano, light percussion, bass Mood: Cheerful, relaxed, playful Tempo: 120 BPM Duration: 60 seconds (loopable) No vocals ``` **Prompt 示例(金色传说BGM)**: ``` Style: Epic orchestral hybrid Instruments: Strings, brass, choir, electronic elements Mood: Majestic, triumphant, awe-inspiring Tempo: 100 BPM Duration: 30 seconds No lyrics ``` --- ## 八、微信小游戏集成 ### 8.1 构建微信小游戏包 **步骤**: 1. 在 Cocos Creator 菜单栏 → 项目 → 构建发布 2. 平台选择:**WeChat Mini Game** 3. 填写 AppID(从微信公众平台获取) 4. 构建模板:选择 **Wechat Game** 5. 点击 **"构建"** 按钮 6. 等待构建完成(约 1-3 分钟) 7. 构建输出目录:`build/wechatgame/` ### 8.2 上传到微信开发者工具 **步骤**: 1. 打开微信开发者工具 2. 点击 **"+"** → 导入项目 3. 项目目录:选择 `build/wechatgame/` 文件夹 4. AppID:填写你的小程序 AppID 5. 点击 **"导入"** 6. 等待编译完成 7. 点击 **"上传"** 按钮 8. 填写版本号和备注 9. 提交审核 ### 8.3 广告 SDK 集成 **重要**:微信小游戏的广告需要在微信公众平台配置后才能使用。 **配置步骤**: 1. 登录 https://mp.weixin.qq.com/ 2. 进入小程序后台 3. 左侧菜单 → 推广 → 流量主 4. 开通流量主(需满足条件:累计独立访客 ≥ 1000) 5. 创建广告位: - 激励视频广告 × 3(复活、去水果、双倍分数) - 插屏广告 × 1 6. 复制广告位ID 7. 在 `AdManager.ts` 中替换广告位ID **测试广告**: 在开发阶段,可使用测试广告位ID(不会真正展示广告,但会触发回调): ```typescript private static readonly AD_UNIT_IDS = { REVIVE: 'test-ad-unit-id', REMOVE_FRUIT: 'test-ad-unit-id', INTERSTITIAL: 'test-ad-unit-id' }; ``` ### 8.4 分包加载(进阶) 如果包体超过 4MB,需要使用分包: **配置分包**: 1. 在 Cocos Creator → 项目 → 项目设置 → 功能裁剪 2. 启用 **"分包加载"** 3. 将大型资源(如音频、高清图片)放入子包 4. 构建时会自动生成分包配置 **代码中加载子包**: ```typescript wx.loadSubpackage({ name: 'subpackage_audio', success: () => { console.log('子包加载成功'); }, fail: (err) => { console.error('子包加载失败', err); } }); ``` ### 8.5 性能监控 微信小游戏提供性能监控接口: ```typescript // 上报自定义数据 wx.reportMonitorPerformance({ key: 'level_clear_time', value: timeSeconds, }); // 上报错误 wx.reportMonitorError({ message: error.message, stack: error.stack, }); ``` --- ## 九、调试与测试 ### 9.1 Cocos Creator 内置调试 **浏览器控制台**: 1. 点击编辑器 **"预览"** 按钮 2. 浏览器自动打开 3. 按 F12 打开开发者工具 4. 查看 Console 标签页的日志 **常用调试命令**: ```javascript // 在控制台执行 // 跳过当前关卡 window.skipLevel = () => { const gm = cc.find('GameManagerNode').getComponent('GameManager'); gm.handleLevelClear(); }; // 强制触发金色传说 window.triggerGolden = () => { const gm = cc.find('GameManagerNode').getComponent('GameManager'); gm.triggerGoldenLegend(); }; // 打印当前分数 console.log(cc.find('GameManagerNode').getComponent('GameManager').score); ``` ### 9.2 真机调试 **步骤**: 1. 在微信开发者工具中点击 **"预览"** 2. 扫描二维码(需用手机微信扫描) 3. 在真机上测试 4. 观察性能和表现 **常见问题**: - 真机性能低于模拟器 → 减少同屏水果数量 - 音频不播放 → 检查文件格式和大小 - 触摸无响应 → 检查 DropArea 的 UITransform 尺寸 ### 9.3 性能分析 **使用 Cocos Profiler**: 1. 在编辑器中点击 **"Profiler"** 按钮 2. 查看 FPS、DrawCall、内存占用 3. 优化瓶颈: - FPS < 30 → 减少物理模拟复杂度 - DrawCall > 100 → 使用图集合并 - 内存 > 100MB → 及时释放未用资源 **微信性能面板**: 1. 微信开发者工具 → 调试器 → Performance 2. 查看 CPU、GPU、内存曲线 3. 识别性能热点 ### 9.4 单元测试(可选) 对于 MergeCore 纯逻辑层,可以编写单元测试: ```typescript // tests/MergeCore.test.ts import { MergeCore } from '../assets/scripts/core/MergeCore'; describe('MergeCore', () => { it('should merge 3 same-level fruits', () => { const core = new MergeCore(); // 添加3个等级1的水果 core.addFruit('f1', 1, 0, 0); core.addFruit('f2', 1, 10, 0); core.addFruit('f3', 1, 5, 10); // 尝试合成 const events = core.tryMerge(); expect(events.length).toBe(1); expect(events[0].newLevel).toBe(2); expect(events[0].removeIds).toEqual(['f1', 'f2', 'f3']); }); }); ``` 运行测试: ```bash npm install --save-dev jest @types/jest npx jest ``` --- ## 十、性能优化 ### 10.1 渲染优化 **图集合并**: - 将所有 UI 元素打包成 1-2 个图集 - 将 9 个水果精灵打包成 1 个图集 - 目标:DrawCall < 50 **节点层级简化**: - 减少不必要的嵌套节点 - 隐藏不可见节点(`node.active = false`) **粒子优化**: - 金色传说特效中的粒子数量控制在 50 以内 - 使用简单的 Quad 粒子而非复杂模型 ### 10.2 物理优化 **限制同屏水果数量**: ```typescript // GameConfig.ts export const PerformanceConfig = { maxFruitsOnScreen: 50, // 超过此数量不再掉落新水果 }; ``` **禁用不必要的物理模拟**: ```typescript // 水果静止后禁用刚体 if (velocity.magnitude < 0.1) { rigidBody.enabled = false; } ``` **调整物理步长**: ```typescript // 在 project.settings 中 PhysicsSystem2D.instance.fixedTimeStep = 1/60; // 默认值,可根据需要调整 ``` ### 10.3 内存优化 **及时释放资源**: ```typescript // 关卡结束时释放未使用的音频 AudioManager.getInstance().clearCache(); // 释放未使用的纹理 resources.releaseRes('textures/fruits/fruit_1', SpriteFrame); ``` **对象池复用**: 对于频繁创建销毁的对象(如水果),使用对象池: ```typescript import { NodePool } from 'cc'; class FruitPool { private static _pool: NodePool = new NodePool(); static get(prefab: Prefab): Node { if (this._pool.size() > 0) { return this._pool.get(); } return instantiate(prefab); } static put(node: Node) { node.setPosition(0, 0, 0); node.setScale(1, 1, 1); this._pool.put(node); } } ``` ### 10.4 代码优化 **避免每帧创建对象**: ```typescript // ❌ 错误示例 update(dt) { const pos = new Vec3(); // 每帧创建新对象 } // ✅ 正确示例 private _tempPos = new Vec3(); update(dt) { this._tempPos.set(0, 0, 0); // 复用对象 } ``` **使用定时器代替每帧检查**: ```typescript // ❌ 错误示例 update(dt) { if (Date.now() - this.lastCheck > 1000) { // 每秒执行的逻辑 } } // ✅ 正确示例 this.schedule(() => { // 每秒执行的逻辑 }, 1.0); ``` --- ## 十一、打包发布 ### 11.1 构建前检查清单 - [ ] 移除所有 `console.log` 调试代码 - [ ] 关闭物理调试绘制(`PhysicsSystem2D.instance.debugDrawFlags = 0`) - [ ] 替换所有测试广告位ID为正式ID - [ ] 压缩音频文件(OGG 格式) - [ ] 检查所有图片尺寸是否符合规范 - [ ] 测试所有广告触发点 - [ ] 测试存档保存和读取 - [ ] 真机测试至少 3 台不同设备 ### 11.2 构建步骤 1. **Cocos Creator 构建**: - 菜单栏 → 项目 → 构建发布 - 平台:WeChat Mini Game - 勾选 **"加密脚本"**(防止代码泄露) - 点击 **"构建"** 2. **微信开发者工具上传**: - 导入 `build/wechatgame/` 目录 - 点击 **"上传"** - 填写版本号(如 1.0.0) - 填写版本说明 3. **提交审核**: - 登录微信公众平台 - 版本管理 → 提交审核 - 填写审核信息: - 服务类目:游戏 → 休闲 - 特殊资质:无需(休闲游戏) - 测试账号:提供测试用的微信账号 ### 11.3 审核后运营 **数据分析**: - 微信公众平台 → 统计 → 数据分析 - 关注指标: - 日活跃用户(DAU) - 留存率(次日、7日、30日) - 广告曝光次数 - 广告点击率(CTR) - eCPM(千次曝光收益) **版本迭代**: - 根据数据调整关卡难度 - 新增活动关卡(节日限定) - 优化广告触发频率 - 修复玩家反馈的 Bug --- ## 十二、常见问题FAQ ### Q1: 水果不掉下来? **可能原因**: 1. RigidBody2D.Type 不是 Dynamic 2. Allow Sleep 被勾选 3. 重力加速度设置为 0 **解决方法**: - 检查 Fruit.prefab 的 RigidBody2D 组件 - Type 设为 Dynamic - 取消勾选 Allow Sleep - Gravity Scale 设为 1 ### Q2: 水果合成不触发? **可能原因**: 1. MergeCore 未正确初始化 2. tryMerge() 未在合适时机调用 3. 水果的 level 属性未设置 **解决方法**: - 在 GameManager.startLevel() 中确认 `this.mergeCore = new MergeCore()` - 在水果落地静止后调用 `this.mergeCore.tryMerge()` - 检查 Fruit.ts 中 `this.level` 是否正确赋值 ### Q3: 金色传说特效不播放? **可能原因**: 1. goldenEffectNode 未绑定 2. GoldenLegendEffect 组件未挂载 3. 特效节点被其他节点遮挡 **解决方法**: - 在 GameManager 属性面板中绑定 goldenEffectNode - 确认 GoldenEffectNode 上已挂载 GoldenLegendEffect.ts - 检查 Z-order,确保特效节点在最上层 ### Q4: 音效不播放? **可能原因**: 1. AudioManager 未 init() 2. 音频文件路径错误 3. 音频文件未导入到项目中 4. 音量为 0 或静音 **解决方法**: - 在 GameManager.start() 中调用 `AudioManager.getInstance().init(this.node)` - 检查音频文件是否在 `assets/audio/` 目录 - 检查控制台是否有 "音频加载失败" 错误 - 调用 `AudioManager.getInstance().setMute(false)` ### Q5: 存档数据丢失? **可能原因**: 1. 在微信模拟器中运行(localStorage 不稳定) 2. JSON 解析错误 3. 存储空间已满 **解决方法**: - 在真机上测试 - 检查 SaveManager.load() 中的 try-catch - 清理微信缓存后重试 ### Q6: 广告不显示? **可能原因**: 1. 广告位ID错误 2. 未开通流量主 3. 广告未预加载 4. 网络问题 **解决方法**: - 确认广告位ID已从微信公众平台复制正确 - 确认已开通流量主(需 ≥ 1000 UV) - 在游戏启动时调用 `AdManager.preloadAds()` - 检查网络连接 ### Q7: 真机性能卡顿? **可能原因**: 1. 同屏水果过多 2. DrawCall 过高 3. 音频文件过大 4. 物理模拟复杂度高 **解决方法**: - 降低 `PerformanceConfig.maxFruitsOnScreen` 到 30 - 使用图集合并,减少 DrawCall - 压缩音频为 OGG 格式 - 简化水果碰撞体(使用 CircleCollider 而非 PolygonCollider) ### Q8: 如何调整关卡难度? **调整方法**: 1. 修改 `GameConfig.ts` 中的 `LEVEL_CONFIGS` 2. 调整以下参数: - `targetLevel`:Boss 需求的水果等级(越高越难) - `feedCount`:需要投喂的次数(越多越难) - `timeLimit`:时间限制(越短越难) **示例**: ```typescript // 第5关 - 中等难度 { level: 5, bossName: '贪吃喵星人', targetLevel: 6, // 需要合成甜橙 feedCount: 5, // 需要投喂5次 timeLimit: 120 // 限时2分钟 } ``` ### Q9: 如何添加新水果? **步骤**: 1. 在 `GameConfig.ts` 的 `FRUIT_CHAIN` 数组中添加新条目 2. 准备对应的水果精灵图 3. 调整物理参数(半径、质量等) 4. 测试合成链是否正常 **示例**: ```typescript { level: 10, name: '超级榴莲王', radius: 100, score: 19683, // 3^9 color: '#FFD700' } ``` ### Q10: 如何实现多语言? **方案**: 1. 创建语言配置文件 `Localization.ts` 2. 使用键值对存储文本 3. 根据系统语言动态切换 **示例**: ```typescript // Localization.ts export const TEXTS = { zh: { start: '开始游戏', pause: '暂停', gameOver: '游戏结束', }, en: { start: 'Start Game', pause: 'Pause', gameOver: 'Game Over', } }; // 使用时 const lang = wx.getSystemInfoSync().language.startsWith('zh') ? 'zh' : 'en'; const text = TEXTS[lang]['start']; ``` --- ## 附录 A:完整开发时间表 | 阶段 | 任务 | 预计工时 | |------|------|----------| | Day 1-2 | 环境搭建、场景搭建、预制体制作 | 16小时 | | Day 3-4 | 核心玩法实现(MergeCore + Fruit + 物理) | 16小时 | | Day 5-6 | Boss系统、金色传说特效、UI界面 | 16小时 | | Day 7-8 | 音频系统、存档系统、广告集成 | 16小时 | | Day 9-10 | 美术资源替换、音频资源配置 | 16小时 | | Day 11-12 | 调试测试、性能优化、Bug修复 | 16小时 | | Day 13-14 | 微信小游戏打包、提交审核 | 8小时 | | Day 15-17 | 审核后调整、上线运营准备 | 8小时 | **总计**:约 112 小时(14 个工作日) --- ## 附录 B:参考资料 - **Cocos Creator 官方文档**:https://docs.cocos.com/creator/manual/zh/ - **微信小游戏文档**:https://developers.weixin.qq.com/minigame/dev/guide/ - **TypeScript 手册**:https://www.typescriptlang.org/docs/ - **游戏设计模式**:https://gameprogrammingpatterns.com/ --- ## 附录 C:联系与支持 - **项目仓库**:(待补充) - **问题反馈**:(待补充) - **社区论坛**:https://forum.qoder.com/ --- **文档版本**:v1.0 **最后更新**:2026-08-14 **作者**:QoderWork AI Assistant **许可证**:MIT