这次我们来看看如何在 UE4 中做个扫雷。之前介绍的打砖块、贪吃蛇、小蜜蜂,依赖 UE4 提供的碰撞就能基本打造出基本的游戏框架,不过这次的扫雷就没这么简单了,我们将要实现相对复杂的蓝图,还需要用到递归。
在扫雷中,我们需要添加一个 Actor,命名为 BP_Block,用来表示扫雷的一个格子。其 Component 如下。
我们添加了一个正方体,同时附加了一个 Text,方便显示文字。
BP_Block 中的变量如下,
X,Y 表示该 block 在扫雷棋盘的坐标,HasMine 表示这个位置是否有雷,marked 表示用户已通过右键标注,uncovered 表示用户有没有点开这个格子。X,Y 我们设成 Editable,并且将 Expose on Spawn 置成 True,方便我们在生成棋盘时设置。
有了 BP_Block 这个基本元素,我们就能构建棋盘了。由于 UE4 中不支持多维数组,为了保存棋盘的状态,我们先建立一个以 BP_Block 数组为成员的结构,命名为 BlockLine,表示棋盘中的一行。
之后我们在 Controller 中建立一个 BlockLine 的数组,命名为 Matrix,用它就额可以表示整个棋盘了。
除了 Matrix 外,Controller 中其他变量如下。
其中 MineCount 表示我们将在地图中放置的地雷总数,MineLeft 表示还有多少个雷没有挖掉。SurroundingDelta 表示每个格子周围的八个点相对于它的偏移量,是个 Vector2D 的数组,内容如下。当用户点开地雷时,我们需要借助它来看看周围有没有地雷。
Controller 中的变量如上,接下去让我们看看 Controller 中的函数。
首先是 EventBeginPlay。
基本操作就是生成整个棋盘,然后在其中布置一些地雷。我们看下 GenerateBlocks。
在 GenerateBlocks 中,我们通过内外两层循环生成整个棋盘。外循环控制行数,内循环控制一行中的每个地雷。在内循环中,我们根据当前地雷的 X,Y 值,计算得到它的位置,并且 Spawn 一个 BP_Block,最后我们把这些 BP_Block 都保存入 Matrix。
生成完棋盘之后我们就能放置地雷。这是在 PutMines 中完成的。
我们已经在 Matrix 中保存了所有地雷的格子,为了让地雷的放置尽可能的简单与平均,我们先通过内外两层循环,把二维的 Matrix 压成一维的、包含左右 BP_Block 的数组,其次我们对该数组进行乱序,然后将其中前 MineCount 个 BP_Block 的 HasMine 置为 True。这样我们便放置了 MineCount 个地雷。
初始过程到此结束。接下去我们介绍几个工具函数,我们把这些工具函数都放在 Controller 中,方便使用。
首先是 ValidXY,用于判定给定的 X,Y 是否是合法的坐标值。当我们使用 SurroundingDelta 取得某个点周围的坐标时,可能会出现负数或者超出棋盘的情况,都可以通过这个函数判定。
其次是 GetBlock 函数。该函数的目的在于从 Matrix 中取得 X,Y 对应的 BP_Block。
有了 ValidXY 和 GetBlock,我们就可以生成 BlockXYHasMine。正如名字所表达的意思一样,这个函数告诉我们 X,Y 对应的位置是否有地雷,其内容如下。
基本上是先判断 X,Y 是否有效,若无效则直接返回没有地雷。如果为有效坐标,则调用 GetBlock 取得 BP_Block,最后根据 BP_Block 中的 hasMine 返回结果。
另外,我们在 Controller 中还添加了个名为 GetSurroundingCount 的函数。用途是取得 X,Y 周围的八个格子中包含了几颗地雷。
我们对 SurroundingDelta 中的八个坐标偏移量逐一循环,依次得到 X,Y 周围的八个 BP_Block,然后通过调用BlockXYHasMine 即可得到周围的地雷数。写到这里的时候觉得这个函数放在 BP_Block 中也许更自然一点,不过既然都截了图了就先这样吧。
Controller 中主要的函数就是上面这些。下次我们将介绍如何处理用户输入,以及 BP_Block 中的各个函数,完成扫雷的剩余部分。