feat: initialized drawio file

This commit is contained in:
merlin
2026-02-06 18:05:57 +08:00
parent 08efed33d0
commit 2f60d57c12
3 changed files with 790 additions and 0 deletions

122
echoes_of_transit.drawio Normal file
View File

@@ -0,0 +1,122 @@
<mxfile host="Electron" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/29.3.0 Chrome/140.0.7339.249 Electron/38.7.2 Safari/537.36" version="29.3.0">
<diagram name="第 1 页" id="03zPjMSEeT14o3F0pt60">
<mxGraphModel dx="1577" dy="1103" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="2336" pageHeight="1654" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="ASVp9LyKSrMTWFK9v5q_-55" parent="1" style="swimlane;whiteSpace=wrap;html=1;" value="trip model" vertex="1">
<mxGeometry height="870" width="580" x="60" y="70" as="geometry">
<mxRectangle height="30" width="90" x="60" y="70" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-85" parent="ASVp9LyKSrMTWFK9v5q_-55" style="swimlane;whiteSpace=wrap;html=1;" value="station or stop" vertex="1">
<mxGeometry height="260" width="300" x="40" y="300" as="geometry">
<mxRectangle height="30" width="140" x="80" y="500" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-86" parent="ASVp9LyKSrMTWFK9v5q_-85" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" value="person" vertex="1">
<mxGeometry height="160" width="109" x="10" y="30" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-87" parent="ASVp9LyKSrMTWFK9v5q_-86" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;autosize=1;resizable=0;" value="O&amp;amp;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;D&lt;/span&gt;&lt;div&gt;出发地与目的地&lt;/div&gt;" vertex="1">
<mxGeometry height="40" width="109" y="30" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-88" parent="ASVp9LyKSrMTWFK9v5q_-86" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="waiting&lt;div&gt;等待忍耐时间&lt;/div&gt;" vertex="1">
<mxGeometry height="30" width="109" y="70" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-89" parent="ASVp9LyKSrMTWFK9v5q_-86" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" value="by当前经由" vertex="1">
<mxGeometry height="30" width="109" y="100" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-90" parent="ASVp9LyKSrMTWFK9v5q_-86" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;autosize=1;resizable=0;" value="transfer换乘站" vertex="1">
<mxGeometry height="30" width="109" y="130" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-91" parent="ASVp9LyKSrMTWFK9v5q_-85" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;autosize=1;resizable=0;" value="..." vertex="1">
<mxGeometry height="30" width="30" x="258" y="85" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-92" parent="ASVp9LyKSrMTWFK9v5q_-85" style="whiteSpace=wrap;html=1;" value="统计器" vertex="1">
<mxGeometry height="30" width="100" x="10" y="200" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-93" parent="ASVp9LyKSrMTWFK9v5q_-85" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" value="person" vertex="1">
<mxGeometry height="160" width="128" x="130" y="30" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-94" parent="ASVp9LyKSrMTWFK9v5q_-93" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;autosize=1;resizable=0;" value="O&amp;amp;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;D&lt;/span&gt;&lt;div&gt;出发地与目的地&lt;/div&gt;" vertex="1">
<mxGeometry height="40" width="128" y="30" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-95" parent="ASVp9LyKSrMTWFK9v5q_-93" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="waiting&lt;div&gt;等待忍耐时间&lt;/div&gt;" vertex="1">
<mxGeometry height="30" width="128" y="70" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-96" parent="ASVp9LyKSrMTWFK9v5q_-93" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" value="by当前经由" vertex="1">
<mxGeometry height="30" width="128" y="100" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-97" parent="ASVp9LyKSrMTWFK9v5q_-93" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;autosize=1;resizable=0;" value="transfer换乘站" vertex="1">
<mxGeometry height="30" width="128" y="130" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-98" parent="ASVp9LyKSrMTWFK9v5q_-85" style="whiteSpace=wrap;html=1;" value="途径线路&amp;amp;对应站序" vertex="1">
<mxGeometry height="30" width="130" x="130" y="200" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-99" parent="ASVp9LyKSrMTWFK9v5q_-55" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" value="person" vertex="1">
<mxGeometry height="160" width="128" x="126" y="60" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-100" parent="ASVp9LyKSrMTWFK9v5q_-99" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;autosize=1;resizable=0;" value="O&amp;amp;&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(0, 0, 0), rgb(255, 255, 255));&quot;&gt;D&lt;/span&gt;&lt;div&gt;出发地与目的地&lt;/div&gt;" vertex="1">
<mxGeometry height="40" width="128" y="30" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-101" parent="ASVp9LyKSrMTWFK9v5q_-99" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;" value="waiting&lt;div&gt;等待忍耐时间&lt;/div&gt;" vertex="1">
<mxGeometry height="30" width="128" y="70" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-102" parent="ASVp9LyKSrMTWFK9v5q_-99" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" value="by当前经由" vertex="1">
<mxGeometry height="30" width="128" y="100" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-103" parent="ASVp9LyKSrMTWFK9v5q_-99" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;autosize=1;resizable=0;" value="transfer换乘站" vertex="1">
<mxGeometry height="30" width="128" y="130" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-104" edge="1" parent="ASVp9LyKSrMTWFK9v5q_-55" source="ASVp9LyKSrMTWFK9v5q_-99" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;" target="ASVp9LyKSrMTWFK9v5q_-85" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="36" y="170" as="sourcePoint" />
<mxPoint x="86" y="120" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-105" parent="ASVp9LyKSrMTWFK9v5q_-55" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;autosize=1;resizable=0;" value="bywalk" vertex="1">
<mxGeometry height="30" width="70" x="196" y="235" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-106" edge="1" parent="ASVp9LyKSrMTWFK9v5q_-55" source="ASVp9LyKSrMTWFK9v5q_-85" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" target="ASVp9LyKSrMTWFK9v5q_-108" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<Array as="points">
<mxPoint x="190" y="620" />
</Array>
<mxPoint x="206" y="730" as="sourcePoint" />
<mxPoint x="190" y="680" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-107" parent="ASVp9LyKSrMTWFK9v5q_-55" style="rounded=1;whiteSpace=wrap;html=1;" value="bywalk&lt;div&gt;步行到达最终目的地&lt;/div&gt;" vertex="1">
<mxGeometry height="60" width="120" x="366" y="760" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-108" parent="ASVp9LyKSrMTWFK9v5q_-55" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" value="判断条件&amp;amp;权重分配" vertex="1">
<mxGeometry height="120" width="140" x="356" y="560" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-109" parent="ASVp9LyKSrMTWFK9v5q_-108" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" value="剩余距离" vertex="1">
<mxGeometry height="30" width="140" y="30" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-110" parent="ASVp9LyKSrMTWFK9v5q_-108" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" value="时间差异" vertex="1">
<mxGeometry height="30" width="140" y="60" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-111" parent="ASVp9LyKSrMTWFK9v5q_-108" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" value="价格差异" vertex="1">
<mxGeometry height="30" width="140" y="90" as="geometry" />
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-112" edge="1" parent="ASVp9LyKSrMTWFK9v5q_-55" source="ASVp9LyKSrMTWFK9v5q_-108" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" target="ASVp9LyKSrMTWFK9v5q_-85" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<Array as="points">
<mxPoint x="426" y="430" />
</Array>
<mxPoint x="426" y="540" as="sourcePoint" />
<mxPoint x="476" y="490" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="ASVp9LyKSrMTWFK9v5q_-113" edge="1" parent="ASVp9LyKSrMTWFK9v5q_-55" source="ASVp9LyKSrMTWFK9v5q_-108" style="shape=flexArrow;endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="ASVp9LyKSrMTWFK9v5q_-107" value="">
<mxGeometry height="50" relative="1" width="50" as="geometry">
<mxPoint x="406" y="740" as="sourcePoint" />
<mxPoint x="456" y="690" as="targetPoint" />
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@@ -0,0 +1,358 @@
# 《路网回声 Echoes of Transit》项目策划案
## 一、游戏概述
### 1.1 游戏名称
- 中文名:《路网回声》
- 外文名:*Echoes of Transit*
### 1.2 游戏类型
- 公共交通规划策略游戏
- 规划公共运输体系路线,自定义运行时刻,自定义运输车辆
- 对现有道路进行重新规划、升级、降级等操作
- 剧情驱动 + 关卡制挑战 + 随机沙盒
- 有剧情驱动,设计评价指标,在一定时间内达成相应目标通关
- 也可以直接挑战沙盒模式
- 单机为主
### 1.3 平台
- PC windows优先
- 后续拓展移动端
### 1.3 美术风格
- 简约3D方块、色块区分功能而非写实
- 建筑物不使用额外贴图普通建筑用灰白色3D方块、特殊地段require、producer、consumer等使用特殊颜色标记
- 强调“信息可读性”而非真实感
- **设计目标**
- 让玩家一眼就能看懂城市结构和交通状态,研究游戏的玩法和规划艺术
## 二、核心设计理念
### 2.1 核心主题
> 交通决策的长期回声
- 一条线路的修建,会在未来数年产生连锁反应
- 错误规划并非立刻失败,而是“慢性问题”
- 城市不是瞬间优化的,而是被一步步塑造
### 2.2 核心体验目标
- 思考 > 操作
- 规划 > 反应
- 结果可解释,非随机惩罚
## 三、世界观与剧情模式
### 3.1 世界观设定
- 架空但贴近现实的城市群
- 城市被抽象为“功能模块”
- 玩家是城市交通规划局的继任者
### 3.2 剧情结构
- 章节制城市
- 每一章 = 一个城市/一个时代
- 每个城市有明确的问题背景
- 每种城市背景可能给线路规划带来增益或debuff
示例:
- 老工业城市:人口外流、通勤距离拉长
- 新兴新区:道路先行,公共交通滞后
- 山地城市:地形受限、线路成本极高
### 3.3 沙盒模式
* 随机生成建筑和道路
* 浮动的公共交通工具价格(成本)
## 四、核心玩法循环
```
阅读城市背景与目标
规划交通线路(公交 / 地铁等)
运行若干“年度回合”
观察数据变化(客流 / 拥堵 / 满意度)
调整或扩展路网
达成评分目标 / 剧情节点
```
## 五、关卡与分数挑战系统
### 5.1 关卡结构
- 固定地图
- 设置一个固定的初始地图
- 后期开发新增自动的扩展
- 固定初始城市状态
- 物价和经济水平
- 道路投资金额
- 经济增长曲线?
- 有限制条件(资金/技术/地形)
- 根据时代背景,研究新型道路类型
- 资金来源?
### 5.2 目标类型
- 总客运量
- 平均通勤时间
- 覆盖率
- 换乘效率
- 财政平衡
### 5.3 评分系统
- 多维评分合成
示例权重:
- 效率40%
- 覆盖率25%
- 稳定性20%
- 成本控制15%
### 5.4 重玩价值
- 不同评分策略
- 隐藏挑战条件
- 最优解并非唯一
### 5.5 沙盒模式
- 采用随机模式生成生产者和消费者
- 采用附着模式生成简单道路
## 六、时间体系
### 6.1 一日时长
* 游戏时间轴
### 6.2 周、月、季、年结算统计
* 统计指标
* 分数比重
## 七、公共交通系统设计与道路设计规划
### 7.1 交通工具
- 公交(低成本、灵活但容量小)
- 地铁(高成本、高容量)
- 有轨电车(中间态)
### 7.2 线路系统
- 手动建站,手动拉线
- 可视化站点服务范围衰减曲线
### 7.3 调度系统
- 采用时刻表模式(先提供简单的时刻表为默认时刻表)
- 车辆可选择性订购,维护价格和车辆价格可变
### 7.4 换乘系统
- 换乘惩罚(时间/不满意度/可达目的地)
- 换乘奖励
### 7.5 道路规划与升级
- 专用车道投资
- 特殊路口投资
- 道路拓宽要求
- 道路修建带来的拆迁成本
## 八、客流与行为模型(抽象模型)
### 8.1 居民抽象
- 不做单个NPC
- 使用“区域客流单元”
- 居民分类上班or游客or日常出行等
### 8.2 出行逻辑
- 固定 OD起点-终点)
- 优先选择:
1. 时间最短
2. 换乘最少
3. 拥挤度最低
### 8.3 反馈可视化
- 客流箭头
- 热力色块
- 失败路径提示
## 九、经济与限制系统
### 9.1 建设成本
- 按距离 / 地形浮动
- 地铁高昂
### 9.2 运营成本
- 线路越多,维护越高
- 低效线路拖累评分
### 9.3 失败机制
- 不会“Game Over”
- 只能低评分通关
- 鼓励反思而非惩罚
## 十、美术与表现
### 10.1 城市视觉语言
- 居住区:浅色块
- 商业区:亮色块
- 工业区:深色块
- 交通设施:高对比
### 10.2 动态表现
- 简化车辆动画
- 拥堵视窗状态的颜色变化
## 十一、UI / UX 设计
### 11.1 信息优先级
- 所有信息“开关式显示”
- 不强迫玩家一次看完
### 11.2 核心面板
- 路线面板
- 年度报告
- 评分分析面板
## 十二、音效与氛围(可选但很加分)
- 低频城市环境音
- 成功规划时的“秩序感音效”
- 失败不是刺耳,而是压抑
## 十三、技术实现方向(简述)
- 引擎Unity / Godot
- 数据驱动关卡
- 模拟逻辑与渲染解耦
- 后期可接入排行榜
## 十四、开发计划(独立开发友好)
### 阶段一:可玩原型
- 单地图
- 公交系统
- 基础评分
### 阶段二:剧情关卡
- 510 个城市
- 完整 UI
### 阶段三:打磨与平衡
- 分数调优
- 视觉统一
## 十五、总结陈述
> 《路网回声》不是关于“建多少条线”,
> 而是关于“每一次选择,会在未来留下怎样的回声”。

View File

@@ -0,0 +1,310 @@
# 《路网回声 Echoes of Transit》游戏策划案大纲
## 一、游戏概述
### 1.1 游戏名称
* 中文名:《路网回声》
* 外文名Echoes of Transit
### 1.2 游戏类型
* 公共交通规划策略游戏
* 剧情驱动 + 关卡制挑战
* 单机为主
### 1.3 平台
* PC windows优先
* 后续拓展移动端
### 1.3 美术风格
* 简约3D方块/像素风
* 低多边形
* 色块区分功能而非写实
* 强调“信息可读性”而非真实感
* **设计目标**
* 让玩家一眼就能看懂城市结构和交通状态,研究游戏的玩法和规划艺术
## 二、核心设计理念
### 2.1 核心主题
> 交通决策的长期回声
- 一条线路的修建,会在未来数年产生连锁反应
- 错误规划并非立刻失败,而是“慢性问题”
- 城市不是瞬间优化的,而是被一步步塑造
### 2.2 核心体验目标
* 思考 > 操作
* 规划 > 反应
* 结果可解释,非随机惩罚
## 三、世界观与剧情模式
### 3.1 世界观设定
* 架空但贴近现实的城市群
* 城市被抽象为“功能模块”
* 玩家是城市交通规划局的继任者
### 3.2 剧情结构
* 章节制城市
* 每一章 = 一个城市/一个时代
* 每个城市有明确的问题背景
## 四、核心玩法循环
```
阅读城市背景与目标
规划交通线路(公交 / 地铁等)
运行若干“年度回合”
观察数据变化(客流 / 拥堵 / 满意度)
调整或扩展路网
达成评分目标 / 剧情节点
```
## 五、关卡与分数挑战系统
### 5.1 关卡结构
* 固定地图
* 固定初始城市状态
* 有限制条件(资金/技术/地形)
### 5.2 目标类型
* 总客运量
* 平均通勤时间
* 覆盖率
* 换乘效率
* 财政平衡
### 5.3 评分系统
* 多维评分合成
示例权重:
- 效率40%
- 覆盖率25%
- 稳定性20%
- 成本控制15%
### 5.4 重玩价值
* 不同评分策略
* 隐藏挑战条件
* 最优解并非唯一
### 5.5 沙盒模式
* 采用随机模式生成生产者和消费者
* 采用附着模式生成简单道路
## 六、公共交通系统设计与道路设计规划
### 6.1 交通工具
* 公交(低成本、灵活但容量小)
* 地铁(高成本、高容量)
* 有轨电车(中间态)
### 6.2 线路系统
* 手动建站,手动拉线
* 可视化站点服务范围衰减曲线
### 6.3 调度系统
* 采用时刻表模式(先提供简单的时刻表为默认时刻表)
* 车辆可选择性订购,维护价格和车辆价格可变
### 6.4 换乘系统
* 换乘惩罚(时间/不满意度/可达目的地)
* 换乘奖励
### 6.5 道路规划与升级
* 专用车道投资
* 特殊路口投资
* 道路拓宽要求
* 道路修建带来的拆迁成本
## 七、客流与行为模型(抽象模型)
### 7.1 居民抽象
* 不做单个NPC
* 使用“区域客流单元”
* 居民分类上班or游客or日常出行等
### 7.2 出行逻辑
- 固定 OD起点-终点)
- 优先选择:
1. 时间最短
2. 换乘最少
3. 拥挤度最低
### 7.3 反馈可视化
- 客流箭头
- 热力色块
- 失败路径提示
## 八、经济与限制系统
### 8.1 建设成本
- 按距离 / 地形浮动
- 地铁高昂
### 8.2 运营成本
- 线路越多,维护越高
- 低效线路拖累评分
### 8.3 失败机制
- 不会“Game Over”
- 只能低评分通关
- 鼓励反思而非惩罚
## 九、美术与表现
### 9.1 城市视觉语言
- 居住区:浅色块
- 商业区:亮色块
- 工业区:深色块
- 交通设施:高对比
### 9.2 动态表现
- 简化车辆动画
- 拥堵视窗状态的颜色变化
## 十、UI / UX 设计
### 10.1 信息优先级
- 所有信息“开关式显示”
- 不强迫玩家一次看完
### 10.2 核心面板
- 路线面板
- 年度报告
- 评分分析面板
## 十一、音效与氛围(可选但很加分)
- 低频城市环境音
- 成功规划时的“秩序感音效”
- 失败不是刺耳,而是压抑
## 十二、技术实现方向(简述)
- 引擎Unity / Godot
- 数据驱动关卡
- 模拟逻辑与渲染解耦
- 后期可接入排行榜
## 十三、开发计划(独立开发友好)
### 阶段一:可玩原型
- 单地图
- 公交系统
- 基础评分
### 阶段二:剧情关卡
- 510 个城市
- 完整 UI
### 阶段三:打磨与平衡
- 分数调优
- 视觉统一
## 十四、总结陈述
> 《路网回声》不是关于“建多少条线”,
> 而是关于“每一次选择,会在未来留下怎样的回声”。