基于ANM9开发板的扫雷游戏设计 数值都加1。这样布雷的底层数据结构就完成了。
用一个dump()函数来打印STL里面的数据,即扫雷的底层数据。如图3-8所示。
图3-8 扫雷底层的数据
在此类的构造函数中默认设置好扫雷区域的宽和高,避免在开局的时候系统产生一个随机的雷数值大于扫雷区域的宽×高使程序出错。设置扫雷区域宽的默认值为5,高的默认值为3,雷数的默认值为4.程序如下:
Field::Field():
{
}
当我们用此类定义一个对象时,系统会自动调用此类的构造函数。在构造函数中调用initCells()和deployMines()函数。这样就可以在设置图片的函数中调用此类就可以把底层数据和上层的图片结合起来。
initCells(); deployMines(); width(5), height(3), mines(4)
3.3 STL图片的设计
3.3.1 图片的选取和加载
在网上选取几张图片做为本次扫雷游戏的图形界面。
1 2 3 4 5 6 7 8
19
基于ARM9开发板的扫雷游戏设计
blank explode flag question initial
选取图片时要保证每张图片的尺寸大小一样,通过画图工具已经把上面这些图片都改成了相同的尺寸,这样当翻开图片时不会出现越界的问题。
其中图片initial为最开局时贴在数据上面的图片,图片1-8为贴在底层数值为1-8的图片,图片blank为贴在底层数值为0的图片,图片explode为贴在雷上面的图片,图片flag和question为点击右键标志时的图片。
在此工程下创立一个资源文件,把这些图片加到资源文件中,如图3-9所示:
图3-9 资源中的图片
在工程下新建cellitem类。类cellitem用来把图片这个道具加到scene场景中以及一些其他的功能。
要把图片放到场景上,首先得把图片加到游戏中来,然后再到场景中为每张图片设置坐标。当加图片的时候我们必须用到每张图片的路径,为了以后方便使用图片,先把每张图片的路径赋给一个字符串。这样直接加字符串就可以了。我们把所有图片放到一个image的文件夹里面,并把这文件夹放到扫雷工
20
基于ANM9开发板的扫雷游戏设计 程里面来。每加一张图片系统就会开辟一段空间来存放图片,程序如下所示:
QPixmap * initial;
......
initial = new QPixmap(\......
因为数值的图片名称有规律可循,我们用一个for循环为数值的每张图片开辟空间,取别名。程序如下:
QString preFix(\
QString postFix(\QString fileName,num; for(int i=1; i<9; i++) {
num.setNum(i); fileName = preFix; fileName += num; fileName += postFix;
digits[i] = new QPixmap(fileName);
}
每次打开扫雷游戏时看到的是initial这张图片,所以先把initial图片放到场景中去,
setPixmap(*initial);
此句程序语句就是把图片initial放到场景中去。
值得注意的是每次运行程序时系统会开辟空间来存放这些图片,所以在结束程序是必须把这些道具删除,系统每开辟一段空间,就要在程序结束时删除这段空间。在程序结束是系统会自动类的调用它的析构函数,所以我们在类的析构函数中删除这些道具。程序如下:
CellItem::~CellItem() {
}
delete initial; ......
21
基于ARM9开发板的扫雷游戏设计 3.3.2 图片坐标的设计
图片已经放到场景中了,为了不使图片层叠,得为每张图片设置好坐标。 新建一个sweepminesscene类,类sweepminesscene主要用来划分场景中贴图片的每个坐标和把底层数据和上层图片结合起来以及一些其他的功能,在扫雷区域中有多个道具,我们要为每个道具设定好坐标,防止道具层叠,这样就靠sweepminesscene来划分。
同3.2在类sweepminesscene中建立一个容器:
Typedef vector
但此容器的类型不为int型,为CellItem*型。同3.2把容器扩容。 在sweepminesscene类中用field类做为数据类型定义一个名叫Filed的变量,当调用变量Field变量是就会自动调用field类的构造函数,见3.2,而field的构造函数会自动调用field类中的initCells()和deployMines()函数,这样就可以把底层数据和上层图片结合起来。上层图片的数量和底层数据的数量必须相匹配,调用field类中的宽和高来为图片的容器扩容。
图片的容器建好之后要把每张图片的坐标设置好,程序如下: static int cw = m_Item[0][0]->boundingRect().width(); static int ch = m_Item[0][0]->boundingRect().height(); m_Item[x][y]->setPos(x*cw,y*ch); addItem(m_Item[x][y]);
cw为每张图片的宽,ch为每张图片的高,boundingRect().width()和boundingRect().height()为类中的函数,只要调用这两个函数就可以自动求出图片的高和宽了。在QT界面中规定场景的左上角为坐标(0,0)点,当设置坐标为(0,0)点时会自动把场景中的(0,0)点和图片的左上角对齐。
当我们设置m_Item[n][n]图片时,图片m_Item[x][y]处于场景中的第x+1行第y+1列,而图片m_Item[n][n]的左上角应放到点(cw×x,ch×y)中,所以设置图片
m_Item[x][y]的坐标为
setPos(x*cw,y*ch)。
addItem(m_Item[x][y])为把此图片加到场景中来。
22
基于ANM9开发板的扫雷游戏设计 3.4 功能程序块的设计
3.4.1 鼠标事件
界面的图形和底层数据都设计好了,但是怎么实现扫雷的功能呢?例如鼠标点击时怎么使图片变换。下面就来设计扫雷的鼠标事件,鼠标点击有三种情况,一个左击和右键,还有一种左右同时按下,由于时间关系左右同时按下在本设计中不用。如图3-8所示:
等待鼠标按 图3-10 鼠标事件流程图 左击 取消标志 左击 右击 标志为疑问 右击 右击 交换图片 左击 右击 标志为雷 鼠标事件函数也是类中带的一个虚函数,虚函数不能用函数去调用,只有当鼠标动作时会自动调用鼠标左击或者右击的鼠标事件函数。 鼠标事件是发生在图片上的事件,所以要在类CellItem执行相关的鼠标事件。 每个图片道具都有几个状态:初始化状态,被挖开状态,被标志为雷状态,被标志为疑问状态。当被挖开状态时此图片不再响应鼠标事件,而当标志为雷状态时此图片不再响应鼠标左键事件,只响应鼠标右键事件。
我们要为每个状态设置一个标识符,用来判断此时图片的状态和改变此时图片的状态。用一个枚举类型来设置标识符,程序如下:
enum CellItemState {
23