火车调度模拟器
3D 俯视角策略游戏:设计并实现车站调度、列车寻路与客流量系统的完整玩法循环。
职责
策划 / 程序
引擎
Unity
团队
2 人团队
周期
2025.10 – 2025.12
项目概述
《Trainline》由三样东西构成:铁路、车站与列车。每一关都交给玩家一张既有的铁路网,以及一批暂时停运的列车。玩家的任务是为这些列车重新规划路线,并处理每个车站不断堆积的客流。
玩家在锁定的 2.5D 俯视视角下工作,通过四种模式——观察、路线规划、时刻表、客流量——进行操作,并可随时暂停时间来思考。

设计起因与目的
这个设计并非从"火车情怀"出发,而是从对真实铁路如何组织、以及为何会失灵的调研开始。
两种组织模式。 英国铁路把职责拆开:唯一的基础设施提供方(Network Rail)负责轨道建设与维护;线路运营商(TOCs)负责司机、乘务、列车日常维护、售票、服务通告与旅客信息发布,以及时刻表的执行;而铁路运营中心(ROC)负责列车路径规划、时刻表调整与信号控制,并通过 ETCS(车载-轨道控制系统)加上 TMS(列车改线、列车优先级、故障绕行)不断数字化。中国铁路则将这一切集中于单一运营主体。正是这种权责对比让"调度"变得有趣:权力是分散的,因此每个决策都必须与时刻表相互博弈。
列车为何会晚点。 约 40% 的延误源于基础设施故障——信号通路故障、道岔故障、供电系统故障、线路封锁与线路检修。其余则来自车辆故障(牵引系统、制动、门控、空调、控制单元,或 ETCS 设备掉线被迫转入手动运行)、人员事故(司机与乘务迟到、排班冲突)、事故与恶劣天气、罢工与安检加强,以及最后一类——系统性问题,其中最关键的是:时刻表过密时,一列车慢,全线皆慢。
成为游戏核心的连锁反应。 最后这一类会产生一条链条:
[信号故障] → [A 车停车] → [B 车等信号] → [C 车改线且低速运行] → [枢纽车站被占用] → [后续列车连带晚点] → [全线时刻表位移]
这条链条正是这款游戏真正的主题。我没有去模拟每一种故障模式,而是把针对它的运营应对——让行与列车优先级——提炼为玩家的核心决策。由此确立的目标是:在不产生延误与事故的前提下,最大化客流量。
设计框架
资源。 城市与车站拥有客流量、列车吞吐量与乘客上车速度。铁路线分为慢车轨、快车轨与高铁三个等级,列车分为普速、快车、高速与磁悬浮四个等级——并附带约束:高等级列车无法在低等级轨道上运行。金钱把这一切串起来:铁路维护消耗货币,客流量带来收入,而铺设线路、造车与雇人则消耗它。
每日循环。 列车每天遵循同一份时刻表,包含发车与到站时间以及检修窗口,且时刻表在每次到站时刷新。
玩家动作。 设置停站等待,让列车为更高优先级的车次让行;设置区间速度,让优先列车快速通过;增开车次以疏运更多客流并提升收入;新增铁路线。
策略与预期的领悟。 在客流量与收入之间取得平衡,决定了一条铁路的优先级;而希望玩家自行发现的最优解其实很简单:速度越快,优先级越高。 成败由两个数字评判:延误列车数与事故数。
范围决策。 为了让玩法循环保持清晰,我很早就固定了几条规则:允许每天的客流盈余不断累积,直到玩家找到能满足需求的方案;列车碰撞立即结束游戏;玩家始终可以暂停时间来编排调度;难度通过多关卡与多列车递进,而不是靠堆叠新机制。

系统架构
我把游戏拆解为若干模块,并将每个模块描述为 View / Control / Mediate 三元结构,使表现、输入与权威状态始终可以分离:
- Camera Controller——锁定的 2.5D 俯视视角,WASD 平移与缩放。
- 列车运动系统——View:沿路线行驶的动画与音效。Control:列车数据(当前站点、速度、路线引导)。关卡工具:以样条(Spline)表示铁路路径,用以限制列车可行驶的范围。Mediate:路线维护——新增路线、修改路线、记录修改时间——并向调度系统与关卡系统提供调用接口。
- 列车调度系统——View:与列车运动相互独立的路线设置面板,以及时刻表设置面板。Control:点选式的路线输入与滑条式的到发时间编辑。Mediate:当前生效的时刻表。
- 客流量系统——View:每日站点客流 UI。Control:关卡驱动,各区域(苏格兰 / 欧洲 / 中国)中每个车站的客流需通过关卡设计与难度测试来评估;列车通过会减少客流。Mediate:读取时间,每日刷新。
- 时间系统——View:时钟 UI。Control:可调节的时间流速。
- 轨道事件——View:快车紧随慢车并鸣笛的状态动画。Control:快车接近前方慢车时降速至与其一致。

过程中的思考
开发从 2025 年 10 月 11 日持续到 12 月 16 日。日志清楚地记录了中途一次重心转移。
前期阶段的目标被明确定义为搭建框架、实现功能:镜头设置、TrainMoveOnSegment、SetRoute、高亮所选车站、将构成路线的车站与铁路排列成序列,以及当样条被反向绘制时翻转行进方向。到 11/22,TrainManager 中的时间线已经能够设定一次行程的站点顺序;到 11/23,客流量已成为真实的数值量,配有事件动作与 UI 读数。
11/24,目标转向"改善用户体验"。 正是这次转向塑造了游戏的质感。时间以固定比例与真实时间挂钩——游戏中 1 秒等于 30 分钟,因此一整天耗时 48 秒——并划分为 5:00–24:00 的白班与 0:00–5:00 的夜班。列车获得了状态,TrainManager 开始以事件形式维护发车计划,并读取 TimeController 以保证准点发车。
第二天暴露出一个值得记录的建模问题:长途列车一天可能只跑一个循环,而短途列车一天可跑多个循环。状态机因此被迭代为运行中 / 停靠中 / 等待发车 / 检修,其中"上客不会唤醒列车"是刻意的设定,同时锁定了一条规则——列车每天的始发站与最终返回站必须相同。 正是这条规则,让界面坚持要求路线必须成环。

UI 设计在 11/27 展开,随后进入实现:RouteEditPanel 从后端读取所选列车的信息,并允许玩家连接站点,配合基于碰撞体的车站按钮、List<Station> 存储、长度检测与路线序列追加;TimeTablePanel 则为每段铁路提供滑条,显示到达站、列车图标与时间戳,并随真实时间推进。

12/04 加入了游戏模式切换器(Num 1 常规、Num 2 路线规划、Num 3 时刻表规划),在关闭面板的同时切换输入模式——于此,操作卡上的四种模式成为一套连贯的状态机,而不再是彼此重叠的 UI。
12/07 的 SchedulePlanPanel 是实现中最具设计驱动色彩的一块。列车初始化时,面板会生成时间线列与时刻表色块,而每个色块的宽度由铁路长度除以速度计算得出——因此时刻表本身就是物理运行时间的直接可视化。拖动色块左缘设定某站的发车时间,右缘设定目标站的到达时间,这让"排时刻表"成为一种空间操作,而非填数字。

遇到的困难与解决方案
拖动相邻滑条时的闪烁(12/15)。 原因:滑条的 DepartTime 被更新了两次,因为被拖动的色块同时包含了鼠标光标下方的那一块。解决方案:只有光标之下的变更在 OnDrag 中处理;其余受影响的色块改由独立函数更新,而不再被卷入同一次拖拽。
时刻表未能及时反映路线变更(12/15)。 原因:时刻表打开的时机与色块面板刷新的时机被绑在一起,且色块在每次 initialize 时都会自动对齐到最左端,导致编辑被覆盖。设想的方案:每次打开时刻表都重新读取路线,即在每次 OnEnable 时初始化;并让时刻表常驻后台运行,仅做显示与隐藏。最终解决:色块仅在首次重定位之后、或被路线编辑器重置之后才对齐到最左端,此后跳过对齐流程。
路线设为非闭环时被销毁(12/15)。 通过优化闭环检测逻辑解决——这正是"每天始发站与终点站相同"这条规则的直接后果。
新的一天列车未能重新发车(12/05)。 与 TrainRouteEditor 的工作一并修复,使每日循环真正能够重启。
客流量可视化中的选取歧义。 选中车站来查看客流存在歧义,因此改为在选取时高亮铁路而非车站。
快车与慢车的追尾。 这个问题是用设计而非代码来回答的。由于碰撞会立即结束游戏,玩家必须在事故发生前就能读出风险:快车逼近前方慢车时会自动降速跟随、闪烁红灯并鸣笛,同时时刻表面板会提前显示可能的冲突。而预期的应对方式——慢车在车站停车让行——正是调研中所识别出的"让行"行为。
交付成果与后续计划
《Trainline》完成了一个包含独立关卡的可运行 Demo。该周期内交付的内容包括:铁路、车站与列车的基础运行逻辑;三套 UI 系统(RoutePlanPanel、TimeTablePanel 与 PassengerFlowUI);符合风格设定的大部分场景美术资源;每日里程上限与每日站点客流更新;以及带有客流目标与胜利界面的第一关。我们两人在各自的版本分支上推进,并在最后一周完成美术与程序的整合。
已完成设计但尚未实现,也是我接下来会补上的部分:
- 轨道事件系统——把列车碰撞做成实时事件,并将列车检修时间作为一种排班约束。
- 商店系统——列车交易与车站升级,这会让"金钱"这项资源真正成为一个决策层。