下载 App

《公交公司》开发者日志6

修改于10/2224 浏览综合

《公交公司》开发者日志 06 · 上线冲刺:地图、排行榜、存档与教学收敛

这一篇记录上线前的最后一轮开发。做完这四件事,游戏就正式发布了。
这一期聊四件事:地图选择、排行榜、自动存档、教学优化。它们看起来是四个独立功能,其实都在解决同一个问题——让玩家能真正「开始玩」,并且玩得下去。
这四件事做完,《公交公司》才算是准备好上线了。
TapTap

一、地图选择:先把「地图」这个概念从代码里拆出来

起因:一个按钮决定的命运
上线前的首页只有一个「开始游戏」按钮,点下去固定进入 18 站成长局。玩家不能选战场,也没法为不同拓扑的城市做准备。
但真正的问题在数据结构,而不是 UI:
「地图」在这款游戏里,当时根本不是一个独立概念。
站点表、边表、桥梁、初始开放站,全部硬编码在「模式」的分支里。growth/weekly 走 18 站扩展图,short/middle 走 12 站基础图,tutorial 走 6 站教学图。
也就是说:「换地图」等价于「换模式」。
想做「选地图」,必须先把地图从模式里拆出来。
拆法:让 mapId 成为独立参数
新建一张地图注册表,把站点和道路数据变成声明式定义:
Maps.DEFS.riverside = {
    id = "riverside",
    name = "滨江",
    stations = { { name = "松林社区", kind = "home", x = 190, y = 250 }, … },
    edges = { … },
    bridges = { 8, 14 },
    lineCount = 5,
}
然后让 mapId 沿着 mode/seed 的透传链一路走下去——建世界、重建、存档全部带上它。
这里有个必须说清楚的边界:这一期 mapId 只对成长局生效。教学、中局、短局、周历各自回到固定图。为什么?因为周历的事件表是写死站号的(「第 3 周开放 17、18 号站」),换一张站数不同的图,它会去取一个不存在的站点,运行中直接崩。
这个坑是加第二张图之后才暴露的:玩家在棋盘城用成长局玩,中途切「周历」模式,程序沿用 mapId="starter" 去建 16 站图,而周历剧本要开 17、18 号站 —— 取到 nil,崩。
修复只有一行:进世界时,非成长局强制把 mapId 清空,回默认图。
第二张图:棋盘城
有了选图功能,自然要有一张**「第一眼就懂」**的入门图。于是新增「棋盘城」:
  • 4×4 规整方格,16 站,24 条边,无桥、无对角线;
  • 从中心三站的 L 形向外一圈圈生长,每波新站必与已开站相邻;
  • 开局极小:1 辆车、1 条线、3 个站(对比滨江的 4 车 / 3 线 / 5 站)。
原来的 18 站图降为「滨江 · 进阶」,保留双桥瓶颈、5 条线、3 种车型。
这里有个设计上的选择值得说:入门的「易」,不靠砍时长。
两张图的局长都是 600 模拟秒,都是每 40 秒开一个新站,成长弧线完全对齐。棋盘城的「易」来自:
  • 开局极小(1 车 1 线,玩家不会被资源淹没);
  • 无桥(没有瓶颈,怎么改线都通,容错高);
  • 线路最多 4 条,不引入快速公交(只引入大容量)。
难度是靠机制的减法降下来的,不是靠稀客流或短时长。这样从入门图毕业到滨江,玩家面对的是同一套规则、更复杂的拓扑。

二、自动存档:为什么必须走云

一个把本地文件判了死刑的场景
需求很简单:刷新页面后还能接着玩。
但 Web(WASM)上,本地 File 写在内存文件系统里,页面一刷新就没了。而「刷新后还能继续」恰恰是核心场景——本地文件存档在这款游戏里没有意义。
所以存储走 clientCloud,按 TapTap 账号在服务端持久化。
存档最难的不是「存」,是「恢复后世界还得是活的」
朴素地逐表转 JSON 会复制对象、打断仿真。有三处对象同一性必须重建:
  1. 乘客:站台候车列表、车内货舱、世界乘客表,必须是同一张表;
  2. 服务:车指向的服务对象,必须就是服务注册表里的那一张;
  3. 道路队列:不存队列本身,加载时由车辆位置重建。
第 2 条踩过一次:服务表的键是 bus.service.id,不是 bus.lineId。两者在正常情况下相等,但换线失败的分支会把 lineId 写成 service.id,并不总是相等。存错键,读档后车就挂到了错误的服务上。
cjson 的两个陷阱
  • 稀疏整数键:world.trips 在滤掉已送达乘客后会变得稀疏,而 cjson 对「键不连续的数字表」往返不可靠。一律序列化成记录数组,加载时重建键表。
  • math.huge:有些站点标记是「永不到来」,值是 math.huge,JSON 无法编码。读取侧本来就是「取不到就当无穷大」,所以编码前统一过滤掉非有限值即可。
只存「还在路上的人」
world.trips 只增不减(每个乘客一条,永不清),跑长局会撑爆存档体积。
裁剪依据是:已送达的乘客不再被任何逻辑读取。所以只存「候车 ∪ 在途」,体积收敛到「站点容量 + 车队容量」。
两个真实踩的坑
坑 1:把云判成不存在。
守卫最初写的是 if type(clientCloud) ~= "table" then return nil end。但 clientCloud 是引擎绑定对象,Lua 侧是 userdata 不是 table。于是明明有云,却被判成「没有云」,白回落到内存后端——表现就是「返回首页后没有继续游戏」。
正确的存在性判断只有一种:
if not clientCloud then ... end   -- ✅
坑 2:一个跨场景存活的标志。
修完上面这个,返回首页仍然显示「开始游戏」。查下来是:点「开始游戏」时记录了一个「当时没存档」的探测标志,返回首页时正确渲染成「继续游戏」,但下一帧主循环看到那个陈旧标志,又把按钮打回了「开始游戏」。
教训:凡是「回调只写标志、由每帧 Update 消费」的模式,标志的生命周期必须和它所属的那块界面同生共死,否则跨场景会串味。
存档节奏
两条触发:真实秒计时器(12 秒)是主保证;有结构变更(改线、投车、开站)时提前落盘。
为什么不能只靠「有变更才存」?因为时钟推进、车辆移动、上下车、需求生成都不算结构变更——纯靠变更触发会漏掉大部分进度。

三、排行榜

排行榜看着简单,实际上大部分工作量在「网络不可靠时怎么办」:
  • 空榜返回的是一个特定错误码,要当成「暂无数据」而不是报错;
  • 回调可能根本不触发 → 5 秒看门狗强制降级 + 0.5 秒延迟显示(防闪烁);
  • 昵称接口没有超时 → 昵称非阻塞,先占位显示「玩家」,拿到后刷新列表;
  • 切换地图 Tab 时如果不清数据,会显示上一张图的榜单 → 请求带上代数标记防竞态。
上线前抓到的一个严重 bug
测试时发现失败局的分数有时不进排行榜。
一开始怀疑是排行榜读取问题,或者是结算没计分。查下来都不是——是提交前的「云端基线」没就绪。
提交流程需要先知道「云端纪录是多少」才敢写(否则无法判断是否破纪录,只能暂存)。而基线的加载,当时只在选图页里触发一次:
玩家路径  经过选图页吗  结果
首页「开始游戏」→ 选图页 → 进局  ✅  基线就绪,分数正常写云
首页「继续游戏」读档进局  ❌  基线未就绪,分数只进暂存,不写云
教学完成后开局  ❌  同上
所以这跟胜负无关——走读档路径的胜利局同样会丢,只是恰好在失败局上被注意到。
修复是在入口层保证:所有注册地图都加载过基线才放行,在「首次进游戏 / 新局 / 读档续玩」三个入口都调用;同时让提交自身也能在基线缺失时自愈补一次。
这个 bug 值得一提的地方是:它只在特定入口路径下出现。如果测试永远从「开始游戏」进去,永远发现不了。

四、教学:从 10 步收敛到 9 步

上线前又重构了一次
上一篇日志里,教学是 10 步。上线前我们把它收敛成了 9 步:
连接 → 延长 → 成环 → 加车 → 加站 → 第二条线 → 断环 → 缩短 → 金线
主要变化是把「环线」提前到了第 3 步。
原来的顺序是先教一堆基础操作、最后才碰环线。但实际试玩下来发现:成环和断环才是这款游戏最有特色的操作,也是最能体现「同一套规则在更大网络里产生复杂问题」的地方。把它埋在后面,玩家可能还没玩到就退出了。
现在的第 3 步就是:把一条线首尾连起来,看它变成环线;第 7 步再把它断开。一开一合,玩家就理解了环线和往返线的区别。
引导动画也跟着做细了
每一步的引导不再是「一句文字 + 一个高亮圈」,而是按操作类型播放对应的手势动画:
操作  引导动画
建线 / 延长  从起点拖向终点的手指轨迹
加站  拖动线路段到新站
成环 / 断环  拖住 T 型柄
缩短  端点柄拖到空白(循环播放)
同时调整了数值:第 4 步的候客人数减半、开局只放 2 个人——教学期的目的不是考验玩家,是让他看懂规则。
教学完成后的引导
教学完成会写一个云变量标记。回到首页后:
  • 教学按钮的排序会变(已完成的玩家,主按钮优先);
  • 文案会调整,引导玩家去「开始游戏」而不是反复重玩教学。
一个必须记住的 Modal 坑
教学完成后的结算界面有三个按钮:再次教学 / 开始游戏 / 返回首页。
第一次实现时,点「开始游戏」完全没反应。原因是:结算界面本身是一个打开的 Modal,它吞掉了新界面的全部点击。
修复方式是:按钮回调里先关闭 Modal 摘掉遮罩层,再切换场景。
这个坑记在这里是因为它很典型:残留的打开态弹窗会吞掉整个新界面的事件。任何「弹窗里换场景」的地方都要注意。

五、回到「涌现」

这四件事放在一起看,其实回答了同一个问题:
玩家怎么才能真的开始玩,并且愿意再玩一局?
  • 地图选择 → 让不同水平的玩家都能找到合适的起点(棋盘城 vs 滨江);
  • 自动存档 → 让「一局 10 分钟」这件事变得可以被打断,玩家不必一次玩完;
  • 排行榜 → 让「再玩一局」有了外部理由,也让规划水平变得可见;
  • 教学收敛 → 让新玩家在前三分钟就摸到这款游戏最有特色的操作。
而它们共享同一条底线:每一个数字都必须是真的。
最高分是真的、排行榜是真的、存档恢复出来的世界是真的(跑 600 帧逐步一致)、教学里那个「环线」也是真的在闭合。

六、下一步

  • 第三张图:环状卫星城 / 双岸桥城这类「专属机制」地图;
  • 周历适配选图:需要先把周历事件表里写死的站号解耦;
  • 成就系统:目前还没有,有了之后可以扩展成就榜;
  • 继续打磨真机体感:触摸热区、手指遮挡。
这四件事收尾之后,《公交公司》正式上线了。欢迎来玩:https://www.taptap.cn/app/965953
如果你玩过之后想聊聊:棋盘城和滨江你更喜欢哪张?你觉得入门图还该再简单一点,还是可以更早引入桥梁和快速公交?
#聚光灯gamejam开发者日志 #公交公司
【童谣镇】聚光灯第二次开发日志截图
【童谣镇】聚光灯第二次开发日志
开发进度: 美术 1、主角人物立绘已细化完成 2、所有NPC的QQ人形象与呼吸动画已设计完成 3、大部分UI界面已设计完成 4、面包房建模与树屋建模以及基础房屋、路灯、树木模型已完成。 5、制作过场动效,制作通用动效材质ing 6、广场资产替换、永续桥和植被的资产替换、房屋资产替换,河流制作 7、学校模型的材质完成 8、石墩子、小道具模型制作ing 9、NPC正比胸像绘制ing 策划 1、任务系统
11 赞
10 回复
《卡牌工业》开发日志 01|从“涌现”到产线对打截图
《卡牌工业》开发日志 01|从“涌现”到产线对打
大家好,我们正在用 Godot 做一个暂名《卡牌工业》的游戏。目前已经跑通了最小的生产与战斗循环,也做了两轮迭代。这篇先记录一下:面对“涌现”这个题目,我们讨论过什么,又为什么最后收敛到卡牌和工厂。 第一步:头脑风暴,涌现可以是什么? 刚看到“涌现”这个题目时,我们的想法几乎朝每个方向散开了。塔防、物理搭建、探索、解谜、经济系统、叙事,甚至增量游戏,都能让简单规则在玩家的操作中长出新的结果。再想下
1 回复
00:30
《失心》游戏开发者日志01|游戏UI迭代及实机演示截图
《失心》游戏开发者日志01|游戏UI迭代及实机演示
进入《失心》之前,玩家首先看到的是我们工作室 UNLOOK 的标识。我们将原来的标识转成 SVG,并让其中的红色瞳点转动、观察,再逐步显露完整字形,希望这个短暂的开场能带出一点好奇和不安。 这次《失心》的开局 UI,我们围绕小灵通(因为游戏的主要交互道具就是小灵通)做了几轮调整,希望玩家从打开游戏开始,就能感受到故事里的年代和气氛(故事年代背景为2000s)。 早期版本先确定了一个方向:把菜单放进
15 赞
10 回复
00:34
《荒原复苏指南》开发日志④:关卡演示堂堂袭来!!截图
《荒原复苏指南》开发日志④:关卡演示堂堂袭来!!
- 人类曾因掌握元素合成技术而一度辉煌,又因滥用元素能量而逐渐从内里衰败。 - 30世纪80年代。社会文化充斥着激进乐观主义与庞大机械美学,在这里,污染和能源共生,幸福与痛苦并存。官方广播和宣传画里依旧在宣扬“科学将战胜一切”、“元素能量将再造新农田”的口号,而世界主城却已经因为污染过度而濒临崩溃、空间挤压严重。为了寻找新的生存空间与无污染能源,官方启动了“重构拓荒计划”。 - 玩家将作为前线拓展
18 赞
6 回复
《气味之城》开发日志#1|为什么"涌现"和猫是天作之合截图
《气味之城》开发日志#1|为什么"涌现"和猫是天作之合
大家好,我是一个人报名了 2026 聚光灯 21 天游戏创作挑战 的独立开发者。今年主题公布那一刻我就笑出了声——涌现。因为我已经想做这个游戏很久了: 《气味之城》:你不是猫神,你只是一只猫。 先说一个所有养猫人都懂的事实:你永远无法"教会"一只猫任何它自己不想学会的事。但你家猫可能自己学会了——听见冰箱开门就瞬移到厨房;你心情不好时过来踩奶;凌晨三点准时在你身上练马拉松。没人教过它,这些行为是它
3 赞
6 回复
00:10
群迹·上取其下,下取其上截图
群迹·上取其下,下取其上
#聚光灯gamejam开发者日志 向大家汇报一下今日进度,目前在和蚁群的默认移动算法进行斗智斗勇。或许是我的AI对蚂蚁有别样的理解,其实最初写出的方案更接近于围绕着恒星公转的行星。 哦我还以为文章里可以插入多支视频视频,想要展示一些其它的运动方式,可惜了。那么就简单在上方传一个比较典型的,有点类似于蟑螂的运行方式。 目前仍在解决蚁群的随机运动,和玩家可操纵性之间的平衡问题。以及如各位所见,目前的
4 赞
1 回复
【2026聚光灯日志01】什么叫你把手牌,骰子和战棋融合了?截图
【2026聚光灯日志01】什么叫你把手牌,骰子和战棋融合了?
大家好啊,我是官方小编,一位还在学校的独自开发的苦逼带学生 这次算是第二次正式参加GameJam,而这回的比赛主题是【涌现】 嗯…老实说,一开始我还真只是从中文语义上来看,理解成“大量的出现”,直到询问ai哦哦哦我这就才想起来还有英文的“整体大于部分之和”意思来着 说起这个主题的意思,立马想起的类 吸血鬼幸存者 ,或者是 文明 系列的各种爆怪,爆兵的设计,即大量的出现敌人或者单位 而从第二个
4 赞
4 回复
开发者日志#01:涌现!! 披着科幻外衣的涌现式增量游戏!!!!截图
开发者日志#01:涌现!! 披着科幻外衣的涌现式增量游戏!!!!
随着Game Jam 主题公示,我们团队立马着手维持了三天的激烈讨论!决定做一个披着科幻外衣的蚂蚁农场以boids算法为灵感的涌现式增量游戏!!! 至此,方案敲定,我们团队将开发一个可升级的自主群体模拟,并且初步规划了玩家游戏时的体验流程: (1)阶段1(开局30s,触发痛点,会有一次提升,但是游戏仍然艰难):一张地图分布着资源点和仓库,玩家此时只能徒手采集资源点的矿石拖入仓库,矿石可以造机器人;
14 赞
7 回复
00:07
雨天決行 开发者日志02-人工智能的自我修养截图
雨天決行 开发者日志02-人工智能的自我修养
又和大家见面啦!第二篇日志,说实话一开始不知道该怎么编排,但团队里惊喜的成果越来越多,我们已经迫不及待把更新的内容端上来给大家啦!那么事不宜迟,快来看看都有什么新情报吧ദ്ദി˶ー̀֊ー́ )✧ 一.美术(重磅升级) 以主美小为的生命力作为燃料(bushi)本次美术组取得了大进程!首先是各个ui界面的优化和细化,上次大家看到时还只是初具雏形的草稿,现在大多都完整起来了哦! 同时,随着配色的补全,手
43 赞
36 回复
00:48
Day1 《逆种》截图
Day1 《逆种》
《逆种》 俯视角快节奏近战动作 Roguelite。 你的打法是自然选择,5 层进化的终点,最终 Boss「逆种」是你亲手培育的克星。 一局 8-15 分钟,死亡即收获,你的怪物通过分享码替你和全世界打。 一、九项核心决定 # 决定项 结论 1 战斗手感 近战为主·哈迪斯风(轻三连段/蓄力重击/冲刺割裂/处决) 2 进化透明度 渐进式透明(表型可视化 → 仪式 diff → 扫描仪 DNA 面板)
4 赞
6 回复