QT实现贪吃蛇游戏

为了熟悉QT的相关知识,我用了大约8个小时的时间用QT再次写了一遍贪吃蛇。

因为QT的机制和平时写的程序流程不同,所以程序中可能没有遵守代码规范。

运行效果:

程序内除了实现贪吃蛇的基本功能外,还添加了记录得分、调节游戏速度、重新开始游戏等功能。

游戏内容使用QPainter类进行绘制。

编译环境:

Windows Qt 5.9.0 Qt Creator 4.3.0

思路:

数组存储蛇节点坐标的贪吃蛇游戏思路。

因为编写过程中使用了分文件编写,且QT框架的其他部分较多,这里仅展示程序实现主要代码。

代码:

MainWindow.h 主窗口类头文件

#ifndef WIDGET_H

#define WIDGET_H

#include <QWidget>

#include <QPainter> //画家类

#include "snake.h" //蛇类

#include <QKeyEvent> //键盘事件

#include "food.h" //食物类

#include <QTimer> //定时器类

namespace Ui {

class Widget;

}

class Widget : public QWidget

{

Q_OBJECT

public:

explicit Widget(QWidget *parent = 0);

~Widget();

//绘图事件

void paintEvent(QPaintEvent *);

//游戏结束的情况

void GameOver();

private:

Ui::Widget *ui;

Snake snake; //蛇对象

char key = 'd'; //接收键值,初始向右

Food food; //食物对象

//创建定时器

QTimer *timer = new QTimer(this);

bool gameflag = false;//游戏结束标记

int score = 0; //记录得分

int timerspeed = 200; //定时器速度

bool bugflag = false; //用于解决操控过快导致撞死自己的bug的标志

//键盘事件,改变键值

void keyPressEvent(QKeyEvent *ev);

};

#endif // WIDGET_H

MainWindow.cpp函数实现

#include "MainWindow.h"

#include "ui_widget.h"

#include <QLabel>

#include <QPushButton>

//主窗口构造函数

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget)

{

ui->setupUi(this); //初始化出.ui界面

//一个格子宽高25像素,地图宽高600像素,每行有24个格子

//设置固定窗口大小

setFixedSize(1000,600);

//设置得分标签控件的属性

ui->label->setFont(QFont("黑体", 20, QFont::Bold, false));

//设置游戏速度标签内容

ui->label_2->setFont(QFont("楷体", 16, QFont::Bold, false));

ui->label_2->setText("游戏速度:");

//滑动条控件,这里将数值按一定比例放大缩小

ui->horizontalSlider->setValue(200 >> 2);

//监听滑动条控件滑动时,改变定时器速度为滑动条的值

connect(ui->horizontalSlider,QSlider::valueChanged,[=]()

{

timerspeed = ui->horizontalSlider->value() << 2;

});

//设置重新开始按钮属性和内容

ui->pushButton_3->setFont(QFont("黑体",12));

ui->pushButton_3->setText("重新开始");

//监听重新开始按钮

connect(ui->pushButton_3,QPushButton::clicked,[=]()

{

snake.Reset(); //重置蛇

score = 0; //得分清0

key = 'd'; //key值向右

timerspeed = 200 << 2;//重置游戏速度

timer->start(timerspeed);//重置定时器

ui->horizontalSlider->setValue(200 >> 2);//重置滑动条

gameflag = false; //重置游戏结束标志

});

//开启定时器

timer->start(timerspeed);

//监听定时器的信号,执行表达式内容

connect(timer,&QTimer::timeout,[=]()

{

timer->start(timerspeed); //调整定时器的速度

snake.Move(key); //蛇移动函数

//吃到食物的情况

(food.getfoodX() == snake.snakevec.at(0).x && food.getfoodY() == snake.snakevec.at(0).y) ?

score++, food.randfood(): //得分+1,随机产生一个食物坐标

snake.snakevec.pop_back(); //删除蛇尾

GameOver(); //游戏失败的情况

update(); //调用绘图函数

//更新标签控件的文本内容

ui->label->setText(QString("得分:%1").arg(score));

});

}

//游戏失败情况

void Widget::GameOver()

{

//撞墙失败

if(snake.snakevec.at(0).x >= 24 * 25 || snake.snakevec.at(0).x < 0 ||

snake.snakevec.at(0).y < 0 || snake.snakevec.at(0).y >= 24 * 25)

{

gameflag = true;

timer->stop(); //暂停定时器

return;

}

//撞自己失败

for(int i = 1; i < snake.snakevec.size(); i++)

{

if(snake.snakevec.at(0).x == snake.snakevec.at(i).x &&

snake.snakevec.at(0).y == snake.snakevec.at(i).y)

gameflag = true, timer->stop();

}

}

//绘图事件

void Widget::paintEvent(QPaintEvent *)

{

//创建画家对象,指定绘图设备为this主窗口

QPainter painter(this);

//设置画刷为红色

QBrush brush1(Qt::red);

//让画家使用画刷

painter.setBrush(brush1);

//画食物

painter.drawRect(QRect(food.getfoodX(),food.getfoodY(),25,25));

//设置画刷为黑色

QBrush brush2(Qt::blue);

painter.setBrush(brush2);

//遍历蛇坐标容器,画出代表蛇身的矩形

for(auto snakenodei : snake.snakevec)

//蛇头画圆形

(snakenodei.x == snake.snakevec.at(0).x &&

snakenodei.y == snake.snakevec.at(0).y) ?

//蛇头画圆形

painter.setRenderHint(QPainter::Antialiasing), //用抗锯齿画圆

painter.drawEllipse(QPoint(snakenodei.x + 12,snakenodei.y + 12),12,12):

//蛇身画矩形

painter.drawRect(QRect(snakenodei.x,snakenodei.y,25,25));

bugflag = false; //在画出蛇之后将标志设为假

//设置画刷为黑色

QBrush brush3(QColor(128, 64, 0));

painter.setBrush(brush3);

//画出墙壁

for(int i = 0; i < 24; i++)

painter.drawRect(QRect(25 * 25, i * 25, 25, 25));

//游戏结束时的绘图

if(gameflag)

{ //设置文字属性

QFont font("楷体", 80, QFont::Bold, false);

painter.setFont(font); //使用字体

painter.drawText(QRect(240, 200, 1000, 500), "游戏结束"); //画出游戏结束文字

}

}

//键盘事件,改变贪吃蛇移动方向

void Widget::keyPressEvent(QKeyEvent *ev)

{

if(bugflag) //bug标志为真直接返回

return;

switch (ev->key())

{

case Qt::Key_W:

if(key == 's') break; //按下与当前方向相反按键时break

key = 'w';

bugflag = true; break; //按键之后将标志设为真

case Qt::Key_S:

if(key == 'w') break;

key = 's';

bugflag = true; break;

case Qt::Key_A:

if(key == 'd') break;

key = 'a';

bugflag = true; break;

case Qt::Key_D:

if(key == 'a') break;

key = 'd';

bugflag = true; break;

case Qt::Key_Space: //空格键暂停,这里有点问题

timer->stop(); break;

default: //其他键重启定时器

timer->start(timerspeed);

}

}

//析构

Widget::~Widget()

{

delete ui;

}

snake.h 蛇类头文件

#ifndef SNAKE_H

#define SNAKE_H

#include <QWidget>

#include <QVector> //Qt动态数组类

class Snake : public QWidget

{

Q_OBJECT

private:

//蛇坐标结构

struct Snakecoor

{

int x;

int y;

};

public:

explicit Snake(QWidget *parent = nullptr);

//蛇坐标容器

QVector<Snakecoor> snakevec;

//蛇移动主要函数

void Move(char key);

//根据key值确定蛇的移动方向

void DeteDirMove(char key, Snakecoor &nexthead);

//重置蛇

void Reset();

signals:

public slots:

};

#endif // SNAKE_H

snake.cpp 蛇类函数实现

#include "snake.h"

//构造函数初始化一条蛇

Snake::Snake(QWidget *parent) : QWidget(parent)

{

Snakecoor snakenode; //临时结构变量用于创建蛇

for (int i = 5; i >= 0; i--) //从右向左创建5节蛇身,容器的第一个元素为蛇头

{

snakenode.x = 25 * 8 + i * 25;//每个格子宽25像素

snakenode.y = 25 * 8;

snakevec.push_back(snakenode);//将蛇节点插入到数组中

}

}

//确定蛇的移动方向,确定新蛇头的坐标位置

inline void Snake::DeteDirMove(char key, Snakecoor &nexthead)

{

switch (key)

{

case 'w':

//新蛇头坐标根据旧蛇头坐标改变

nexthead.x = snakevec.front().x;

nexthead.y = snakevec.front().y - 25;

break;

case 's':

nexthead.x = snakevec.front().x;

nexthead.y = snakevec.front().y + 25;

break;

case 'a':

nexthead.x = snakevec.front().x - 25;

nexthead.y = snakevec.front().y;

break;

case 'd':

nexthead.x = snakevec.front().x + 25;

nexthead.y = snakevec.front().y;

}

}

//蛇移动主要函数

void Snake::Move(char key)

{

Snakecoor nexthead; //创建一个新的蛇头

DeteDirMove(key, nexthead); //确定新蛇头的位置

snakevec.insert(snakevec.begin(), nexthead); //将新蛇头插入到容器头部

}

//重置蛇函数

void Snake::Reset()

{

snakevec.clear(); //清空容器

//初始化蛇

Snakecoor snakenode;

for (int i = 5; i >= 0; i--)

{

snakenode.x = 25 * 8 + i * 25;

snakenode.y = 25 * 8;

snakevec.push_back(snakenode);

}

}

food.h 食物类头文件

#ifndef FOOD_H

#define FOOD_H

#include <QWidget>

class Food : public QWidget

{

Q_OBJECT

public :

int food_x = 0; //食物坐标

int food_y = 0;

public:

explicit Food(QWidget *parent = nullptr);

void randfood(); //随机产生食物坐标

int getfoodX(); //返回食物坐标

int getfoodY();

signals:

public slots:

};

#endif // FOOD_H

food.cpp 食物类函数实现

#include "food.h"

#include <ctime>

Food::Food(QWidget *parent) : QWidget(parent)

{

randfood(); //创建对象时产生就一个随机坐标

}

//随机产生食物坐标

void Food::randfood()

{

srand((unsigned)time(NULL));

food_x = (rand() % 24) * 25;

food_y = (rand() % 24 )* 25;

}

//获取食物的坐标

int Food::getfoodX()

{

return food_x;

}

int Food::getfoodY()

{

return food_y;

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

以上是 QT实现贪吃蛇游戏 的全部内容, 来源链接: utcz.com/p/246147.html

回到顶部