全部文章

· 约 3 分钟

我们如何用程序生成一整座浮岛小镇

有机网格、一小套建筑语汇,加上大量“看邻居”的规则——《空岛日和》里房子、拱桥和屋顶背后的做法。

  • #程序化生成
  • #空岛日和
  • #技术
云海之上的一座小镇,奶油色墙和陶红屋顶。

在《空岛日和》里,你从来不用挑房子模型。点一下格子,长出一层;再点,就更高一层。至于墙、窗、屋顶、拱桥、台阶、码头和塔楼,全部由周围的格子推导出来。这篇讲讲它是怎么做的,以及为什么整个游戏还能塞进一个 0.7 MB 的 HTML 文件。

1. 一张看起来不像网格的网格

正方形网格会让小镇看起来像一张表格。我们想要的是山城那种微微弯曲的街巷,所以浮岛建在一张有机网格上:

  1. 先铺一片六边形的点阵,连成三角形。
  2. 随机把相邻的两个三角形合并成四边形。
  3. 把所有形状(三角形和四边形)再细分成更小的四边形,这样每个格子都恰好是四条边。
  4. 做几十轮松弛:一点点挪动每个顶点,让每个四边形都尽量接近正方形。

结果是一张每个格子形状都略有不同、但相邻格子总是共享整条边的网格。“四条边”非常关键:墙、屋顶、桥只需要为一种格子设计。

网格用固定种子生成,所有玩家拿到的都是同一张。这也是岛屿分享码能这么短的原因:链接里只需要记录“哪些格子有砖、是什么颜色”。

2. 每个格子是一根柱子

一个格子上最多叠八层,每层记住一个配色。整座小镇的数据就只有这些:高度和颜色。“盖成什么样”一个字节都不存。

3. 由上下文决定盖成什么

某根柱子变化时,我们看它和邻居,从一小套建筑语汇里挑部件:

  • 靠岛边的地面层 → 石墙加拱门;靠内的地面层 → 带门的房子正面;挨着水 → 小木码头。
  • 中间层 → 带窗的墙,但只有朝外露出的墙面才开窗,偶尔加个阳台或花箱。
  • 顶层 → 坡屋顶加烟囱。如果邻居一样高,两片屋顶会合并成一条连排屋脊,沿着长边走。
  • 两侧都有高楼的空格 → 架起拱桥。
  • 邻居低一层 → 外侧台阶。
  • 孤零零的一根高柱 → 尖顶塔楼。

单看每条规则都不复杂,合在一起,小镇就像被设计过一样,哪怕玩家只是随手乱点。这是第一个原型的核心目标:随便点十下,就应该得到一张想截图的画面。

屋顶、烟囱和常春藤,全部由上面的规则挑选出来。

4. 只重建变化的部分

在手机上,点击必须是“立刻”的。一根柱子变化时,它自己和紧挨着的一圈邻居在同一帧重建;外面两圈排进队列,每帧大约 4 毫秒的预算,分几次重建完。建筑再按区块合并,所以整座岛一帧大约只要 70 次绘制调用。

5. 不用贴图的水彩感

游戏里没有一张图片贴图。所有表面共用一种“水彩”材质:两三层柔和的明暗分层、偏蓝紫的阴影,再加一点程序化的笔触噪声。画面上下边缘轻微的移轴模糊,让小岛看起来像桌上的微缩模型。

6. 剩下的交给时间

每座建筑都记得自己第一块砖是什么时候放下的。随着真实时间流逝(关掉游戏也一样),常春藤爬上墙,屋顶长出青苔,窗台多了花箱;空地先长草,再开花,然后冒出小树苗,慢慢长成大树。外观来自“规则加时间”,所以不需要手工做任何动画。

自己试试

理解这些规则最快的办法是去“打破”它们:在空地中间叠一根高柱,然后在旁边加一个邻居,看看屋顶怎么改主意。