一、实验要求
1. 实现贪吃蛇游戏基本功能,屏幕上随机出现一个“食物”,利用键盘中的方向键(上
下左右)控制“蛇”的移动,“蛇”吃到食物后身体加长一点,得分增加,“蛇”碰到边界或蛇头与蛇
身相撞,“蛇”死亡,游戏结束。
2. 为游戏设计友好的交互界面,例如欢迎界面,游戏界面,游戏结束界面,并且有开始键,暂停键
和停止退出的选项。
3. 对吃到的食物进行分数计算,可以设置游戏速度,游戏音乐等拓展元素。
二、开发工具
编程语言:C++
工具:QT Creator
三、实验思路
1.页面的跳转
游戏主要设计三个界面,第一个界面是欢迎界面(主窗口),第二个和第三个分别是操作提示界面(副窗口1)和游戏界面(副窗口2)。
为了实现游戏界面的跳转,则需要借助QT自定义信号与槽。自定义信号与槽可以实现两个独立窗口之间的切换,点击"Next" 跳到下一个窗口, 点击"Back" 返回到上一个窗口。
具体步骤如下:
① 新建一个副窗口类,基类仍为QWidget。可以修改副窗口的标题加以区分
this->setWindowTitle("Windows2")
② 在副窗口头文件中声明新的按钮back
private:
QPushButton back
并在副窗口.cpp中对按钮进行编辑
back.setParent(this);
back.setText("Back");
back.move(150, 50);
但是, 这仅仅是写了一个新窗口的类, 还没有实例化,所以我们在主窗口.h中先包含副窗口的头文件, 然后实例化一个副窗口w对象。
按照类似步骤在主窗口文件里新建一个按钮next。
③建立信号与槽的连接,当点击next按钮时,就会运行nextSlot()函数。
connect(next, &QPushButton::clicked, this, QWidget::nextSlot);
void QWidget::nextSlot() {
Win2.show();
this->hide();
}
④要实现Back功能, 就需要在"Back"按钮按下后, 副窗口发送一个信号, 然后主窗口收到这个信号后, 显示自己, 隐藏副窗口。
connect(&back, &QPushButton::clicked, this, &win2::sendSignal);
在副窗口.h中声明一个自定义的信号, 和用于发送该信号的槽函数:
signals:
void backSignal();
public slots:
void sendSignal();
由于信号只需声明, 无需定义, 所以只要在副窗口.cpp定义槽函数来发送信号:
void win2::sendSignal()
{
emit backSignal();
}
在主窗口中需要再定义一个槽函数来处理back信号,在主窗口.h中声明槽函数。
void backSlot();
在主窗口.cpp中定义:
void QWidget::backSlot()
{
this->show();
win2.hide();
}
connect信号与槽, 收到副窗口发送的信号后返回主窗口:
connect(&win2, &win2::backSignal, this, &QWidget::backSlot);
这样就实现了两个界面之间的跳转。
2.蛇和食物的表示
为了实现蛇的移动,需要在蛇头出添加小方块,蛇尾出删除一个小方块,因此需要在容器的头部进行插入操作。所以选择链表QList来表示蛇。用链表存储蛇身后,在构造函数中对其进行初始化,再通过渲染函数将其画在界面里。
食物就用一个小方块进行表示。通过封装一个成员函数来随机分配食物这个小方块的位置。
3.蛇的移动
3.1定时器
定时器可以使游戏动起来,也就是一帧一帧的进行绘制,来实现“蛇”的运动。使用QTimer类定义一个定时器,该定时器不断地发出timeout信号,相应的槽函数就会不断地接收该信号来执行动作以控制蛇移动,然后不断地进行重新渲染,以达到蛇不断移动的效果。
3.2按键反应
本实验通过控制键盘上下左右四个键来实现蛇的移动。因此定义四个成员函数,分别对应按键上下左右四个键的按键反应。每个成员函数运用的原理就是在在蛇头出添加小方块,蛇尾出删除一个小方块。即在链表头部进行插入操作。
3.3蛇的增长
判断蛇身是否与食物重合,若重合了,则在头部增加两个小方块,尾部删除一个小方块。若没有重合,则在头部增加一个小方块,尾部删除一个小方块。
3.4蛇运动的暂停
定时器调用stop()函数时就会停止发送timeout()信号,则timeout()信号相应的槽函数也就停止执行,timeout()相应的槽函数是控制蛇移动的,timeout相应的槽函数停止执行,那么对应的蛇也就停止了移动。