这是什么
TBA(TaskBarApocalypse)是一款废土题材的任务栏挂机 RPG:一支三人小队在屏幕最下面一条 760×200 的透明窄条里自动行军、遇敌、开打、捡装备,你干活它升级。设计上有三个圈:主队实时自动战斗、藏身处养成、中后期解锁的远征系统(把队员派出去 8 到 12 小时,回来带一批特定类型的高级装备)。
我们给它定的调子是小而美、口碑留存优先、本地优先、无核心服务器、无真钱市场。灵感来自同类的任务栏挂机游戏,数值量级也参考了它们的公开资料,但所有绝对值都要按自己的节奏重锚。

先定规矩,再写代码
正式动手前先写了一份技术设计与交接文档,把架构和几条铁律固定下来,之后每个开发任务都引用它。
四层单向依赖:表现层 → 模拟层 ←→ 数据层 / 持久化层。表现层只读模拟层,模拟层不认识任何视觉节点。
四条铁律:
- 模拟层用固定时间步(0.1 秒一个 tick)累加器驱动,与渲染帧率解耦。窗口缩成一丁点或藏起来逻辑照跑;离线追算就是"快进 N 个 tick"。
- 模拟层确定性:同样的种子加同样的输入,结果一模一样。随机数用可序列化的种子,连同状态一起进存档。
- 存档是唯一真相源。没有服务器对账,就不存在本地与服务器不一致的问题。
- 不做反作弊。存档只做轻量校验防止改坏崩溃,改钟只坑自己。
然后把开发切成一串端到端可跑的纵切片,先无头模拟加占位美术,表现层后叠:
| 切片 | 内容 | 状态 |
|---|---|---|
| 0 骨架 | Godot 工程、目录、固定 tick 循环、调试面板 | 完成 |
| 1 无头战斗 | 三层属性、伤害公式、缓解管线、掉落进库存 | 完成 |
| 2 经济循环 | 物资 / 装备双引擎、藏身处与工作台、区域深度刹车 | 完成 |
| 3 角色合成器 | 五层分层 rig + 五状态 + 逐帧枢轴 | 跑通后搁置 |
| 表现层 | 像素战斗舞台,接真实数值与经济循环 | 可玩 |
| 4 远征 | 派遣、部署锁定、真离线时间戳、分级结算 | 未开始 |
| 5 持久化 | 本地存档、离线追算、任务栏窗口模式 | 未开始 |
切片 0 + 1:没有画面的战斗
第一版战斗完全是文字。三个队员对五个杂兵,每 tick 推进出手计时,控制台一行一行打"近战 攻击 D1兵3 -18 (HP 72/90)"。目的只有一个:先证明数学对、循环好玩,再谈美术。
属性走暗黑 2 式的三层叠加:
最终值 = (base + Σflat) × (1 + Σadditive) × Π(1 + 每个 multiplicative 层)
乘法层是"多个独立的层逐个相乘",不是加总后乘一次。这是刻意的:飞轮和"一套满词条战力大跳"都从这里来。工程启动时会跑一个自检,base 10、flat 5、additive 50%、两个乘法层 20% 和 10%,期望 29.7,不对就直接报 FAIL。
伤害缓解管线严格按序七步:闪避 → 格挡(削固定值)→ 元素抗性 → 物理护甲递减 → 通用减伤 → 吸收护盾 → 地板(每击至少 1 点)。护甲这一步和区域深度耦合:
减伤 = 护甲 / (护甲 + 阈值),阈值 = 14 × 深度 + 12
护甲等于阈值时正好减一半。这条公式是把"深度"变成战力门槛的数学钩子:同一件护甲越往深处越不顶用,自然逼你换装。
随机数封装成 DetRNG,种子和内部状态都能存取,为切片 5 的离线追算留好接口。
切片 2:让经济自己转起来
经济是双引擎:
- 规模引擎:清区域拿物资 → 升藏身处 → 全队百分比加成,每三级多开一个远征槽。
- 装备引擎:清区域拿材料 → 升工作台 → 造装 → 装备 → 战力。
两台靠远征槽耦合,刹车链是"区域深度 → 要求战力 → 卡造装深度 / 工作台等级",不靠限制装备数量限速。
挂机时的自动消费是一段确定性的贪心策略,顺序固定:能升就升藏身处,能升就升工作台,最后试着造一件武器。造装有一条关键规则:造出来的东西只有确实比现役强才扣材料留下,否则丢弃、材料不扣。于是造装碰到瓶颈时材料会自然攒起来升工作台,工作台升级后又能造出更强的东西,两台引擎交替往前拱,不需要任何额外调度代码。
验证方式是无头跑 12000 个 tick(20 分钟游戏时间)出一份报告:胜负场次、最深抵达、资源余额、藏身处和工作台等级、库存件数。同一个种子跑两遍结果逐字相同,确定性通过。
切片 3:自研分层角色,跑通了,然后放下了
设计文档里的角色方案很讲究:五层精灵(右臂 / 身体 / 右武器 / 左臂 / 左道具)按 z 序叠放,不用骨骼插值(40 像素高的角色一插值就抖),改用帧驱动加逐帧枢轴——每帧读一组右肩、右手、左肩、左手坐标,武器和道具贴到对应枢轴上。右手武器类是唯一驱动,决定双臂用哪套动画;左道具被动跟着左手;身体通用,双手近战攻击时换前倾身体。
我们用彩色矩形当占位把整套逻辑跑通了:五个状态、四种武器类切换、镜像、枢轴可视化,都对。

然后做了一个现实的决定:搁置。跑通逻辑容易,为每种武器类画五层五状态的像素序列帧是另一个量级的工作量,这个阶段不该把时间花在这里。蓝图保留,代码保留,玩家角色改走"轨道 B"——用现成素材包的整体序列帧。两条轨道统一由同一个 AnimState 枚举驱动,将来想切回来不用动战斗代码。
美术的一段弯路
一开始想让 AI 画像素角色。出图很快,但拿到手是伪像素:看着是格子,实际网格倍率不均匀、边缘带抗锯齿、一个"像素"里有好几种颜色,缩回原始分辨率就糊。
![]()
为此写了一个本地小工具:对图像梯度剖面做 FFT 找主空间周期,得到真实网格倍率和相位;按格取主色降采样回真实分辨率;再可选做中位切割缩减调色板、透明背景二值化。用合成的伪像素图自测能正确还原。
工具能用,但最后还是没走这条路——修图的时间不如直接买。现在的美术来自两个素材包:一个后启示录主题包(无手身体加武器层的组合式主角、三种僵尸、大量场景物件)和一个暗黑系列怪物包(二十多种 90×90 单行连排的怪物、四套六层视差背景)。两个包都是付费商用授权、禁止再分发,所以整个 art/ 目录不进 git。
素材包的文件名大小写不统一、帧数编码在文件名里,我们写了一个 ArtDB 全小写索引一次性解决,目前索引到 1338 个剪辑。
表现层:现在跑起来是什么样
主场景是一个 760×200 的透明窄条,Godot 开了逐像素透明。里面是一个行军 → 遭遇 → 战斗 → 胜利 / 战败的循环:
- 行军:六层视差背景按系数滚动,远处 0.02、近处 1.0,天空层可开关。
- 遭遇:怪从左边走进来,近战冲上去,枪手和步枪手停在各自射程。
- 战斗:每一次命中都调用模拟层的
Damage.resolve_hit,和无头模拟用同一套数学,只是编排方式换成了帧率驱动。子弹真的飞过去、弹壳真的抛出来落地,命中闪白加 1 像素击退,飘字、格挡标记、MISS 一应俱全。 - 镜头:没怪时对准队伍中心,有怪时对准队伍和怪群中心的中点,带死区和限速,不会因为一只怪死了就猛晃。
- 坐标重基:每波打完把整个世界平移回标准槽位、镜头反向平移同样距离,画面纹丝不动,但队员再也不需要"往后走"归位。
经济循环已经并入:清波掉落进库存、物资材料入账、自动升级和造装的事件以播报形式弹出;战力达标就深入下一区并切背景,战败就撤退一层 farming。区域有 8 层,每层 10 波,第 10 波是放大 1.5 倍的首领;队员被击倒后原地倒下等 12 秒充能复活,右上角会出现一个流泪的小头像;脱战时每秒回 5% 血,战斗中不回。

关键决策一览
| 决策 | 选择 | 原因 |
|---|---|---|
| 渲染 | 双轨:CharacterRig(搁置)/ ActorSprite(现用),同一 AnimState | 保留蓝图,先用现成素材出效果 |
| 主队 | 棒球棍 / 手枪 / 步枪,同一具身体靠色调区分 | 素材包只有一个主角身体 |
| 死亡 | 倒地待救,充能后原地复活 | 不打断挂机节奏 |
| 数值 | 表现层与无头模拟共用 Combatant / Damage | 两套数学迟早对不上 |
| 美术 | 付费素材包,不进 git | 授权禁再分发 |
工具链
引擎 Godot 4.6,语言 GDScript,代码由 Claude Code 在命令行里写。编辑器里装了一个 MCP 插件,智能体可以直接驱动编辑器运行场景和截图,不需要人来回切窗口。无头验证走 godot --headless,跑完打印报告自动退出。
接下来
- 数值节奏细调:怪物成长、掉率、区域门槛都还是占位量级。
- UI 壳:右侧面板、基地入口,让玩家能看队伍和背包。
- 切片 4 远征、切片 5 存档 + 离线追算 + 真正的任务栏化(无边框、置顶、吸底)。
这篇文章由 Claude Code 根据工程源码与设计文档整理写成,截图来自当前构建。