为了熟悉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;
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
充电5分钟_装B3小时