← 回成果库

城市系统 v2 —— 贴图尺度 · 设施系统 · 道路系统 · 车流重做

日期:2026-08-02 | 项目:M-383 / P582 | 在线试https://metazero-terminal.pages.dev/maptext/

入口:模板选「⭐ 大都市」→ ▶渲染 → 🚶走进去;语法看「📖 语法」,立面挑号看「🏢 楼房图鉴」


0. 一句话

主席点的四件事全做完了。每一件都是先量、再定位根因、再改、再用数字证明改好了——不是"我觉得好些了"。

主席说量出来的真相改完
贴图拉太长、太大中位层高 3.6m 其实是对的,但最大到 5.4m、招牌墙开间 4.8m最大 4.00m / 3.31m,贴图 128→256px
车流不合理,短距离来回开80 辆车里 43 辆在原地打转,240 帧掉头 377 次原地打转 0 辆,掉头 3 次
要有公园/游乐园/球场原来只有一格一格的绿地,没有内部结构公园/球场/游乐园/广场各有内部布局系统
蓝图和道路要跟着变原来永远是均匀棋盘密街 + 两格宽主干道;设施区内不铺路,道路自动绕开

1. 贴图拉太长 —— 先量再改

量到的(改之前)

立面一个开间实际几米(最小/中位/最大)一层实际几米
招牌墙3.09 / 4.80 / 4.801.64 / 3.67 / 5.33
东京密集窗0.91 / 1.92 / 2.070.80 / 3.64 / 5.40
老城石砌3.56 / 4.14 / 4.141.73 / 2.82 / 3.30

真实的写字楼一层 3.3–4.0m、一个开间 3.0–3.6m。中位数是对的,坏在最大值

根因

`js

Math.max(1, Math.round(len / tile)) // ← 就是这一行

`

一面 16 米高的裙房配一张 3 层的贴图(= 10.8m 一张):round(16/10.8) = round(1.48) = 1

→ 一张 3 层的图被拉到 16 米 → 一层 5.3 米。楼越矮、贴图越拉。

改法

取整之后再过一道尺度上限:一个开间不许超过 3.9m、一层不许超过 4.0m,超了就把重复次数往上顶。

宁可窗户偏小,绝不许偏大。 同时贴图 128→256px、各向异性 4→8,近看清晰度翻倍;招牌墙/石砌/带窗/石库门每张图多塞几个开间。

改完(同一张图重新量)

指标改前改后
全城最宽的开间4.80m3.31m
全城最高的一层5.40m4.00m

2. 车流"短距离来回开" —— 根因就一行

`js

if (blocked) { m.sign = -m.sign; ... } // 一被挡就掉头

`

车出生时方向是随机给的。出生方向跟街道方向对不上的车,第一步就撞墙 → 掉头 → 再撞墙,在一格之内来回抽搐。这就是主席看到的现象。

重写成真路网走法

1. 车活在格子图上:当前格 + 朝向 + 这一格走了多少(0~1)

2. 走满一格就到路口 → 从四个方向里挑一个还是路的:优先直行、其次左右转,绝不主动掉头

3. 靠右行驶:垂直于行进方向偏出半条车道 → 对向车自然分两边

4. 前面有车就减速排队,不是掉头;堵超过 3 秒就换个方向破死锁

5. 路口先到先过:不光查"目标格有没有人",还查"谁也盯上了这一格"——否则两辆车从垂直方向同时冲进路口,那一格还是空的,两边都以为能走,就在正中间穿模

6. 真走到死路 = 换个地方重新出生,不掉头

7. 出生就把朝向对准街道(治本的一步)

前后对比(把改动前的版本拉出来单独跑,同一张图、同样 240 帧)

指标旧版(主席看到的)新版
原地打转的车43 / 80 辆0 辆
掉头次数377 次3 次
净位移 ÷ 总路程0.650.72
跑到人行道/楼上0(19,200 次采样)
路口穿模0 帧

> "净位移÷总路程"是判断"来回蹦"的直接标尺:真在往一个方向开的车这个数接近 1,原地来回蹦的车趋近 0。


3. 设施系统 —— 公园/球场/游乐园各有内部布局

新模块 facilities.js。三个设计上的命门:

🌳 公园(参考中央公园 / 代々木公園)

`

水池 → 小山 → 弯曲步道(配长椅路灯)→ 按【密度场】种树

`

密度场就是"有系统"和"随便撒"的区别:

实测中央公园那一片(22×43 格 ≈ 660×1290m):水池 1 · 小山 3 · 步道 2 · 树 1,786 棵

⚽ 球场

一片体育公园切成好几块场地,不是一整片草。实测 14×14 格的体育区 → 9 块场地 + 18 根灯柱 + 3 排看台,场地类型各自抽签:

类型画了什么
足球场中线 + 中圈 + 两个禁区 + 两个球门框
棒球场内野钻石 + 外野弧线
篮球场群两块场地 + 中圈 + 篮架
网球场群两块场地 + 中线 + 球网
田径场三圈跑道 + 内场

🎡 游乐园

摩天轮(辐条 + 彩色吊舱 + A 形支架)+ 起伏的过山车轨道(双轨 + 支柱)+ 旋转木马(尖顶篷)+ 一大片彩色帐篷 + 园区主路。实测 20×18 格 → 摩天轮 1 · 过山车 1 · 旋转木马 4 · 帐篷 180 顶。

尺寸一律按米封顶(踩过的坑)

第一版按"占设施百分之几格"算,一格 30 米的图上长出了直径 360 米的摩天轮(真实摩天轮直径 100 米出头),过山车轨道横跨半张地图。现在全部按米夹住:摩天轮半径 22–52m、小山 14–55m、水池 12–90m、足球场 40–115m。实测摩天轮半径 52m


4. 道路系统 —— 蓝图跟着设施变

① 主干道 avenue_every

`

@meta road_every=6 avenue_every=3

`

每隔 3 条街升级成一条两格宽的主干道 —— 这就是曼哈顿的结构:密的是 street、疏而宽的是 avenue。

② 设施区内不铺路(中央公园做法)

`

@zones

centralpark = rect(150,120,171,162) facility=T

`

facility= 一写,这一整片就归这个设施,而且道路规则在它之前就被拦下——路自然绕着走。实测中央公园那 22×43 格里道路 0 格

span 从只给楼用,扩到公园/球场/游乐园/广场/水面


5. 实测汇总(本地跑一遍、把线上文件下载回来再跑一遍,共 83 项全绿)

项数内容
A–G 综合28/28跨格建筑 3 项 · 车和机器人 6 项 · 街道杂物 2 项 · 新立面 4 项 · 车流 4 项 · 设施 5 项 · 贴图尺度 1 项
楼房系统25/25四档分布、12 种立面、随机拼接、同种子可复现、老模板不受影响、7 套材质
第一人称18/18走/看/飞/碰撞/窗口跟人搬/车不上人行道/活物不重叠
材质+小地图12/129 套模板 0 报错、7 套材质逐像素互不撞脸、FPS、小地图、随机传送

性能:同一张 512 大城,走贴图 vs 老写法 = 帧率 114%,光点省 5.1 倍,draw call 6→15。

⚠️ 帧率在 swiftshader 纯 CPU 软渲下测,绝对值无意义,只有比值可信


6. 这轮踩到并修掉的坑(诚实留痕)

1. 图例字符撞车A 已经是 tower,我又写了 A amuse,后者把前者整个覆盖掉 —— 大都市里的超高层全没了。已改成 Y

2. 人行道规则误写成"四邻有路"road_every=3 的复古英伦模板里每一格都挨着路,于是整座城一栋楼都不剩。已改回"紧贴道路的那一条带"。

3. 设施尺寸没按米封顶:长出 360 米的摩天轮(见上)。

4. 我自己的测试也错过一次:跨格楼碰撞测试里跨半张图 teleport,触发了窗口重建,量到的"被推开 816 米"其实是坐标系搬家不是碰撞。改成先正经走过去再测,真实推开距离 14.6–15.4m,并加了一条"期间不许重建"的断言。


7. 红队:这轮哪里可能判断错了

最强反对:「车流现在合理了」可能是错的。

我量的是"净位移÷路程 = 0.72"和"掉头 3 次",但这两个指标都测不出"车流看起来像不像真的"。真实城市的车流有红绿灯节奏、有车队成串、有拥堵传播波——我这套是"每辆车各走各的、路口先到先过",本质上还是无信号交叉口。主席肉眼可能仍觉得"车太均匀、没有节奏"。

回应:这一轮解决的是"荒唐"(原地抽搐),不是"逼真"。荒唐是 bug,逼真是下一层。先把 bug 修干净再谈节奏,顺序不能倒。

可证伪锚:主席看了新版如果说"还是不对,车太机械/太均匀",那说明瓶颈已经从"路径"转到"节奏",下一步应该做红绿灯 + 车队跟驰 + 拥堵波,而不是继续调路径。这一条主席一句话就能检验。

诚实列缺口


*支撑文件:web/terminal/maptext/facilities.js(新·设施内部布局系统)· maptext.js(主干道 + 设施区 + span 扩展)· index.html(车流引擎 v2 + 设施渲染 + 贴图尺度闸)· buildings.js(12 种立面 · 256px)*