QT上实现贪吃蛇
设备描述
- Linux操作系统
- QT5.5.1
关键点分析
- 贪吃蛇的身体用什么形式展现
- 当方向改变时,蛇身如何实现转向前进
- 如何记录蛇身的每一个坐标
- 如何判断游戏结束
实现步骤
-
首先有两种办法实现,第一:用QPushButton按键类,每个一个按键就是蛇的一部分身体,另外:用QPaintEvent绘图事件画出蛇的身体,个人认为用QPushButton实现比较简单粗暴,表面上看起来效果都一样。
-
之前在想这个问题的时候很头痛,进入了一个误区,一直在想蛇头可以根据转向而立刻改变,但是蛇尾该如何慢慢转变过去呢,蛇身每转一次就有一个转折点,后面的蛇身都需要根据这个转折点来转向,心想还需要记录每一个转折点地址。但是后面发现根本就没用这么复杂,只需要将蛇身的每一个点根据上一个点的坐标走,第一个蛇身点根据蛇头走就可以了。
-
由于我的蛇身每一个节点都是一个QPushButton对象,而这个类有一个获取坐标的函数geometry();和设置控件坐标的函数setGeometry();这样我们只需要用一个指针数组记录下每一个QPushButton的地址,通过遍历数组的方式就可知道每一个蛇身节点的地址
QPushButton *dot1 = new QPushButton;
Snake_buff[buff_ip++] = (unsigned int *)dot1;
- 游戏结束有两种情况,第一:当蛇头碰到活动边界时,游戏结束。第二:当蛇头碰到蛇身体时,游戏结束。这里就要注意用全局变量存放活动边界的坐标。
代码讲解
main.h文件
#include <QMainWindow>
#include <QPushButton>
#include <QTimer>
#include <QPaintEvent>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
virtual void paintEvent(QPaintEvent*);
void over();
void SnakeInit();
public slots:
void onButStart();
void onButUp();
void onButDown();
void onButLift();
void onButRight();
void onTimer();
private:
Ui::MainWindow *ui;
QPushButton* dot; //蛇头
QPushButton* new_dot; //食物
QTimer* timerId; //定时器
int direction; //行驶方向
unsigned int* Snake_buff[100]; //蛇身
int buff_ip; //蛇身长度,同时也是游戏得分体现
int Snake_food[3]; //食物坐标,状态
};
复写void paintEvent(QPaintEvent*)绘图函数,画四条边线。头文件
#include"QPaintEvent"
void MainWindow::paintEvent(QPaintEvent *)
{
// 画一条直线
QPainter* painter = new QPainter(this); // 创建QPainter一个对象
QPen pen;
pen.setColor(Qt::black); // 设置画笔为黑色
painter->setPen(pen); // 设置画笔
painter->drawLine(line_lift,line_up,line_right,line_up);
painter->drawLine(line_lift,line_down,line_right,line_down);
painter->drawLine(line_lift,line_up,line_lift,line_down);
painter->drawLine(line_right,line_up,line_right,line_down);
}
main.cpp主函数
主要实现功能:初始化界面,初始化定时器,链接信号与槽
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowIcon(QIcon(":/new/prefix1/icon/dot_head.png"));
setWindowTitle("贪吃蛇");
timerId = new QTimer(this);
connect(timerId,SIGNAL(timeout()),this,SLOT(onTimer()));
ui->start->setStyleSheet(
"border-image: url(:/new/prefix1/icon/dot_green.png);font: 28pt Sans;");
ui->start->setText("开始");
dot = NULL;
new_dot = NULL;
connect(ui->start,SIGNAL(clicked(bool)),this,SLOT(onButStart()));
connect(ui->lift,SIGNAL(clicked(bool)),this,SLOT(onButLift()));
connect(ui->right,SIGNAL(clicked(bool)),this,SLOT(onButRight()));
connect(ui->up,SIGNAL(clicked(bool)),this,SLOT(onButUp()));
connect(ui->down,SIGNAL(clicked(bool)),this,SLOT(onButDown()));
}
main.cpp定时器函数
主要实现功能:蛇的运动过程,判断是否吃到食物,判断是否游戏结束
void MainWindow::onTimer()
{
int x = dot->geometry().x(); //获取蛇头坐标
int y = dot->geometry().y();
if(x==Snake_food[0] && y==Snake_food[1]) //判断蛇头与食物坐标是否相同,相同表示吃到食物
{
QPushButton *dot1 = new QPushButton; //创
Snake_buff[buff_ip++] = (unsigned int *)dot1;//将新的节点存入数组
dot1->setEnabled(0); //设置按钮为不可点击状态
dot1->setParent(this); //设置新建按钮显示在当前界面
dot1->setStyleSheet("border-image: url(:/new/prefix1/icon/dot_green.png);");
QPushButton* dot2 = (QPushButton*)Snake_buff[buff_ip-1];
int x1 = dot2->geometry().x(); //获取当前蛇身的最后一个节点
int y1 = dot2->geometry().y();
dot1->setGeometry(x1,y1,dot_size,dot_size); //将新节点加入蛇身末尾
dot1->show(); //显示出该节点
Snake_food[2] = 1; //食物已被吃标志
}
switch (direction) { //判断当前行驶方向
case 1:
if(y>=line_up)
dot->setGeometry(x,y-dot_size,dot_size,dot_size);//改变蛇头坐标
//当向左或右行驶时,下一个方向只能是上,或着下
//当向上或下行驶时,下一个方向只能是左,或者右
ui->up->setEnabled(0);
ui->down->setEnabled(0); //设置按钮状态为不可点击
ui->lift->setEnabled(1); //设置按钮状态为可以点击
ui->right->setEnabled(1);
break;
case 2:
if(y<=line_down)
dot->setGeometry(x,y+dot_size,dot_size,dot_size);
ui->up->setEnabled(0);
ui->down->setEnabled(0);
ui->lift->setEnabled(1);
ui->right->setEnabled(1);
break;
case 3:
if(x>=line_lift)
dot->setGeometry(x-dot_size,y,dot_size,dot_size);
ui->up->setEnabled(1);
ui->down->setEnabled(1);
ui->lift->setEnabled(0);
ui->right->setEnabled(0);
break;
case 4:
if(x<=line_right)
dot->setGeometry(x+dot_size,y,dot_size,dot_size);
ui->up->setEnabled(1);
ui->down->setEnabled(1);
ui->lift->setEnabled(0);
ui->right->setEnabled(0);
break;
default:
break;
}
if(buff_ip) //当蛇身长度大于等于一时,将蛇身的后一个节点等于前一个节点的坐标
{
for(int i=buff_ip-1;i>0;i--) //遍历蛇身所有节点
{
QPushButton* dot1 = (QPushButton*)Snake_buff[i];
QPushButton* dot2 = (QPushButton*)Snake_buff[i-1];
int x1 = dot2->geometry().x();
int y1 = dot2->geometry().y();
dot1->setGeometry(x1,y1,dot_size,dot_size);
}
QPushButton* dot1 = (QPushButton*)Snake_buff[0];
dot1->setGeometry(x,y,dot_size,dot_size);
}
//当贪吃蛇碰到边界时,游戏结束
if(y<line_up || y>=line_down || x<line_lift || x>=line_right)
over();
//当贪吃蛇碰到自己尾巴时,游戏结束
for(int i=2;i<buff_ip;i++)
{
QPushButton* dot2 = (QPushButton*)Snake_buff[i];
if(x==dot2->geometry().x() && y==dot2->geometry().y())
over();
}
if(Snake_food[2]) //当食物被吃掉时,创建下一个食物坐标
{
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));//生成随机数
int new_x = qrand()%1000/56*20+line_lift;
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
int new_y = qrand()%100/8*20+line_up;
Snake_food[0] = new_x; //记录下食物的坐标
Snake_food[1] = new_y;
new_dot->setGeometry(new_x,new_y,dot_size,dot_size);
new_dot->show();
Snake_food[2] = 0; //设置食物未被吃掉标志
}
ui->label->setText(QString::number(buff_ip)); //显示当前游戏得分
//设置蛇行驶速度,得分越高,速度越快
if(buff_ip==5)
timerId->setInterval(300);
else if(buff_ip==10)
timerId->setInterval(250);
else if(buff_ip==20)
timerId->setInterval(200);
else if(buff_ip==50)
timerId->setInterval(150);
}
项目的工程文件在我的资源文件里面,大家感兴趣的可以去下载。