扫雷的规则
扫雷,顾名思义,就是在一块区域内把所有非地雷的格子揭开即胜利;踩到地雷格子就算失败。区域的大小随难度的大小决定,有9X9(简单)到16X30(困难)之分,另外还有自定义的。
通过点击格子来打开它,如果里面有雷,你就输了;没有雷,出现一个数字n,表示在与其相邻的8个格子内存在着n个雷。如果相邻的格子没有雷,那么这个格子也会被发现。
从上面的规则中,我们可以推断出扫雷简单版需要的几个要素:
· 布满格子的网格
· 格子能够填充一个雷的大小
· 格子能够随着鼠标的点击响应事件
· 当某个各自响应鼠标点击事件时,它能够计算出周围的雷的数量。
新建一个Unity项目,再创建一个cube命名为Tile。将它拖到项目文件中作为一个预制物体。我们会用这个没有脚本的格子作为玩的范围,而后我们会添加脚本给他。
新建一个空的物体命名为Grid,同样把它作为预制物体。它将作为游戏区域和所有格子的生成器。
再新建一个Js脚本,命名为Grid,将其添加到Grid物体上面。Grid脚本主要创建了一个域,如下:
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
|
public
var tilePrefab: GameObject;
public
var numberOfTiles:
int
= 10;
public
var distanceBetweenTiles:
float
= 1.0;
function Start()
{
CreateTiles();
}
function CreateTiles()
{
}
|
然后,指定Grid物体上面的Tile Prefab公有变量,将预制物体Tile赋值给它。numberOfTiles变量表示允许你创建的格子数,DistanceBetweenTiles声明了调整格子间距的大小。

现在,网格生成器还没有具体功能,在CreateTile()函数中添加以下代码:
[C#]
纯文本查看
复制代码
1
2
3
4
5
6
|
var xOffset:
float
= 0.0;
for
(var tilesCreated:
int
= 0; tilesCreated < numberOfTiles; tilesCreated += 1)
{
xOffset += distanceBetweenTiles;
Instantiate(tilePrefab, Vector3(transform.position.x + xOffset, transform.position.y, transform.position.z), transform.rotation);
}
|
如果你执行当前的场景,就会创建一行格子,就像这样:

这个函数复制了我们指定数量的格子,然后我们将他们放置一行,通过distanceBetweenTiles控制他们之间的距离。调整距离以达到适当的距离。
对于扫雷游戏,我们需要的是让格子摆成一个网格,而不是一条线。为了实现这种效果,我们还需要在Grid代码的开始添加以下代码:
[C#]
纯文本查看
复制代码
|
public
var tilesPerRow:
int
= 4;
|
调整CreateTile()函数,就像这样:
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
function CreateTiles()
{
var xOffset:
float
= 0.0;
var zOffset:
float
= 0.0;
for
(var tilesCreated:
int
= 0; tilesCreated < numberOfTiles; tilesCreated += 1)
{
xOffset += distanceBetweenTiles;
if
(tilesCreated % tilesPerRow == 0)
{
zOffset += distanceBetweenTiles;
xOffset = 0;
}
Instantiate(tilePrefab, Vector3(transform.position.x + xOffset, transform.position.y, transform.position.z + zOffset), transform.rotation);
}
}
|

如果你设置的tilesPerRow变量合适,生成器便会创建一个很棒的规则区域。如果你编程能力很强的话,你还可以尝试更好的优化方案。
既然我们已经创建了基座扫雷格子,那么我们就可以给它添加“炸弹”了。
新建一个Js脚本,命名为Tile,并将它添到Tile预制物体上,然后声明一个bool变量。
[C#]
纯文本查看
复制代码
|
public
var isMined: boolean =
false
;
|
这个变量表示在格子中是否存在炸弹。接着我们得将“炸弹”放进网格中。为了实现这样的效果,我们需要改变Tile预制物体的游戏物体类型,使其转变为我们刚刚创建的Tile类,如下:
[C#]
纯文本查看
复制代码
|
public
var tilePrefab: Tile;
|
然后把Tile物体再次赋值给这个变量。现在我们就可以开始访问这些变量了。赋值炸弹还是有些技巧的,我们应该在网格生成器中赋值。
首先,在Grid代码中用三个数组来表示一个格子的数据:
[C#]
纯文本查看
复制代码
1
2
|
static
var tilesAll: Tile[];
static
var tilesMined: Array;
static
var tilesUnmined: Array;
|
这里,我们需要初始化数组。初始化操作放在CreateTiles函数中进行,如下:
[C#]
纯文本查看
复制代码
1
2
|
tilesAll =
new
Tile[numberOfTiles];
tilesMined =
new
Array();
tilesUnmined =
new
Array();
|
然后,还是在CreateTiles函数中改变实例化操作的参数,如下:
[C#]
纯文本查看
复制代码
1
|
var newTile = Instantiate(tilePrefab, Vector3(transform.position.x + xOffset, transform.position.y, transform.position.z + zOffset), transform.rotation);
tilesAll[tilesCreated] = newTile;
|
在CreateTiles函数最后添加AssighMines函数:
[C#]
纯文本查看
复制代码
|
AssignMines();
|
CreateTiles函数整体如下:
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
function CreateTiles()
{
tilesAll =
new
Tile[numberOfTiles];
tilesMined =
new
Array();
tilesUnmined =
new
Array();
var xOffset:
float
= 0.0;
var zOffset:
float
= 0.0;
for
(var tilesCreated:
int
= 0; tilesCreated < numberOfTiles; tilesCreated += 1)
{
xOffset += distanceBetweenTiles;
if
(tilesCreated % tilesPerRow == 0)
{
zOffset += distanceBetweenTiles;
xOffset = 0;
}
var newTile = Instantiate(tilePrefab, Vector3(transform.position.x + xOffset, transform.position.y, transform.position.z + zOffset), transform.rotation);
tilesAll[tilesCreated] = newTile;
}
AssignMines();
}
|
然后,实现AssighMines函数:
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
|
function AssignMines()
{
tilesUnmined = tilesAll;
for
(var minesAssigned:
int
= 0; minesAssigned < numberOfMines; minesAssigned += 1)
{
var currentTile: Tile = tilesUnmined[Random.Range(0, tilesUnmined.length)];
tilesMined.Push(currentTile);
tilesUnmined.Remove(currentTile);
currentTile.GetComponent(Tile).isMined =
true
;
}
}
|
代码梳理:当一个格子Tile在CreateTiles函数中被创建的时候,这个格子便会被添加到tileAll数组中,所有的格子还会被复制到tileUnmined数组中。在这个数组中,我们随机选择格子给其添加炸弹。添加炸弹的操作就是设置变量isMined为true,即表示本格子内存在炸弹。

现在,格子就矗立在Unity立方体上,让我们把他们变成真的“格子”。在原文件中,你能够找到一个叫做“puzzleObjects.fbx”的3D文件。把复制到的资源文件中,我们就能用它了。我们还要确保导入的文件它的比例为1,因为我们之前使用的设置就是这个比例。
文件导入设置如下:

然后设置一下预制物体格子,用tileImproved替换掉立方体原有的mesh。

当我们进行到这一步,重置格子的BoxCollider组件。这么做会让碰撞体更加契合格子。

最后给格子重新赋值一个新的材质,不然格子纯白色的,不好看。

注意:改变预制物体后记得要apply一下,这样我们改动的东西才能应用到之后创建的预制物体上。之后创建的格子都会照着新的格子去复制。
我们需要一个数字来显示本格子周围有多少地雷。实现这个功能的一个简单方法就是使用Unity的3D文字。通过点击GameObject ->CreateOther ->3DText创建,然后把它添加到格子上,就像这样:

让我们再改进一下:旋转text让它面朝上。先给它赋个0值,这样好让我们能够知道字体大小是否合适。还要调整字体和文本的大小,让字体显得清晰就行。


好了,现在我们还要在代码中能够访问3D文本,添加以下代码:
[C#]
纯文本查看
复制代码
|
public
var displayText: TextMesh;
|
把3D文本拖到对应的变量上面:

再次提醒,改变预制物体需要应用一下!
总结
我们已经实现了扫雷游戏的基础函数,目前来说还不能运行,在下一个部分会添加更多的内容,敬请期待。