可以与 Tilemaps 一起使用的程序模式,第 1 部分

许多创作者使用程序生成来为他们的游戏增添一些多样性。一些值得一提的游戏包括 Minecraft,以及最近的 Enter the Gungeon 和 Descenders。这篇文章介绍了一些可以与 Tilemap(在 Unity 2017.2 中作为 2D 功能引入)和 RuleTile一起使用的算法。
通过程序创建的地图,您可以确保您的游戏中没有两次玩法是相同的。您可以使用各种输入,例如时间或玩家的当前级别,以确保游戏构建完成后内容也会动态变化。

当我们使用任何算法生成地图时,我们将收到一个包含所有新数据的 int 数组。然后我们可以获取这些数据并继续修改它或将其渲染为图块地图。
在继续阅读之前,您需要了解以下信息:
我们通过二进制来区分什么是图块,什么不是图块。1 表示开启,0 表示关闭。
我们将把所有地图存储到二维整数数组中,该数组在每个函数结束时返回给用户(渲染时除外)。
我将使用数组函数 GetUpperBound() 来获取每个地图的高度和宽度,这样每个函数中进入的变量就更少,代码也更简洁。
我经常使用 Mathf.FloorToInt(),这是因为 Tilemap 坐标系从左下角开始,使用 Mathf.FloorToInt() 允许我们将数字四舍五入为整数。
本博文中提供的所有代码均为 C# 代码。
GenerateArray 创建一个给定大小的新 int 数组。我们还可以说出数组应该是满的还是空的(1 或 0)。代码如下:
未知的块类型“codeBlock”,请在“serializers.types”属性中为其指定一个序列化器
此函数用于将我们的地图渲染为 Tilemap。我们循环遍历地图的宽度和高度,仅当数组在我们正在检查的位置有 1 时才放置图块。
未知的块类型“codeBlock”,请在“serializers.types”属性中为其指定一个序列化器
该函数仅用于更新地图,而不是再次渲染。这样,我们可以使用更少的资源,因为我们不需要重新绘制每一个图块及其图块数据。
未知的块类型“codeBlock”,请在“serializers.types”属性中为其指定一个序列化器
Perlin 噪声 有多种用途。我们使用它的第一种方法是为我们的地图创建一个顶层。这很简单,只需使用我们当前的 x 位置和种子即可获得一个新点。
这一代采用了将 Perlin Noise 实现到级别生成的最简单形式。我们可以使用 Unity 的 Perlin Noise 函数来帮助我们,因此不需要进行复杂的编程。我们还将使用函数 Mathf.FloorToInt()来确保我们的图块地图有整数。
未知的块类型“codeBlock”,请在“serializers.types”属性中为其指定一个序列化器
这是它在瓦片地图上呈现的样子:

我们也可以采用这个函数,并使其变得平滑。设置间隔来记录 Perlin 高度,然后在各点之间进行平滑。这个函数最终会稍微先进一些,因为我们必须考虑间隔的整数列表。
未知的块类型“codeBlock”,请在“serializers.types”属性中为其指定一个序列化器
对于此函数的第一部分,我们首先检查间隔是否大于一。如果是,我们就产生噪音。我们每隔一段时间就会进行一次此操作,以保证平滑。下一部分是通过平滑点来进行工作。
未知的块类型“codeBlock”,请在“serializers.types”属性中为其指定一个序列化器
平滑过程通过以下步骤进行:
- 获取当前位置和上一个位置
- 获取两个位置之间的差异,我们想要的关键信息是 y 轴的差异
- 下一步,我们确定应该将命中率改变多少,这是通过将 y 差异除以区间变量来实现的。
现在我们可以开始设置位置了。我们将努力将目标降至零
当我们在 y 轴上达到 0 时,我们会将高度变化添加到当前高度,并对下一个 x 位置重复该过程
一旦我们完成了上一个位置和当前位置之间的每个位置,我们将转到下一个点
如果间隔小于一,我们只需使用前一个函数来为我们完成工作。
未知的块类型“codeBlock”,请在“serializers.types”属性中为其指定一个序列化器
让我们看看它的渲染效果:

该算法的工作方式是抛硬币。然后我们会得到两个结果之一。如果结果是正面,我们就向上移动一个区块;如果结果是反面,我们就向下移动一个区块。通过不断向上或向下移动,这会为我们的水平创造一定的高度。这种算法的唯一缺点是它看起来非常块状。让我们看看它是如何工作的。
未知的块类型“codeBlock”,请在“serializers.types”属性中为其指定一个序列化器
与 Perlin 噪声生成相比,这一生成为我们提供了更加平滑的高度。
与 Perlin 噪声生成相比,这一生成为我们提供了更加平滑的高度。
与之前的版本相比,这种随机游走变化可以实现更加平滑的效果。我们可以通过向函数添加两个新变量来实现这一点:
- 第一个变量用来确定我们保持当前身高多长时间。这是一个整数,当我们改变高度时它会被重置。
- 第二个变量是函数的输入,用作高度的最小截面宽度。当你看到函数时,这将更有意义
现在我们知道需要添加什么了。让我们看一下这个函数:
未知的块类型“codeBlock”,请在“serializers.types”属性中为其指定一个序列化器
正如您从下面的 gif 中看到的,随机游走算法的平滑性使得关卡中可以出现一些漂亮的平坦部分。

我希望这可以激励您开始在项目中使用某种形式的程序生成。如果您想 了解有关程序生成地图的更多信息 ,请查看 Procedural Generation Wiki 或 Roguebasin.com,这两个都是很好的资源。
您可以关注该系列的下一篇文章,了解我们如何使用程序生成来创建洞穴系统。
如果您使用程序生成制作了一些很酷的东西,请随时在 Twitter 上给我留言或在下面发表评论!
想要了解更多信息并获得现场演示吗?我还将于 6 月 20 日在柏林 Unite 展览厅迷你剧院讨论与 Tilemaps 一起使用的程序模式。如果您想亲自聊聊的话,演讲结束后我会在场!