一.实验内容:
1)实现贪吃蛇游戏基本功能,屏幕上随机出现一个“食物”,称为豆子。玩家能利用WASD键控制“蛇”的移动,“蛇”吃到“豆子”后“蛇”身体加长一节,得分增加,“蛇”碰到边界或蛇头与蛇身相撞,“蛇”死亡,游戏结束。
2)进行交互界面的设计,要有开始键、暂停键和停止退出的选项,能够控制游戏进程。对蛇吃到豆子进行分值计算,可以设置游戏速度拓展元素。
二.实验环境
QT和C++环境下实现
三.代码实现
1.开始界面的实现
页面的跳转,通过信号与槽的的方式来实现
头文件
#ifndef START_H
#define START_H
#include <QDialog>
namespace Ui {
class start;
}
class start : public QDialog
{
Q_OBJECT
public:
explicit start(QWidget *parent = nullptr);
~start();
int getspeed();
private:
Ui::start *ui;
};
#endif // START_H
源文件:
#include "start.h"
#include "ui_start.h"
#include <QDebug>
start::start(QWidget *parent) :
QDialog(parent),
ui(new Ui::start)
{
ui->setupUi(this);
this->setFixedSize(this->size());
}
start::~start()
{
delete ui;
}
int start::getspeed()
{
int n=ui->comboBox->currentIndex();
if(n==0)return 20;
if(n==1)return 10;
if(n==2)return 5;
}
2.绘制食物和蛇身,以及判断是否吃到食物
随机生成数且设置srand
生成随机数randy randx
判断xy是否在游戏界限内,若在游戏界限内生成食物的坐标
用一个循根据坐标数组绘制食物的点
设置画笔的颜色和宽度
用painter对象绘制食物
body用坐标数组来表示,用painter,来画点
判断蛇头是否在食物的范围内,如果在这个范围内,就吃掉食物,并且更新长度。
//绘制函数,负责绘制食物和蛇
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setPen(QPen(QColor(Qt::yellow)));
painter.setBrush(QBrush(QColor(Qt::white)));
//游戏边框线
painter.drawRect(rectangle);
//随机生成食物
if(!eatflag)
{
eatflag = 1;
srand(QTime::currentTime().msec()*rand()*rand()*rand());
while(1)
{
//按照界面的大小生成的数
randx = rand() % (this->width());
randy = rand() % (this->height());
//判断一下是否在游戏界限内,在界内才会生成
if(randx >= 15 && randy >= 45)
{
if(randx <= (this->width()-15) && randy <= (this->height()-15))
{
food_point.setX(randx);
food_point.setY(randy);
break;
}
}
}
}
QPen pen;
pen.setWidth(10);
pen.setColor(Qt::green);//设置食物的颜色
painter.setPen(pen);
painter.drawPoint(food_point);//画食物
//len越大,画的越长
for(int j= 0;j < len;j++)
{
pen.setColor(Qt::black);
painter.setPen(pen);
painter.drawPoint(body[j]);//画蛇,按照这个坐标数组去画点
}
//判断是否吃到食物
if((head_point.y() < (food_point.y()+5))&&(head_point.y() > (food_point.y()-5)))
{
if((head_point.x()<(food_point.x()+5))&&(head_point.x()>(food_point.x()-5)))
{
len += 5;
score += 1;
eatflag = 0;
// qDebug() << "eat!!";
}
}
}
3.键盘响应实现移动
从键盘传入参数,当direction为0的时候,将头部坐标y值减一,将头部坐标赋给后面的body(0),将后面的坐标依次向前移动一个位置
switch (direction)
{
case 0:
point = body[0];
head_point.setY(head_point.y()-1);
body[0] = head_point;
for(i = 1; i < len; i++)
{
buf = body[i];
body[i] = point;
point = buf;
}
break;
case 1:
point = body[0];
head_point.setY(head_point.y()+1);
body[0] = head_point;
for(i = 1; i < len; i++)
{
buf = body[i];
body[i] = point;
point = buf;
}
break;
case 2:
point = body[0];
head_point.setX(head_point.x()-1);
body[0] = head_point;
for(i = 1; i < len; i++)
{
buf = body[i];
body[i] = point;
point = buf;
}
break;
case 3:
point = body[0];
head_point.setX(head_point.x()+1);
body[0] = head_point;
for(i = 1; i < len; i++)
{
buf = body[i];
body[i] = point;
point = buf;
}
break;
default:
break;
}
//update()时,调用paintEvent(QPaintEvent*)
update();
}
void Widget::keyPressEvent(QKeyEvent *event)
{
//点击按键会给direction赋值,但如果是向上走就不能往下 上下左右0123
switch (event->key())
{
case Qt::Key_W:
if(direction == 1)
break;
direction = 0;
break;
case Qt::Key_S:
if(direction == 0)
break;
direction = 1;
break;
case Qt::Key_A:
if(direction == 3)
break;
direction = 2;
break;
case Qt::Key_D:
if(direction == 2)
break;
direction = 3;
break;
default:
break;
}
}
4.游戏结束的条件
撞到墙或者头撞到身体
void Widget::timerEvent(QTimerEvent *event)
{
static int i = 0;
//update score
QString text = QString("你的得分:%1").arg(score);
ui->label_2->setText(text);
/***********游戏结束条件********************/
//撞到身体了
for(i = 1;i<len;i++)
{
if(head_point == body[i])
{
killTimer(timeid);
QMessageBox::about(this,"游戏结束",text);
}
}
//撞墙
if(head_point.x() <= 15 || head_point.y() <= 45)
{
killTimer(timeid);
QMessageBox::about(this,"游戏结束",text);
}
else if(head_point.x() >= (this->width()-15) || head_point.y() >= (this->height()-15))
{
killTimer(timeid);
QMessageBox::about(this,"游戏结束",text);
}
四.实际演示
1.开始界面
可以选者蛇身的速度
2.开始游戏
3.游戏结束
项目界面