下载 App
开发日志④|让子弹不堵车:子弹工厂背后的交通模拟
在《多米诺的子弹工厂》里,子弹沿着轨道前进,看起来像是一件很简单的事:让它们往前移动就好了。
但当子弹开始排队、转弯、汇合,或者一座炮台快装满时,“往前走”就没那么简单了。谁先通过路口?后面的子弹该停在哪里?转弯时会不会撞上另一条轨道来的子弹?如果画面卡了一下,子弹会不会直接跳过这些判断?
上一篇日志里我们提到,玩家的热情超出了预期。人一多,工厂的规模也被推着往上走:生产线搭得越复杂,那些平时藏得很好的问题就越容易被撞见。距离投稿截止越来越近,我们这段时间做的反而更琐碎——不是加新内容,而是让已经搭好的东西不再出错。这篇开发日志,想聊聊其中看不见的那些交通规则。
先让仿真时间稳定下来
游戏画面是一帧一帧绘制的,但画面帧率可能变化。如果直接按照每帧经过的时间移动子弹,卡顿时子弹可能一下走很远,让碰撞或路口判断来不及处理。
所以,工厂的实时仿真采用固定步长:每一步推进 1/60 秒。每次更新累积经过的时间,再按照这个固定间隔处理仿真。为了避免卡顿时一帧里补算太多,实时运行时每帧最多处理六步,并以约 8 毫秒作为让出预算;没来得及处理的仿真时间会留到后续帧继续推进。
简单来说,我们尽量不让一帧突然变成一大步,而是把它拆成一连串更容易判断的小步。
子弹走的不是“瞬移路线”

每颗子弹都记录了自己所在的格子、行进方向,以及当前处于进入格子还是离开格子的阶段。移动时,它会沿着当前路段前进;来到格子中心,就处理路由和设施效果,再继续走下一段。
这很重要,因为一次移动可能经过转角,甚至正好经过一个加工设施。如果只检查子弹移动前和移动后的坐标,中间发生的事就可能被跳过。
子弹之间还有一条安全规则:中心间距至少要保留 0.4 格。判断时不能只看移动前有没有撞在一起,而要检查这一小段移动过程中,子弹最早会在什么位置进入彼此的安全距离。算出这个位置后,就在到达那里之前停下。换句话说,子弹不是撞上了才停,而是在快要撞上的那一刻之前就停住了。
这样,画面帧率变化或移动速度加快时,子弹也不应该因为跨过了一段距离,就穿过前面的队伍。
同一条队伍,前面的先走;到了路口,再分配通行权

在直线路段上,后面的子弹需要跟着前面的队列移动。因此仿真会先识别同一车道上的前后关系,让前面的子弹先更新,后面的再根据安全距离跟进。
但到了汇合处,不同方向的队伍会争用同一个中心位置。这个时候,单纯按数组顺序移动就不够了:某个方向的后排子弹,不能抢在自己队首前面通过;没有拿到通行权的子弹,也要在进入中心前停下。
炮台这类有容量上限的入口还要多考虑一步:已经在路上的来弹也会占用预留容量,不能因为几条线路同时供弹,就让抵达数量超过弹仓所能容纳的上限。
玩家看到的是一颗颗子弹继续前进;仿真需要处理的,则是队列、路口和容量之间的协调。
不让每颗子弹都检查整个工厂
如果每次移动都让每颗子弹逐一检查场上的其他子弹,工厂越拥挤,需要做的检查也会越多。
目前的做法是先按格子把子弹分组,移动检测时只查询附近可能发生接触的区域;沿直线前进时,也优先查看前方相关的格子。临时使用的队列和候选列表会尽量复用,减少重复创建。
这里有一个取舍:可以缓存“附近有哪些子弹”,但不能把它们的当前位置或方向也当成不变的数据。子弹每一步都会移动、转向,所以真正判断安全距离时,仍然要根据它们此刻的状态重新计算。
换句话说,可以复用找人的名单,不能拿昨天的位置当作今天的位置。
一颗子弹卡住,可能是整条交通规则的问题
更新记录里,我们修复过一种情况:子弹从侧面进入动力发电机的直通轨道时,可能卡住整条竖直车流。
这类问题看起来像是“某颗子弹不动”,排查时却需要一起观察它所在的格子、行进方向、移动阶段、前方间距,以及路口的通行状态。只盯着画面上的一个位置,很难判断问题出在路径连接、队列顺序,还是路口让行规则。
因此,仿真里也有专门的停滞诊断:当场上有未满的炮台、子弹却持续没有移动时,会记录一份有限的状态快照,帮助定位子弹当时的位置、进度和安全距离,而不是每一帧都输出大量日志。
让复杂工厂也能按规则运转
轨道交通这部分的目标,不只是让子弹从起点抵达炮台,而是让直线排队、转角、汇合和满仓等待,都遵守一致的规则。
这些技术细节不会直接出现在玩家的操作说明里,但它们决定了玩家能不能安心地搭建更复杂的生产线。工厂越忙,子弹越多,交通规则就越要清楚。
我们想让玩家专注于设计自己的工厂,而不是被不明原因卡住的子弹打断思路。
把这些规则立清楚,还有一层我们更在意的原因:只有当玩家相信子弹会按规则移动,他们才敢把工厂搭得更复杂、更冒险。而那些我们自己都没预料到的组合,恰恰是在这种复杂度里冒出来的。











