
《终极法则》0.11版更新第57期:解决世界地图线索孤立区域问题的几何数学探索
2026年4月11日 [游戏设计](https://www.markrjohnsongames.com/category/game-design/ "查看游戏设计类的所有文章"), [《终极法则》](https://www.markrjohnsongames.com/category/ultima-ratio-regum/ "查看《终极法则》相关的所有文章"),[更新](https://www.markrjohnsongames.com/category/updates/ "查看所有更新类文章")
大家好!这两周的内容和往常不太一样。我一般不太会详细说代码实现细节,更关注设计问题,但这周我打算分享一下。自[上两周的文章](https://www.markrjohnsongames.com/2026/03/30/ultima-ratio-regum-0-11-update-56-huge-map-clue-advancement-and-integration-complete/)发布后,我在处理世界地图线索的边缘情况和漏洞时,碰到一个有趣挑战,要解决一个隐蔽又棘手的边缘情况。具体而言,在世界地图线索上,伤害有机扩散后,可能使线索一部分孤立地漂浮在伤害区域中,周围没其他东西相连。要是不太明白,看看下面这张图:

从可信度看,这显然是个问题。玩家角色咋知道重要部分该放哪儿呢?要说明的是,这里关键的“X”恰好是孤立部分,纯属巧合。我还遇到过地图上任何元素在周围受伤害时孤立漂浮的情况,甚至有几块地图像较大岛屿一样漂浮着。这个问题得解决,但处理起来出奇复杂。原因有几个:
首先,我得找个方法,尽量减少对伤害生成时间的影响。直观的解决办法是用泛洪填充算法,即不断检查地图上未受损部分是否相连,若突然不相连,就移除或撤销上一次添加的伤害区域。这方法直观,但有问题。如该技术的[维基百科页面](https://en.wikipedia.org/wiki/Flood_fill)详细阐述的,优化这个算法在计算上是个难题,因为可能耗费大量时间。这是个问题,因为生成高难度(如“困难”或“极难”)的地图,对游戏来说本就比“简单”或“普通”难度的地图困难,因为游戏有时得舍弃一些不符合我设定参数的尝试。这意味着我真不想在生成系统里再增加计算密集型元素,特别是每次添加伤害区域后都得运行(严格说,前七次添加伤害区域时不用运行,因为形成完整环需要八个区域,但大家懂我意思)。
第二个挑战是,伤害分布方式很自然——游戏会在网格上选一些起始点(难度越高,起始点越多;难度越低,起始点越少),然后让伤害向各方向扩散(难度越高,扩散范围越大;难度越低,扩散范围越小),经过一定次数迭代(同样,难度越高,迭代次数越多;难度越低,迭代次数越少)。这种方式能在地图上形成自然丰富的伤害效果,我很不想改变它,特别是我花了很多时间优化这段代码,确保它在美学和游戏性方面都达到我想要的效果。但我找不到明显的非泛洪填充方法,利用现有代码检查是否会形成孤立区域。如果一块伤害区域与另一块相连,这本身不是问题,也不一定会形成孤立区域。最好的替代方法似乎是,每次在某个格子上添加伤害时,检查它周围上下左右的格子,再从这些格子检查它们上下左右的格子,如果这些格子中已有3/4是伤害格子,就不添加刚要添加的伤害。这比泛洪填充算法快,但计算量仍很大。对于大量伤害,可能要运行50次左右,每次运行要进行16次检查,即总共800次,每次检查都要查看两个不同网格(地图网格和伤害网格)。而且,即便这样也不能完全解决问题,因为它无法防止出现2格或3格的孤立区域!目前已有代码确保整个地图不会被分成两半,即地图边缘只能有一个格子受伤害(这种情况不总发生,且在小地图上比大地图上更常见,因为边缘在地图总面积中占比更大),这有帮助,但这些代码无法防止孤立区域出现。所以,考虑到这些情况,我得找其他解决方案。这篇博客文章就是关于寻找和完善这个解决方案的逻辑与思考过程。
于是,我开始考虑其他替代方案,一个想法马上浮现,它计算极其简单,只需在游戏考虑添加伤害区域时做一次短暂检查。这个想法是在地图网格下面设一个隐藏网格,玩家永远看不到,其中有一组特定格子不能变成伤害区域,且这些格子的几何排列要确保永远不会形成孤立区域。我意识到,如果地图上某个格子永远不会成为伤害格子,那它周围所有格子在某种意义上就“安全”了,不会成为孤立区域,因为它们肯定会与一个永远不会成为伤害的格子相邻。有了这个想法后,我打开画图软件,做了个基本的9×9网格——我知道最大的世界地图线索处理起来最困难,所以从这儿开始——并尝试找出最少需要多少个格子才能达到这种效果。基于我刚才说的逻辑,我最初的实验结果如下,有那么10秒钟,我很满意,觉得只要红色格子永远不是伤害格子,就不会出现孤立区域,因为其他每个格子都与一个红色格子相邻……对吧?显然不是,我的大脑马上指出,这虽能防止单格孤立区域,但无法防止多格孤立区域出现。哎呀!

接下来,我要找一种模型,让整个网格上每个格子都与一个红色格子(在这个模型中,我不允许这些格子成为伤害格子)相邻,并且确保没有可能形成环。实际上,这意味着不能成为伤害的格子(红色格子)都得以某种方式与地图边缘相连,否则,在极罕见的边缘情况下,游戏仍可能在它们周围生成较大伤害环,从而在中心形成较大孤立区域,而非单个格子。当然,我自然不想过多改变伤害整体形状,希望找到尽可能大的空间,让这些不能成为伤害的格子不影响其他区域,同时确保每个格子都能与一个这样的格子相邻。经过思考,我觉得平行对角线可能是最好的方法,因为平行的水平线或垂直线之间只能有2×2的其他格子区域,而这里我们几乎可以有3×3的可受伤害格子区域,每个区域只需有一个红色格子,就能确保每个可能的格子都与一个不能成为伤害的格子相连,从而防止孤立区域出现。当时我还觉得,边缘格子通常也需要有红色格子,这样内部格子就不会因边缘伤害形成环而变成孤立区域(这时我还没忘记在生成器早期版本中实现的“地图边缘只能有一个格子受到伤害”的规则,但还没意识到这个规则对这个系统的影响)。经过思考,并尽量减少不能成为伤害的格子数量后,我想出了下面这个可能的隐藏网格,它确实能完全防止孤立区域出现:

我挺满意,但也对它的局限性感到失望——在这个模型中,地图上很多可能受伤害的区域都被排除了!当然,这个模型可以有多种变体,比如沿x轴或y轴翻转,或者将对角线放不同位置,仍能达到相同目标。但即便如此,在这个模型中,地图上相当大一部分区域都不能受到潜在伤害。尽管如此,这似乎是我能想到的最好方案了,所以我花时间探索其他几何形状,以最大化不能成为伤害的格子布局的可能性。这样,即使在上面的版本中某些区域不能受伤害,在其他版本中这些格子也可以受伤害。由于这些都是隐藏的、玩家永远看不到的东西,玩家应该不会注意到或意识到这些网格对高难度世界地图线索上的伤害分布产生的微妙影响。实际上,这是个有趣的智力和几何练习,因为我总试图确保不能成为伤害的格子数量尽可能少,同时确保每个格子都与其中一个相连,它们都能到达地图网格边缘,并且以各种有趣的方式连接,以确保在不被这些防止孤立区域出现的隐藏网格过度限制的情况下,线索上仍能产生尽可能多的不同伤害变化。经过努力,我想出了类似下面这样的方案,并开始了解这个特定几何问题的一些“规则”:

(实际上,其中有两个地方有错误——看看你能不能找出这些网格中可能出现孤立区域的两个地方!)
这些方案有用,但这时我开始担心它们会限制可能出现的伤害形状。回顾[上周的文章](https://www.markrjohnsongames.com/2026/03/30/ultima-ratio-regum-0-11-update-56-huge-map-clue-advancement-and-integration-complete/),一些“困难”和“极难”难度的地图上,有相当大的区域被伤害移除,而且形状各异。但无论我怎么尝试,这些方案都会限制这种多样性。我意识到,在大多数伤害生成过程中,很多不能成为伤害的格子实际上完全没必要,但它们仍会在很多时候阻止伤害生成出我想要的有趣效果。这有点让人左右为难,但后来我有了个想法,也有了新认识。想法是这样的:如果我们将不能成为伤害的格子分组,伤害生成器计算每组中有多少个格子受了伤害,只有当一组中所有格子都受伤害,从而可能形成环时,游戏才会说“不”,并阻止添加伤害。但当我完善这个想法时,我意识到这行不通,因为在达到主要规模之前,仍可能出现较小的伤害环。所以,我转而考虑一种系统,在这个系统中,某些格子只有在其他格子满足特定条件时才能受伤害——大致如下面图片左侧所示。与此同时,我意识到,地图上整个最外层格子和第二层格子无论如何都不会变成孤立区域!在所有情况下,都需要多个外层格子变成伤害区域才会出现这种情况,而已经有规则禁止这种情况发生,所以这大大简化了问题。基于这两点,我试图设计一个模型——如下面图片右侧所示——在这个模型中,我们可以有少量分组的格子,每组中只有一个可以受伤害,并且只有少数绝对不能成为伤害的格子……但这变得相当复杂,计算量也比我预期的大,需要大量条件判断才能让这样的系统正常工作。

然而,意识到最外层的两层格子不会出现这个问题后,就只剩内部区域比较麻烦了,我们只需将这些内部区域与最外层连接起来。这又变成了一个有趣的几何和数学小问题:怎样才能最有效地做到这一点,让所有不能成为伤害的格子以某种方式与第二层或另一个不能成为伤害的格子相连,并且让除了最外层和第二层之外的每个格子都与一个不能成为伤害的格子正交或对角相连,同时尽可能减少不能成为伤害的格子数量,以确保在世界地图线索上生成视觉伤害时有最大的可能性空间?下面是我早期的两个实验,左边的方案在一个9×9的世界地图线索网格中只需要九个格子就能满足所有条件,右边的方案则需要十个格子来满足相同的条件。在尝试的过程中,我没找到只需要八个格子的方案,但也许存在这样的方案。如果你能找到一个满足这些规则的方案(假设根据我上面的描述你能理解这些规则),请告诉我,我很想看看。不管怎样,我对这两个方案很满意,因为它们仍能让地图上的伤害视觉效果有很大变化,同时又能确保不会出现单格孤立区域。这时,我开始觉得自己真取得了进展——早期的一些方案中有太多不能成为伤害的格子,我真担心这会对最终结果产生非常不利的影响,但现在,我对最终的效果很有信心。

然而,这些方案中的对角线部分让我觉得可以尝试去掉。确实有一些地图线索生成时,地图的一部分只是对角地“挂”在地图的其他部分上,看起来虽然还可以,但在视觉上不如地图以正交方式连接生成的效果好。因此,我回到画图软件中的网格,试图找到一些不能成为伤害的格子的网格布局,这些布局中的连接完全或主要是正交的,以确保生成的地图看起来更好。这有点棘手,因为在平面上,正交线覆盖的“距离”不如对角线长——这就是为什么很多策略游戏使用六边形格子来防止对角移动比正交移动更有优势的原因。但很快,我就找到了三个完全使用正交连接的不能成为伤害的格子的例子,还有一个是两种连接方式都有的例子。我决定保留第四个例子,因为偶尔有一些伤害或非伤害区域穿过对角线是完全可以接受的,但总体来说,我认为如果尽量让这些连接成为正交的,会生成更美观、更有视觉吸引力的地图。因此,我得到这四个方案后,很快就将它们以所有可能的旋转和翻转方式应用到游戏中,当然,也对7×7和5×5的可能性进行了同样的处理,这两个尺寸的处理要简单得多。5×5的情况特别有趣,每个方案只需要在第二层的某个位置(角落或边缘)有一个不能成为伤害的格子,就能防止任何孤立区域的出现,这已经是最简单的情况了。

有了这些方案后,我当然进行了大量游戏测试。我很高兴地报告,高伤害地图,特别是“困难”和“极难”难度的地图,最终的生成效果没有任何变化,看起来棒极了!你几乎完全注意不到在地图生成过程中,有一条或一组隐藏的规则在微妙地影响着有机伤害的形成。实际上,游戏中还有很多其他地方使用了类似的想法(虽然背景不同),即固定某些特定的点或元素,然后围绕这些元素构建其他生成结果,因为这样通常能确保生成的结果更接近我想要的自然效果,同时又不失多样性——而完全自由生成(比如《终极法则》这样的游戏中,不能让世界地图生成时只有一个国家征服了整个世界)则不太适合。对于地图线索来说,关键是视觉上没有任何变化,但现在不会出现孤立区域了,因此这个小几何和数学探索的设计目标已经实现,而且计算量极小,最多只会在地图线索生成时增加大约千分之一秒的时间,而不是可能会有明显影响的时间(这两者看起来可能差不多,但要记住,游戏在生成任何东西时不会做其他事情,所以我们需要尽可能快的速度)。另外很棒的是,一旦我开始生成本地地图线索,这些见解也可以很容易地应用——实际上,9×9尺寸的20个隐藏网格、7×7尺寸的16个隐藏网格和5×5尺寸的8个隐藏网格,在本地地图线索的情况下也能同样有效地确保不会生成孤立的纸片区域。
就是这样——显然,这并不是这两周的全部工作(整个过程大约花了半天时间集中精力思考和规划),但我认为这是一个有趣的关于编码过程的洞察,从发现问题,到想出糟糕的解决方案,到还可以的解决方案,到好的解决方案,到优化的解决方案,最后到实施的解决方案。它可能会让你对我如何处理问题以及如何平衡



被折叠的 条评论
为什么被折叠?



