这篇开发日志记录《捡钱》从一个小想法到上架 CrazyGames 的全过程。我会尽量还原每个关键决策点的思考——为什么选 Cocos Creator、玩法怎么从原型迭代到上线版、广告 SDK 怎么接、QA 环节踩了哪些坑。希望对同样在做休闲小游戏的独立开发者有参考价值。
一、立项:为什么做《捡钱》
做独立游戏最难的不是写代码,而是「决定做什么」。我在 CrazyGames 上观察了一段时间,发现点击类休闲小游戏有几个特点:开发周期短、玩家上手门槛低、适合碎片时间体验。这正好符合我作为独立开发者的资源约束——一个人、业余时间、没有美术预算。
《捡钱》的核心循环可以用一句话概括:屏幕上不断出现钞票,玩家点击捡起,在限定时间内尽可能多捡,分数越高越好。 听起来简单到「无聊」,但正是这种「一秒理解、三秒上手」的特性,让它在网页游戏平台上有了生存空间。
立项时我给自己定了三个约束:
- 开发周期不超过 2 周(业余时间折算)
- 不引入任何付费素材,全部用免费资源或自制
- 包体控制在 5MB 以内,保证网页秒开
这三个约束后来成了所有设计决策的过滤网——凡是会打破约束的功能,再有趣也砍掉。
图解:依据文中玩法绘制的机制示意,不能替代历史原型或平台审核截图。
玩家反馈可以延后播放,但逻辑状态应先确认。例如点击到已经结算的对象,不应再增加分数;重开后旧计时器也不能继续生成物体。将生成频率、在场数量和反馈时长分别记录,才能判断“变难”来自决策压力还是视觉干扰。
动手核对: 连续重开、结算瞬间点击、页面切后台后返回,分别检查分数、对象数与计时器。实际截图应标注对应版本;尚未留存的历史画面用明确标注的示意图说明。
二、玩法设计与原型迭代
2.1 第一版原型:太朴素了
第一版原型极其简陋:全屏随机生成钞票 sprite,点击 +1 分,30 秒倒计时。玩了两分钟我就发现一个问题——没有任何变化感。分数在涨,但体验是平的,玩家很快就会觉得「就这?」。
2.2 加入难度曲线
核心改动是引入「随时间递增的挑战」:
- 生成速度递增:前 10 秒每 0.8s 生成一个,之后逐渐缩短到 0.3s
- 钞票类型分化:普通钞票(1 分)、大额钞票(5 分,出现概率低)、炸弹(点了扣分)
- 视觉反馈强化:捡到时弹出 +N 飞字、连击时有粒子特效
这一步的数值调表过程我单独写了一篇 → 《休闲游戏的难度曲线设计》
2.3 上线版 vs 原型的差异
| 维度 | 第一版原型 | 上线版 |
|---|---|---|
| 物体类型 | 仅钞票 | 钞票 + 大额钞票 + 炸弹 + 金币袋(稀有) |
| 计分 | 纯累计 | 累计 + 连击加成 + 时间奖励 |
| 反馈 | 无 | 粒子、飞字、音效、屏幕震动 |
| 结算 | 显示分数 | 分数 + 最高分记录 + 「再来一局」按钮 |
迭代的核心原则是:每次改动只加一个变量,玩 10 局感受变化,再决定保留还是回退。
三、Cocos Creator 实现要点
3.1 项目结构与场景划分
项目只有两个场景:Loading(加载/Logo)和 Main(主游戏)。没有用多场景,因为休闲小游戏的复杂度不值得引入场景管理的开销。
assets/
scenes/ # Loading.scene, Main.scene
scripts/
GameManager.ts # 游戏总控:状态机、计分、计时
Spawner.ts # 生成器:按难度曲线 spawn 物体
Pickup.ts # 挂在可点击物体上:处理点击、动画、回收
UIManager.ts # UI:分数、倒计时、结算面板
prefabs/ # 钞票、炸弹、金币袋的预制体
textures/ # 精灵图、图集
audio/ # 音效
3.2 核心脚本:生成器与对象池
生成器是游戏的心脏。关键是用对象池而非 instantiate/destroy——休闲游戏频繁创建销毁节点会导致 GC 卡顿:
// Spawner.ts 核心逻辑(简化版)
const POOL_SIZE = 20;
private pool: cc.Node[] = [];
spawnItem(): void {
const node = this.pool.pop() ?? cc.instantiate(this.prefab);
node.setPosition(this.randomPosition());
node.active = true;
// ... 设置类型、速度等
}
recycleItem(node: cc.Node): void {
node.active = false;
if (this.pool.length < POOL_SIZE) {
this.pool.push(node);
} else {
node.destroy();
}
}
3.3 动效与音效的取舍
音效是最容易被砍的部分,但对体验影响极大。最终我只保留了 4 个音效:捡钱(叮)、炸弹(砰)、连击(升调)、结算(胜利/失败)。全部用免费音效站下载,总大小 < 200KB。
动效方面,屏幕震动是性价比最高的反馈——Cocos Creator 里一行 node.runAction(cc.shake(0.1, 5)) 就能让「捡到大额钞票」的爽感翻倍。
四、美术与音效资源
4.1 资源来源
没有美术预算的情况下,我的方案是:
- 钞票/金币:用免费的扁平化图标(Flaticon 免费版),统一调色后打成图集
- UI 元素:纯代码绘制 + Cocos 内置 UI 组件
- 背景:纯色渐变 + 简单粒子点缀
4.2 分辨率与包体控制
目标平台是网页,所以适配策略是 fitWidth + fitHeight(等比缩放铺满)。设计分辨率 720×1280(竖屏),图集用 PNG 8-bit 压缩,最终包体 3.2MB,在 CrazyGames 上首屏加载 < 2 秒。
4.3 风格统一的经验
最实用的技巧:定一个 5 色调色板,所有素材只能用这 5 个色。我的调色板是:
| 用途 | 颜色 | 色值 |
|---|---|---|
| 背景 | 深蓝 | #1a1a2e |
| 主色 | 琥珀金 | #f0a500 |
| 辅色 | 翠绿 | #06d6a0 |
| 警告 | 珊瑚红 | #ef476f |
| 文字 | 米白 | #f8f9fa |
强制约束让「东拼西凑的素材」看起来像「有设计感的产品」。
五、广告接入与变现
5.1 CrazyGames 广告 SDK 接入
CrazyGames 提供了自己的广告 SDK,接入流程比想象中简单——在 Cocos Creator 构建出的 HTML 中引入 SDK 脚本,然后调用 CrazyGames.SDK.ad.requestAd() 即可。
5.2 广告触发时机
休闲游戏的广告最忌讳「打断心流」。我最终选了两个触发点:
- 游戏结束时:结算页面自然出现「看广告复活 / 双倍分数」的激励视频
- 每 3 局后:间歇插屏广告(玩家可以预期,不会觉得突兀)
没有在游戏进行中插广告——这是底线。
5.3 收益数据
上线首月的收益数据我暂不公开具体数字,但可以分享一个比例:激励视频的 eCPM 大约是插屏广告的 3-4 倍,所以「让玩家主动选择看广告」远比「强制插屏」更划算。
六、上架 CrazyGames 的踩坑记录
6.1 提审被拒原因
第一次提审被拒,原因是 游戏在部分浏览器下加载失败。排查发现是 Cocos Creator 构建时没勾选「分离引擎」,导致首包过大触发了 CrazyGames 的加载超时。修复方法是重新构建,勾选 分离引擎 + 压缩纹理,首包从 3.2MB 降到 1.8MB。
6.2 qaTool 的使用经验
CrazyGames 的 QA 预览链接带了几个参数:
?qaTool=true&disableSubmitQA=true&role=developer
qaTool=true:开启 QA 工具栏,可以模拟不同分辨率、查看 FPSdisableSubmitQA=true:禁用「提交 QA 报告」按钮(开发自测时用)role=developer:以开发者身份预览,能看到普通玩家看不到的调试信息
建议:本地测完后再用 qaTool 链接做一轮全平台回归(Chrome / Firefox / Safari / 移动端),能发现很多本地预览看不到的问题。详细的发布流程我单独写了一篇 → 《CrazyGames 发布全流程》
6.3 上线后的玩家反馈与迭代
上线后收到的反馈集中在两点:
- 「30 秒太短了」 → 加了 60 秒模式作为选项
- 「想要排行榜」 → CrazyGames 暂不支持原生排行榜,用 localStorage 做了本地最高分
七、复盘与下一步
复盘里需要分开记录三种完成状态:功能已经实现、本地测试已经通过、平台已经发布。它们对应不同证据。后续修改玩法或广告逻辑时,应该重新走相关验证,不能沿用早期版本的“已通过”结论。
7.1 做得好的地方
- Scope 控制到位:三个约束(2 周 / 无付费素材 / 5MB)始终没破
- 对象池提前引入:避免了后期性能重构
- 调色板约束:让零散素材有了统一感
7.2 如果重来会怎么改
- 第一天就接广告 SDK:而不是等游戏做完了才接,这样能在开发阶段就测试广告触发体验
- 数据埋点更早:上线后才发现缺少「平均游戏时长」「留存率」等数据,无法科学迭代
- 音效用程序化生成:而非下载音效文件,能进一步压缩包体
7.3 对下一个项目的启发
《捡钱》验证了「小 scope + 快速上线」的可行性。下一个项目《数钱》在此基础上做了差异化——从「点击」变成「拖拽清点」,玩法更有深度。两者的开发日志会互相参照,形成一套「休闲小游戏从 0 到 1」的完整方法论。
💬 如果你对某个章节想看更详细的技术实现,欢迎在评论区告诉我,我会补充展开。
💬 评论
这套方案在哪一步卡住了?也欢迎补充你的实现方式或踩坑经验。