本系列记录我从 0 到 1 实现一个 Balatro 风格的游戏后端系统,并逐步将其工程化为可扩展的实时服务項目。
- 该项目的代码已开源,可在 GitHub 与 GitCode 上获取。
- 📌 这篇文章原本不在计划里,故无对应分支代码。
- ⚠️ 本文是 Balatro 后端項目的第 3 篇进阶分支,写在主分支第 8 篇正式实现之前。
🃏写在前面
这篇文章有点特殊。
它不是一次功能实现,也不是一次代码提交。
而是我在准备第 8 篇“跳过 Blind 与 Tag 奖励机制设计”时,突然卡住后写下来的记录。
卡住的原因也不是代码不会写,而是我第一次很明显地感觉到:机制设计,好像真的比写代码更难。
⚠️这次到底卡在了哪里?
卡住之后,我才发现,自己真正纠结的并不是skipBlind这个方法怎么写。
而是它背后的一连串问题:
- 玩家为什么愿意跳过当前的
Blind? - 跳过后应该给什么?
- 奖励太强,会不会破坏平衡?
- 奖励太弱,玩家为什么要选?
- 这个奖励是立即生效,还是延迟生效?
- 这个状态应该存在当前
Blind,还是跨Blind保留? - 后端应该如何记录这个选择带来的影响?
这些问题看起来都围绕一个“跳过 Blind”的功能展开。
但真正想下去以后,我才发现,它其实已经不是单纯的代码实现问题了。
所以本篇不展开第 8 篇的正式实现,只记录我在写“跳过 Blind 与 Tag 奖励机制设计”之前,对机制设计、状态流转和項目演化一次思考。
文章目录
- ⚠️这次到底卡在了哪里?
- 一、以前更多是在明确需求下写代码
- 1. 以前的边界是别人定义好的
- 2. 我更熟悉的是“需求 -> 参数 -> 代码”
- 二、但 Balatro 項目没有人替我定义需求
- 1. 个人项目开始要求自己判断
- 2. 从单次行为进入生命周期
- 三、真正难的是生命週期,而不是某一段代码
- 1. 问题不再只是一个函数怎么写
- 2. 思考顺序发生了变化
- 四、为什么不能只是照着游戏抄一遍?
- 1. 结果可以查到,但原因需要理解
- 2. 真正难的是风险和收益
- 五、从“实现功能”到“设计机制”
- 1. 第一阶段更偏功能实现
- 2. 第二阶段开始偏规则设计
- 六、为什么有些数据一定要由后端处理?
- 1. 不是因为重要,而是因为会影响结果
- 2. 前端展示,后端维护可信规则
- 七、从“我学到了什么”变成“我要怎么讲清楚”
- 1. 从记录学习,到说清设计过程
- 八、这件事对我有什么用?
- 1. AI 能帮我写代码,但不能替我经历项目演化
- 九、从查攻略,到理解问题本质
- 1. 有些问题不是知道答案就结束了
- 十、总结
- 1. 这次卡住,卡的不是代码
- 2. 从“实现需求”,到“理解规则”
- 3. 记录这次卡住
一、以前更多是在明确需求下写代码
1. 以前的边界是别人定义好的
在过往的工作经历中,我处于的角色更多是:产品或者項目经理给出具体需求文檔,然后我根据一个明确的需求去完成对应实现。
这个流程其实是比较清楚的。比如:
- 这个接口需要什么参数
- 返回什么数据
- 什么情况下报错
- 什么情况下算成功
- 前端需要什么字段
- 测试应该怎么验收
在这种模式下,我更多思考的是:
这个需求怎么实现比较合理?
而不是
为什么要这样设计这个需求?
这并不是说以前的开发不需要思考。只是以前大部分时候,问题的边界已经被别人定义好了。
我需要在一个相对明确的范围内,把代码写出来,把逻辑跑通,把异常处理好。
2. 我更熟悉的是“需求 -> 参数 -> 代码”
也就是说,过去更多的是:
需求 -> 参数 -> 代码
先有需求,再拆参数,最后落到代码实现。
这个过程我相对熟悉。尤其我过去做的大多也是游戏向开发,很多逻辑说难不难,说简单也不简单,但需求通常是明确的。我只需要根据已有的规则,去完成对应的逻辑实现就好。
二、但 Balatro 項目没有人替我定义需求
1. 个人项目开始要求自己判断
而Balatro这个項目不太一样,它是属于我个人的。
没有項目经理给我写需求文檔,也没有同事和我一起做思路碰撞。很多事情都需要自己去判断:
- 这个阶段应该做什么?
- 当前功能应该拆到什么程度?
- 哪些状态应该由后端维护?
- 哪些逻辑现在可以简化?
- 哪些结构要为以后扩展留口子?
- 这个机制到底解决了什么问题?
一开始做这个項目的时候,其实没有这么累。因为前面的功能都比较直观。比如:发牌、出牌、弃牌、补牌、判断牌型、计算分数、判断当局是否结束。
这些都属于局内行为。它们的特点是:执行一次,就结束一次。
比如玩家出牌,后端计算这次出牌的分数,然后从手牌中移除对应卡牌,再补牌。
这个过程虽然也需要状态管理,但它的边界比较清楚。
可以简单理解成:
玩家出牌 ↓ 校验选择的卡牌 ↓ 计算当前牌型分数 ↓ 更新当前 `Blind` 得分 ↓ 扣除出牌次数 ↓ 补充玩家手牌这条链路虽然也有状态变化,但整体还是围绕“一次玩家行为”展开。
2. 从单次行为进入生命周期
可到了第二阶段,事情就开始变得不一样了。因为項目开始进入了Blind、Ante、Boss Blind、跳过奖励、阶段推进这些内容。
| 阶段 | 我主要在做什么 | 难点 |
|---|---|---|
| 第一阶段 | 发牌、出牌、补牌、算分 | 把单次行为跑通 |
| 第二阶段 | Blind、Ante、Boss、跳过奖励 | 判断状态如何流转 |
| 后续阶段 | 商店、特殊卡牌、Modifier | 让系统可以持续扩展 |
也就是从“单次行为”进入到了“生命週期”。
三、真正难的是生命週期,而不是某一段代码
1. 问题不再只是一个函数怎么写
第二阶段之后,我遇到的问题开始变成:
- 当前
Blind是谁? - 当前
Ante是多少? - 当前目标分是多少?
- 玩家什么时候进入下一个
Blind? - 什么时候进入
Boss Blind? - 什么时候重置状态?
- 哪些状态只属于当前
Blind? - 哪些状态需要跨
Blind保留? - 哪些状态未来可能需要持久化?
这些问题并不是单纯靠写一个函数就能解决,因为它们会影响整个游戏流程。
以前写一个出牌逻辑,我可以想:
玩家选择卡牌 -> 判断牌型 -> 计算分数 -> 扣除出牌次数 -> 补牌
这个链路是相对性短的。但现在设计Blind流转时,我需要想的是:
当前
Blind的状态 -> 玩家行为 -> 分数变化 -> 是否达标 -> 是否推进Blind-> 是否进入Boss-> 是否重置局内状态 -> 是否保留进度
这就不再只是一个函数的问题了,它开始变成状态之间的关系。
2. 思考顺序发生了变化
也正是在这里,我对項目的理解发生了一些变化。
以前我更习惯:需求 -> 参数 -> 代码
而现在变成了:规则 -> 状态 -> 生命周期 -> 架构 -> 可扩展性
可以简单理解成,我现在遇到的不是“代码变多了”,而是思考顺序变了。
| 过去的开发方式 | 现在的項目状态 |
|---|---|
| 需求已经明确 | 规则需要自己判断 |
| 参数边界清楚 | 状态归属需要设计 |
| 按需求完成实现 | 需要考虑生命周期 |
| 验收标准由别人定义 | 对错需要自己权衡 |
| 重点是代码能否跑通 | 重点是系统能否继续扩展 |
四、为什么不能只是照着游戏抄一遍?
在写“跳过Blind与Tag奖励机制设计”的时候,我其实对自己产生过怀疑。
1. 结果可以查到,但原因需要理解
因为Balatro是一个公开的游戏,游戏能下載,机制能看到,攻略也能查到。
比如:
- 跳过
Blind会给什么奖励 - 游戏里有哪些
Tag - 每个
Tag大概有什么效果
这些内容其实都可以通过查资料或者打开游戏获得。
所以我有一个疑问:
既然结果都能看到,那我为什么还要花这么多时间去思考“为什么”?
直接照着实现不就好了么?
但深入了解后,我才发现,问题并不是“知不知道游戏里有哪些Tag”。
真正的问题是:
我是否理解这个机制为什么存在。
比如跳过Blind这个行为。如果只看表面,它可能只是一个选项:玩家选择跳过 -> 后端发放一个奖励。
但如果继续往下想,它其实在解决一个更深的问题:
玩家放弃当前
Blind收益,换取一个不确定的未来收益。
2. 真正难的是风险和收益
这就涉及到了风险和收益的问题:
- 如果奖励太弱,玩家没有理由跳过
- 如果奖励太强,跳过就会变成最优解,反而破坏正常流程
- 如果奖励立即生效,可能影响当前阶段
- 如果奖励延迟生效,就需要后端记录它何时触发
- 如果奖励会影响商店、经济系统、卡牌成长,那么它又会和未来很多系统产生关联
所以我真正需要理解的,不是游戏里具体给了什么奖励,而是为什么这个奖励适合放在跳过Blind之后。
这两件事是不一样的。前者是查资料,后者是做设计。
这次真正让我卡住的,也并不是“查不到答案”。
| 不是 | 而是 |
|---|---|
不知道Tag有哪些 | 不知道为什么这个机制适合放在这里 |
不知道跳过Blind给什么 | 不知道奖励强弱如何影响选择 |
| 不知道接口怎么写 | 不知道状态应该怎么保留 |
| 不知道代码怎么跑 | 不知道规则如何进入系统 |
五、从“实现功能”到“设计机制”
这次卡住,也让我重新看了这个項目从开始到现在的变化。
1. 第一阶段更偏功能实现
第一阶段,我更多是在完成一个个功能点。比如我会问:
- 怎么判断牌型?
- 怎么洗牌?
- 怎么发牌?
- 怎么扣除玩家手牌?
- 怎么计算当前出牌分数?
这些问题都比较偏实现。
2. 第二阶段开始偏规则设计
到了第二阶段,我开始问的是:
- 这个状态属于谁?
- 它什么时候创建?
- 它什么时候销毁?
- 它是否应该跨阶段保留?
- 如果以后加数据库,它应该如何持久化?
- 如果以后加商店系统,它要不要和商店发生关系?
- 如果以后加特殊奖励,它要不要抽象成统一的效果系统?
这些问题开始偏设计。
我也慢慢意识到:
代码不是一开始就复杂的,复杂是因为状态之间开始产生关系。
当項目只有发牌、出牌、结算时,它就像是一条线。
但当項目开始出现Blind、Ante、Boss、跳过奖励、阶段流转时,它就开始像一个系统。
🎯 而系统最难的地方,不是某一个函数怎么写,而是每个状态应该放在哪里。
六、为什么有些数据一定要由后端处理?
在这个过程中,我也对一些以前模糊的概念有了更具体的理解。
比如:为什么有些数据一定要由后端处理?
1. 不是因为重要,而是因为会影响结果
以前我可能会比较直觉地觉得:这个数据重要,所以放后端。
但现在我会更倾向于从状态和规则的角度去判断。
比如Blind当前进度、目标分、玩家是否跳过、获得了什么Tag,这些都不是单纯展示用的数据,它们会影响后续流程。
只要一个数据会影响游戏结果,那么它就不应该只依赖前端维护。因为前端更适合展示和交互,而后端需要负责规则判断和状态可信。
2. 前端展示,后端维护可信规则
这里暂时不讨论具体实现,只从职责边界上做一个简单区分:
前端适合做:
- 展示当前
Blind - 展示目标分
- 展示可选择的
Tag - 展示玩家当前状态
后端应该负责:
- 判断 Blind 是否可跳过
- 判断 Tag 是否可发放
- 判断
Tag是否已生效 - 判断当前状态是否能进入下一阶段
- 维护可信的游戏进度
这也是我在Balatro項目中逐渐明确的一点:
后端不只是返回数据,而是维护规则的可信来源。
这句话以前可能也听过,但真正自己做項目去思考时,才会开始理解它为什么重要。
七、从“我学到了什么”变成“我要怎么讲清楚”
1. 从记录学习,到说清设计过程
除了代码本身,这个項目对我来说另一个影响是“输出”。
最开始写博客的时候,我更多是在记录:我今天学到了什么。比如我学会了NestJS,学会了怎么写测试。
但现在不太一样了。现在每一篇主分支博文,我都会需要先想:
- 这一篇到底解决什么问题?
- 为什么它应该放在当前阶段?
- 它和前一篇有什么关系?
- 它会为后一篇留下什么基础?
- 我怎么把自己的设计过程说清楚?
这就导致我写文章的方式也变了。以前可能是边做边写。现在更多的是先想清楚流程,再写代码,再回头整理文章。
有时候这比写代码还累。因为写代码只需要跑通了,至少能看到结果。但设计思路有没有说清楚,很多时候没那么直观。这也是我现在觉得难的地方。
八、这件事对我有什么用?
1. AI 能帮我写代码,但不能替我经历项目演化
在写第八篇之前,我确实问过自己:
- 我为什么要自己做奖励机制设计?
- 这对我的成长到底有什么用?
尤其现在 AI 工具这么多。Cursor、Copilot、Claude、ChatGPT、CodeX,都是能帮程序员更快的生成代码。
单纯写代码的能力,越来越不稀缺了。
但这段时间做Balatro項目后,我慢慢有了一点新的理解。
AI 可以提高代码生产效率,也可以辅助我拆解问题、Review 设计、指出边界情况。 但它不能替我经历一个項目从简单功能逐渐演化成复杂系统的过程。
它可以告诉我一个函数怎么写,但我需要自己去判断:
- 这个函数为什么存在
- 这个状态属于哪个模块
- 这个规则未来是否会扩展
- 当前是否应该抽象
- 什么时候应该先简单实现
- 什么时候必须提前拆边界
这些东西不是单纯看教程、查攻略就能完全变成自己的知识储备。它需要在一个真实的項目里反复遇到问题,再反复调整。
九、从查攻略,到理解问题本质
回头看这个項目从初始到现在,我能感觉到自己的变化。一开始遇到问题时,我更习惯查攻略、看答案、找别人怎么做。
这当然有用。
1. 有些问题不是知道答案就结束了
但做到现在,我开始发现:有些问题不是知道答案就结束了。
比如:
- 为什么这个状态应该放在后端?
- 为什么这里需要生命周期?
- 为什么跳过
Blind不能只是一个简单接口? - 为什么奖励机制会影响后续架构?
- 为什么一个小功能会牵扯到未来扩展?
这些问题没有唯一标准答案,或者说,即使有现成答案,我也需要理解它背后的原因。
因为我不是在做一道题。我是在做一个会不断演化的項目,这也是Balatro項目对我来说越来越重要的地方。
它不只是一个游戏后端deDemo, 它更像是一个可以让我练习架构判断、状态设计、工程拆分和技术表达的长期項目。
十、总结
1. 这次卡住,卡的不是代码
这篇文章不是第 8 篇的正式实现,它只是我在准备写“跳过Blind与Tag奖励机制设计”之前,突然卡住后写下来的一次记录。
但也正是因为这次卡住,我才意识到自己现在遇到的难点,已经不只是“代码怎么写”了。
2. 从“实现需求”,到“理解规则”
以前更多是别人把需求定义好,我在明确的范围里完成实现。而现在,这个項目是我自己的。没有人提前告诉我,这个机制应该怎么拆,状态应该放在哪里,生命週期应该怎么走。
以前的“对错”,很多时候是产品经理或者需求文檔定义的。而现在,在自己的項目里,我需要通过规则、状态、生命週期和扩展性,去判断一个设计是否合理。
这件事确实更累… 因为写代码的时候,至少还能通过运行结果判断它有没有跑通。但机制设计很多时候没有一个立刻可见的答案,只能不断想、不断推翻、不断调整。
3. 记录这次卡住
也许这就是这个項目对我来说真正有意义的地方。让自己不只停留在“接需求、改老代码、修线上问题”的状态里。
这篇没有什么标准答案,只是突然的想记录一下。记录这次卡住,也记录自己开始从“实现需求”,慢慢走向“理解规则”的过程。