qt是一个由Qt Company于1991年开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序(比如控制台工具和服务器)。在图形用户界面开发相比MFC更加适合新手入门以及非专业编程设计人员进行一些简易软件设计工作,本文介绍的是如何使用Qt5设计贪吃蛇小游戏作为入门学习。
由于Qt5安装的教程网上比较多,本文不再赘述。
1.新建项目工程
打开软件后,单击 文件(F)→新建文件或项目(N)。
(1).选择创建一个常用Qt桌面版本的编译程序。
(2).修改和确认项目名称以及项目存放位置。
/********不想修改可以使用默认***********/
(3).选择编译器,可默认不修改。
//好像是选择编译器吧,不是很清楚。
(4)设置类名&头文件&源文件等文件名称。
/**********这里基类选择QWidget**********/
/**********这里基类选择QWidget**********/
/**********这里基类选择QWidget**********/
若想后续直接Ctrl C+V使用示例代码的话,需要使用snake作为类名。
(5).完成新项目创建。
2.项目工程编译验证
完成了新项目的建立,可以运行试一下看是否成功。
单击右下角绿色的三角形,进行编译运行,若为如图所示弹窗即为成功。
3.UI界面设计
因为Qt方便就是在于GUI的设计方便,所以先进行图形化界面设计工作。
新建完成后,项目文件内应该包含图示文件.
.cpp是作为程序存放的地方 .ui是图形设计的存储的地方
(1).文字类显示使用Label。//显示字符文字都可以实现/.
(2).数值类显示使用LCD Number。//显示整数So easy,后会介绍怎么进行使用。
(3).输入类使用Push Button。//打开&发送&取消一系列按键都能用。
(4).下拉选项使用Combo Box。 //写写波特率&二级菜单&校验位啥的管够。
选择需要使用的控件按下左键拖到UI设计窗体中就可以了,尝试进行你想要的UI设计吧。
/*****************************************************************************************
控件都有属于自己的objectName,这个是控件能区分的唯一ID,不可重复!!
*****************************************************************************************/
4.功能程序设计
ui设计后,控件只是独立的一部分存在,并没有赋予我们需要的功能或用途,这时就需要在.CPP中进行功能和控件的关联了。
(1).系统函数以及自定义函数,变量的定义。
打开snake.h文件,在内添加需要用到的一些函数以及变量。
#ifndef SNAKE_H
#define SNAKE_H
#include <QWidget>
/*************定时器****************/
#include <QTime>
#include <QTimer>
/*************图形绘制***************/
#include <QPen>
#include <QPainter>
#include <QPaintEvent>
#include <QRect>
#include <QPoint>
#include <QBrush>
#include <QLabel>
/***************弹窗相关*****************/
#include <QMessageBox>
#include <QApplication>
#include <QDir>
#include <QProcess>
/****************程序调试*********************/
#include <QDebug>
static const int RETCODE_RESTART = 773;
namespace Ui {
class snake;
}
class snake : public QWidget
{
Q_OBJECT
public:
explicit snake(QWidget *parent = nullptr);
~snake();
public:
void Init(); //初始化函数界面
/**************定时器相关**************************/
public:
QTimer *m_Timer;
bool time_flag=false;
int base_time=0,time_s=0; //10ms的基础时间
bool flag_times=false;
private slots:
void dida_time();
void star_time();
void stop_time();
void restar_time();
/**************界面相关**************************/
public:
int x,y,base;
int save[625][2]={{2,0},{1,0},{0,0}};
int length=3;
int mark=0;
int now_head_x,now_head_y;
int head_x=2,head_y=0;
int food_x=6,food_y=6;
bool food_flag=true;
char head_direction=4; // ^1 v2 <3 >4
bool head_eat=false;
bool move_flag=false;
void reboot();
protected:
void paintEvent(QPaintEvent *); //绘制
/**************按键相关*************************/
protected:
void keyPressEvent(QKeyEvent *event);
void keyReleaseEvent(QKeyEvent *event);
private:
Ui::snake *ui;
};
#endif // SNAKE_H
(2).在snake.cpp中添加.h文件中的函数
#include "snake.h"
#include "ui_snake.h"
snake::snake(QWidget *parent) :
QWidget(parent),
ui(new Ui::snake)
{
ui->setupUi(this);
this->Init(); //初始化界面函数
}
snake::~snake()
{
delete ui;
}
void snake::Init()//初始化函数
{
ui->lcd_mark->display(0);
ui->lcd_time->display(0);
//关联按键和信号函数
connect(ui->btn_star,SIGNAL(clicked()),this,SLOT(star_time()));
connect(ui->btn_stop,SIGNAL(clicked()),this,SLOT(stop_time()));
connect(ui->btn_restar,SIGNAL(clicked()),this,SLOT(restar_time()));
}
void snake::star_time() //开启定时器
{
m_Timer = new QTimer(this);
m_Timer->start(100);//设定溢出时间100ms
connect(m_Timer,SIGNAL(timeout()),this,SLOT(dida_time()));//溢出后自动调用dida_time
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
// qDebug("OK!");
time_flag=true;
}
void snake::stop_time() //断开连接信号,即无法自动调用dida_time
{
if(time_flag==true)
{ disconnect(m_Timer,SIGNAL(timeout()),this,SLOT(dida_time())); time_flag=false; }
}
void snake::restar_time() //调用重启函数
{
reboot();
}
void snake::dida_time() //每100ms调用一次
{
base_time++;
time_s=base_time/10;
ui->lcd_time->display(time_s); //累加时间
// if(base_time%10==1) //1s时间到
{
/*********************是否吃掉食物********************************************/
if(head_x==food_x && head_y==food_y)
{
head_eat=true;
mark++;
length++;
ui->lcd_mark->display(mark);
}
/**********************随机格子**************************/
if(head_eat==false) //旧食物
{
}
else //新生成食物
{
food_x=qrand()%25; //在25x25的格子内生成食物
food_y=qrand()%25;
for(int i=1;i<length; i++) //防止食物为蛇身
{
if(food_x==save[i][0] && food_y==save[i][1])//若为蛇身,重构食物
{
food_x=qrand()%25;
food_y=qrand()%25;
i=1;
}
}
head_eat=false;
}
// qDebug("????");
now_head_x=head_x; //获取当前蛇头位置
now_head_y=head_y;
switch(head_direction) //添加蛇头位置
{
case 1: head_y--; break; // ^
case 2: head_y++; break; // v
case 3: head_x--; break; // <
case 4: head_x++; break; // >
}
/************************检查是否死亡************************/
for(int i=1;i<length; i++)
{
if(head_x==save[i][0] && head_y==save[i][1])//是否为自环死亡
{
disconnect(m_Timer,SIGNAL(timeout()),this,SLOT(dida_time()));
QMessageBox message(QMessageBox::NoIcon, "挑战失败", "the game is over!");
message.exec();
reboot();
}
if(head_x>24 || head_y>24 ||head_x<0 || head_y<0)//是否为撞墙死亡
{
disconnect(m_Timer,SIGNAL(timeout()),this,SLOT(dida_time()));
QMessageBox message(QMessageBox::NoIcon, "挑战失败", "the game is over!");
message.exec();
reboot();
}
}
// qDebug("direcrtion:%d head_x:%d head_y:%d",head_direction,head_x,head_y);
for(int i=1;i<length; i++)//更新蛇身位置信息
{
save[length-i][0]=save[length-i-1][0];
save[length-i][1]=save[length-i-1][1];
}
save[0][0]=head_x; //更新蛇头位置
save[0][1]=head_y;
update(); //刷新屏幕显示
}
}
void snake::paintEvent(QPaintEvent *)
{
QPainter painter(this);
// painter.drawLine(80,80,100,200); //图形绘制代码测试
// painter.setPen(Qt::red);
// painter.drawRect(10,10,100,100);
/***********************画底格****************************/
painter.setPen(QPen(Qt::blue,2)); //外框色 宽度
painter.setBrush(Qt::black); //内涂色
base=20;
for(x=0;x<25;x++)for(y=0;y<25;y++)
painter.drawRect(x*base,y*base,base,base); // 画25x25格子
/***********************绘制蛇身*****************************/
painter.setPen(QPen(Qt::yellow,2)); //外框色 宽度
painter.setBrush(Qt::green); //内涂色
for(int num=0;num<length;num++)
{
painter.drawRect(save[num][0]*base,save[num][1]*base,base,base); // 画格子
}
/***********************画食物*****************************/
painter.setPen(QPen(Qt::white,2)); //外框色 宽度
painter.setBrush(Qt::red); //内涂色
painter.drawRect(food_x*base,food_y*base,base,base); // 画格子
// painter.drawEllipse(50,150,200,200);//画圆
}
void snake::keyPressEvent(QKeyEvent *event) // 键盘按下事件d
{
switch (event->key())
{
case Qt::Key_W:
qDebug("I get up!"); if(head_direction!=2) head_direction=1; break;
case Qt::Key_S:
qDebug("I get down!"); if(head_direction!=1) head_direction=2; break;
case Qt::Key_A:
qDebug("I get left!"); if(head_direction!=4) head_direction=3; break;
case Qt::Key_D:
qDebug("I get right!");if(head_direction!=3) head_direction=4; break;
case Qt::Key_Space:
qDebug("I get Space!"); break;
default: QWidget::keyPressEvent(event); break;
}
update();
}
void snake::keyReleaseEvent(QKeyEvent *) // 按键释放事件
{
// 其他操作
}
void snake::reboot()//重启软件函数
{
QString program = QApplication::applicationFilePath();
QStringList arguments = QApplication::arguments();
QString workingDirectory = QDir::currentPath();
QProcess::startDetached(program, arguments, workingDirectory);
QApplication::exit();
exit(0);
}
由于具体实现过程注意的细节比较多,请自行理解读阅。
PS:(1):void snake::keyPressEvent(QKeyEvent *event) // 键盘按下事件 __按下键盘自动触发
void snake::paintEvent(QPaintEvent *) //屏幕显示 ___updata()可触发
以上为Qt内部的功能函数,系统会根据触发的信号进行调用,写入系统循环中。
(2):void snake::paintEvent(QPaintEvent *) //屏幕显示
内部需要包含所有与Paint相关的事件,不能将drawRect&drawLine等绘图函数写入其他函数内(除重定义函数外)。
/************************************************************
---------------- 正确用法 ----------------
*************************************************************/
void snake::paintEvent(QPaintEvent *)
{
QPainter painter(this);
// painter.drawLine(80,80,100,200); //图形绘制代码测试
// painter.setPen(Qt::red);
// painter.drawRect(10,10,100,100);
/***********************画底格****************************/
painter.setPen(QPen(Qt::blue,2)); //外框色 宽度
painter.setBrush(Qt::black); //内涂色
base=20;
for(x=0;x<25;x++)for(y=0;y<25;y++)
painter.drawRect(x*base,y*base,base,base); // 画25x25格子
}
/************************************************************
---------------- 错误用法 ----------------
*************************************************************/
void snake::display()
{
QPainter painter(this);
// painter.drawLine(80,80,100,200); //图形绘制代码测试
// painter.setPen(Qt::red);
// painter.drawRect(10,10,100,100);
/***********************画底格****************************/
painter.setPen(QPen(Qt::blue,2)); //外框色 宽度
painter.setBrush(Qt::black); //内涂色
base=20;
for(x=0;x<25;x++)for(y=0;y<25;y++)
painter.drawRect(x*base,y*base,base,base); // 画25x25格子
}
最后附上成品gif