通常我们会发布非常小的更新... 今天我们却要深入探讨双网格(Dual Grid)和它在我们的游戏中的作用。

双网格是什么?

首先我们应该解释一下什么是双网格系统。我们的游戏使用网格来决定建筑物的位置以及特定区域的地形。以下是代表这种情况的图像,其中黄色表示沙子,蓝色表示水。

https://preview.redd.it/opws0y5ji12h1.png?width=256&format=png&auto=webp&s=4ba5df9817a03316fbac6429028868d9f20d8a77

这种方法在尝试确定是否可以在某个位置建造建筑物或进行路径寻找时非常有效,但这意味着地形之间的过渡会看起来非常方块。另外,这种表示法虽然在程序上简单,但在艺术上却复杂!我们需要绘制数百种可能的网格之间的过渡来使其看起来良好,因此我们需要一种新的思路来帮助管理这个问题。

一些人可能记得我们的游戏在较早的截图中看起来非常类似于上述图像。这就是双网格的作用。它将游戏中的逻辑组件(模型)与视觉组件(视觉)分开,使用一个偏离模型的网格系统,如下所示:

https://preview.redd.it/maxq2c3mi12h1.png?width=256&format=png&auto=webp&s=861917f66d9fbfea091597070778a1c6022873cd

上面的图像可能看起来有点奇怪 - 绿色是我们的模型网格,紫色是我们的新双网格。您可以看到通过偏移网格,我们可以现在创建平滑的过渡,不再依赖于模型网格。

当我们将问题看作这样的时候,我们只有 13 种可能的网格组合 - 4 个凸角,4 个凹角,4 个对角线角和没有过渡。因此,我们可以创建一个非常简单的网格图来存储这些数据:

https://preview.redd.it/1a9ks62vi12h1.jpg?width=820&format=pjpg&auto=webp&s=dca603099263e8ff211fbdeeb1fe331534ffa42f

这种方法有一些局限性,特别是双网格只能处理两个地形之间的过渡。

所以规则是:模型网格的每个正方形都必须连接到同类别的其他网格正方形上垂直和水平。这样就确保了双网格只需要处理两个地形之间的过渡,例如海洋和沙子,或沙子和草。

着色概念

现在我们了解了一些关于双网格的知识,我们可以讨论一下如何在游戏中可视化它。我们使用着色器来完成所有的繁重工作,使用一个实体来每帧绘制。着色器接受一个摄像机偏移(所以我们知道我们在看哪里),网格大小,和一堆遮罩。

我们想要在这里做的是取模型网格和,根据屏幕上的任何点,决定应该显示双网格的哪个部分,以及应该显示多少。要做到这一点,我们必须首先定义当我们达到相交的网格时双网格看起来是什么样的(例如沙子和水)。我们可以将这些定义为遮罩,如下所示(黑白版本的彩色版本):

https://preview.redd.it/v77bfii1j12h1.png?width=320&format=png&auto=webp&s=ebebbc95190ba33cd83db5a7b5b45f94dc73f66e

这些遮罩可以在后续的步骤中用来确定我们在哪个过渡中。

步骤 1 - 绘制网格

每个地形都被赋予了一个深度,从 0 到 1,其中各种点被赋予了特定的意义。例如,任何大于 0.1 的深度都是海洋,任何大于 0.2 的深度都是浅水,任何大于 0.3 的深度都是沙子等。我们将这个网格通过一个纹理传递给着色器,其中每个像素代表一个深度(尽管这也可以是数值数组)。然后我们只需要取屏幕位置,偏移该位置以半个网格大小(-32px),然后将该位置除以网格大小(64px)。对于我们的例子,这给出了一个遮罩,看起来有点像这样:

https://preview.redd.it/5mkjao76j12h1.png?width=651&format=png&auto=webp&s=13bcc4d3f64ea77fb0868459accb032ddb9dab3b

步骤 2 - 覆盖边界遮罩

在这里我们需要解决的问题是,当我们有一个被其他深度所包围的网格时,过渡看起来会是什么样的。首先的一部分相对简单,我们只需要使用找到当前网格的代码来找到顶部右侧、顶部左侧和左侧的网格。顺序在这里很重要,当前网格总是最后一个在列表中。

如果网格被同类别的网格所包围,我们可以在此停止,因为我们已经有了网格的深度。

否则,我们得到 4 个网格的最小深度和最大深度,并按顺序排列这些网格以创建一个边界形状。我们可以通过定义一个网格是否是“上”(up)或“下”(down)来完成这一点。一个“上”网格是指向或等于最大深度的网格,而一个“下”网格是指向或等于最小深度的网格。如果我们通过每个网格标记“上”为“true”并“下”为“false”,我们可以得到一个布尔数组,我们可以然后比较并选择我们在遮罩上面的区域。

要做到这一点,我们只需要查找模式(true,false,false,false; 将是凸形状的例子)。然后我们可以在我们的遮罩上找到该模式。

我们现在有一个64x64的网格在我们的遮罩上选择一个位置 - 我们可以使用屏幕大小除以网格大小的分数部分来得到该位置的百分比。

我们现在有一个要混合的深度(最小深度)、要混合的深度(最大深度)和要混合的每个像素的百分比(我们的遮罩的像素从黑到白)。我们只需要混合从最小到最大使用要混合的百分比,这给出了:

https://preview.redd.it/f1qyhh79j12h1.png?width=651&format=png&auto=webp&s=c104222a74c8dfad700001523f665898d4b87a29

步骤 3 - 抓取彩色笔

现在我们有一个介于 0 和 1 之间的值,表示我们正在绘制的 terrain。从这里我们只需要选择一个颜色(深蓝色表示海洋,浅蓝色表示浅水,黄色表示沙子等)。

https://preview.redd.it/40u902mbj12h1.png?width=651&format=png&auto=webp&s=df4e92c05cbd6572bf277446e9cbd10e53f03928

构建系统的这种方式的一个好处是,遮罩可以重用来做更多的事情。因为遮罩只描述了任何给定像素上的过渡存在的程度,我们可以将该值传递给任何东西。我们使用它来驱动波浪大小,例如 - 通过修改遮罩以向中心渐变,我们可以限制波浪出现的深度,如下所示:

https://preview.redd.it/b67fc8dej12h1.png?width=320&format=png&auto=webp&s=0a8829236d5582ae2e524581949372056aaaa275