经典游戏 ue4 重制(4)扫雷 - 上

这次我们来看看如何在 UE4 中做个扫雷。之前介绍的打砖块、贪吃蛇、小蜜蜂,依赖 UE4 提供的碰撞就能基本打造出基本的游戏框架,不过这次的扫雷就没这么简单了,我们将要实现相对复杂的蓝图,还需要用到递归。

在扫雷中,我们需要添加一个 Actor,命名为 BP_Block,用来表示扫雷的一个格子。其 Component 如下。

Image01.png

我们添加了一个正方体,同时附加了一个 Text,方便显示文字。

BP_Block 中的变量如下,

Image02.png

X,Y 表示该 block 在扫雷棋盘的坐标,HasMine 表示这个位置是否有雷,marked 表示用户已通过右键标注,uncovered 表示用户有没有点开这个格子。X,Y 我们设成 Editable,并且将 Expose on Spawn 置成 True,方便我们在生成棋盘时设置。

有了 BP_Block 这个基本元素,我们就能构建棋盘了。由于 UE4 中不支持多维数组,为了保存棋盘的状态,我们先建立一个以 BP_Block 数组为成员的结构,命名为 BlockLine,表示棋盘中的一行。

Image03.png

之后我们在 Controller 中建立一个 BlockLine 的数组,命名为 Matrix,用它就额可以表示整个棋盘了。

除了 Matrix 外,Controller 中其他变量如下。

Image04.png

其中 MineCount 表示我们将在地图中放置的地雷总数,MineLeft 表示还有多少个雷没有挖掉。SurroundingDelta 表示每个格子周围的八个点相对于它的偏移量,是个 Vector2D 的数组,内容如下。当用户点开地雷时,我们需要借助它来看看周围有没有地雷。

Image02.png

Controller 中的变量如上,接下去让我们看看 Controller 中的函数。

首先是 EventBeginPlay。

基本操作就是生成整个棋盘,然后在其中布置一些地雷。我们看下 GenerateBlocks。

Image03.png

在 GenerateBlocks 中,我们通过内外两层循环生成整个棋盘。外循环控制行数,内循环控制一行中的每个地雷。在内循环中,我们根据当前地雷的 X,Y 值,计算得到它的位置,并且 Spawn 一个 BP_Block,最后我们把这些 BP_Block 都保存入 Matrix。

生成完棋盘之后我们就能放置地雷。这是在 PutMines 中完成的。

Image04.png

我们已经在 Matrix 中保存了所有地雷的格子,为了让地雷的放置尽可能的简单与平均,我们先通过内外两层循环,把二维的 Matrix 压成一维的、包含左右 BP_Block 的数组,其次我们对该数组进行乱序,然后将其中前 MineCount 个 BP_Block 的 HasMine 置为 True。这样我们便放置了 MineCount 个地雷。

初始过程到此结束。接下去我们介绍几个工具函数,我们把这些工具函数都放在 Controller 中,方便使用。

首先是 ValidXY,用于判定给定的 X,Y 是否是合法的坐标值。当我们使用 SurroundingDelta 取得某个点周围的坐标时,可能会出现负数或者超出棋盘的情况,都可以通过这个函数判定。

Image05.png

其次是 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 中的各个函数,完成扫雷的剩余部分。

很不错的小教学,多谢分享了。 等我最近空了,把你这个项目做好打包丢上来,

不敢有劳!改天我把项目清清干净放到 github 上吧~~主要是 starter content 太大了。。

没事,一般新建都是空文档比较好,Starter Contet实在是占位子

您好,我看UE4新建项目puzzlegame的那个示例中,初始化棋盘的步骤是使用格子actor外的另一个actor。像楼主这样吧初始化棋盘的步骤写在controller里面,我把gamemode里面的controller改好,把一个格子的actor拖到场景中,怎么无法根据controller里面的generateblock来生成棋盘啊?

1 Like

这个项目的源代码放在这里了,请参考下。

https://forums.unrealengine.com/showthread.php?114517

https://s26.postimg.org/awr3ebjft/QQ_20160810181753.png

你好,请问你这里设置的布尔uncovered 是怎么打出来的,我只能弄出没有target的uncovered值,因为这个变量是在bp_block里面设置的啊?

PS:我现在知道怎么打出来了,但是不明白为什么不能直接在bp_block里面get和set(不显示target)