QT实现可登录注册页面可切换的贪吃蛇小游戏

QT实现可登录注册页面可切换的贪吃蛇小游戏

设计思路

蛇身和豆子:使用了QList容器,其中的对象都是QRectf矩形;QList< QRectF >

移动:先判断当前方向,和蛇头方块坐标,判断该坐标是否会撞到蛇身、边框,没撞到则往

QList首插入一个节点,尾部元素移除,完成前进的效果;

如果移动后碰到食物(即蛇头坐标和某一个食物坐标重合),则不移除尾部元素,实现蛇身增

长一格

新建一个Qt项目

创建第一个登录窗口widget

widget.h

#include <QWidget>
#include <QSqlDatabase>//数据库类,需要加库
#include "snakesgame.h"//游戏窗口头文件
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
    Q_OBJECT
signals:
    void login_successed(QString);//登录成功的信号
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
private slots:
    void on_pushButton_2_clicked();//注册按钮的槽函数
    void on_pushButton_clicked();//登录按钮的槽函数
private:
    Ui::Widget *ui;
    snakesgame * s;//游戏窗口
    QSqlDatabase db;//申明数据库
};

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QSqlQuery>//SQL语句类
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);//按钮和行编辑框使用的拖拽
    s=new snakesgame;//定义游戏窗口
    s->hide();//游戏窗口隐藏
    this->setFixedSize(800,600);//设置当前窗口的固定大小
    connect(this, SIGNAL(login_successed(QString)), s, SLOT(sqlcreate(QString)));//信号与槽机制,登陆成功调用游戏界面的槽函数
    //创建数据库
        db = QSqlDatabase::addDatabase("QSQLITE");//选择使用哪一种数据库"QSQLITE",创建一个类型为QSQLITE的数据库
        db.setDatabaseName("namepassdb");//数据库的名字为namepassdb
        bool ok = db.open();

        //创建用户名+密码表
        QString  str("create table namepass(name, pass,score);");//创建数据库表的SQL语句
        QSqlQuery query;//辅助执行SQL语句的类
        query.exec(str);//执行SQL语句
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_pushButton_2_clicked()//注册
{
    //向数据库中加入一条信息
       QString  str = QString("insert into namepass(name, pass,score) values('%0', '%1','0');").arg(ui->lineEdit->text()).arg(ui->lineEdit_2->text());//加入信息的SQL语句
       QSqlQuery query;
       query.exec(str);
}

void Widget::on_pushButton_clicked()//登录
{
    //去数据库中查询一条信息
        QString  str = QString("select * from namepass where name='%0' and pass='%1';").arg(ui->lineEdit->text()).arg(ui->lineEdit_2->text());
        QSqlQuery query;
        query.exec(str);

        while(query.next())//如果查到信息返回正值
        {
//            qDebug() << query.value(0).toString();//显示
//            qDebug() << query.value(1).toString();
            emit login_successed(ui->lineEdit->text());//调用信号
            hide();//登录界面隐藏
            s->show();//游戏窗口显示
        }
}

创建第二个游戏窗口snakesgame继承于Qwidget

snakesgame.h

#include <QWidget>
#include <QPaintEvent>
#include<QKeyEvent>
#include<QList>
#include<QTimer>
#include<QLCDNumber>
#include<QLabel>
class snakesgame : public QWidget
{
    Q_OBJECT
public:
    explicit snakesgame(QWidget *parent = nullptr);
    ~snakesgame();
    void paintEvent(QPaintEvent *event);//绘画事件
    void keyPressEvent(QKeyEvent *event);//键盘按压事件
    void addTopRectF();//向上的方向增加节点,造成向上移动的效果
    void addDownRectF();//向下的方向增加节点,造成向下移动的效果
    void addRightRectf();//向右的方向增加节点,造成向右移动的效果
    void addLeftRectf();//向左的方向增加节点,造成向左移动的效果
    void deleteLastRectf();//删掉最后一个节点
    bool snakedead();//游戏结束
public slots:
    void game_timeout();
    void flash_timeout();
    void food_timeout();
    void sqlcreate(QString name);//接受登陆界面的槽函数
private:
    QString id;//游戏id
    QList<QRectF> snake;//贪吃蛇本体,使用了QList容器,其中的对象都是QRectf矩形
    QList<QRectF> food;//豆子
    int snakefoodWidth = 10;//蛇和豆子的宽度
    int snakefoodHeight = 10;   //蛇和豆子的高度
    int moveFlage=Up;//移动方向
    enum{Up,Down,Left,Right};
    QTimer * gametimer;//游戏刷新时间定时器
    QTimer * foodtimer;//食物事件刷新定时器
    QTimer * timer;//游戏时间定时器
    int time=100;//游戏刷新时间
    int Countdown=60;//游戏时间
    int score;//分数
    QLCDNumber *lcd;//显示时间
    QLabel * lb1;//显示提示
    QLabel * lb2;//显示历史最高分
    bool gameStart=false;//游戏是否开始
    bool gameOver=false;//游戏是否结束
};

snakesgame.cpp

snakesgame构造函数
#include "snakesgame.h"
#include<QPainter>
#include<QPen>
#include <QtGlobal>
#include <QPointF>
#include<Qtime>
#include <QSqlQuery>
snakesgame::snakesgame(QWidget *parent) : QWidget(parent)
{
    setWindowTitle("贪吃蛇");
    setFixedSize(800,600);
    lb1=new QLabel;
    QFont font("黑体",12,QFont::ExtraLight,false);
    lb1->setFont(font);
    lb1->setParent(this);
    lb1->setGeometry(610,150,190,300);
    lb1->setText("Tab:开始游戏\nSpace:暂停游戏\nSpace:恢复游戏\nAlt:游戏结束之\n后重新开始");
    lb2=new QLabel;
    lb2->setGeometry(630,10,170,30);
    lb2->setFont(font);
    lb2->setParent(this);
    snake.append(QRectF(300,300,snakefoodHeight,snakefoodWidth));//在对应的坐标添加节点
    addTopRectF();
    addTopRectF();
    food.append(QRectF(50,50,snakefoodHeight,snakefoodWidth));
    gametimer=new QTimer;
    //gametimer->start(time);
    connect(gametimer,SIGNAL(timeout()),this,SLOT(flash_timeout()));
    foodtimer=new QTimer;
    //foodtimer->start(time);
    connect(foodtimer,SIGNAL(timeout()),this,SLOT(food_timeout()));
    timer=new QTimer;
    lcd=new QLCDNumber;
    lcd->display(Countdown);
    lcd->setGeometry(630,80,150,50);
    lcd->setParent(this);
    connect(foodtimer,SIGNAL(timeout()),this,SLOT(game_timeout()));
}
与登陆界面联通的槽函数
void snakesgame::sqlcreate(QString name)//接受登陆界面传过来的id
{
    id=name;
    QString  str = QString("select * from namepass where name='%0';").arg(id);//在数据库表里查找此id
    QSqlQuery query;
    query.exec(str);
    while(query.next())
        {
            score=query.value(2).toString().toInt();//记录最高分
            QString str1=QString("历史最高分:%0").arg(query.value(2).toString());
            lb2->setText(str1);//在标签页显示
        }
}
绘图事件
void snakesgame::paintEvent(QPaintEvent *event)//绘图事件
{
    QPainter p1(this);
    QBrush brush1;
    brush1.setColor(QColor(128,128,128,127));
    brush1.setStyle(Qt::SolidPattern);
    p1.setBrush(brush1);
    p1.drawRect(0,0,600,600);//游戏框

    QPainter p2(this);
    QPen pen2(QColor(255, 0, 0, 255));
    QBrush brush2;
    brush2.setColor(QColor(255, 0, 0, 255));
    brush2.setStyle(Qt::Dense2Pattern);
    pen2.setWidth(5);
    p2.setPen(pen2);
    p2.setBrush(brush2);
    for(int i = 0;i < snake.length();i++){
            p2.drawRect(snake.at(i));
        }//画蛇
    pen2.setColor(QColor(0, 255, 0, 255));
    brush2.setColor(QColor(0, 255, 0, 255));
    brush2.setStyle(Qt::SolidPattern);
    p2.setBrush(brush2);
    p2.setPen(pen2);
        for(int i = 0;i < food.length();i++){
           p2.drawEllipse(food.at(i));
        }//画豆子
    QFont font("黑体",12,QFont::ExtraLight,false);//设置字体
    pen2.setColor(Qt::black);
    p2.setPen(pen2);
    p2.setFont(font);
    p2.drawText(630,60,QString("当前得分:%0").arg(snake.length()-3));

    if(snakedead()|| Countdown==0)//游戏结束,蛇死或时间结束
    {
            QFont font2("方正舒体",30,QFont::ExtraLight,false);
            p2.setFont(font2);
            p2.drawText(120,300,QString("GAME OVER!"));
            p2.drawText(120,400,QString("你的分数:%0").arg(snake.length()-3));
            if((snake.length()-3)>score)//如果分数大于历史最高分就更新数据库表
            {
                QString  str = QString("update namepass set score='%0' where name='%1';").arg(snake.length()-3).arg(id);
                QSqlQuery query;
                query.exec(str);
            }
            gametimer->stop();
            foodtimer->stop();
            gameOver = true;
        }
        //QWidget::paintEvent(event);//加不加都不影响
}
键盘按压事件
void snakesgame::keyPressEvent(QKeyEvent *event)//键盘按压事件
{
    event->accept();
    switch(event->key())
    {
        case Qt::Key_Up:
            if(moveFlage!=Down)//按键方向不能和现在移动方向相反
          moveFlage=Up;
        break;
        case Qt::Key_Down:
        if(moveFlage!=Up)
            moveFlage=Down;
        break;
    case Qt::Key_Right:
        if(moveFlage!=Left)
            moveFlage=Right;
        break;
    case Qt::Key_Left:
        if(moveFlage!=Right)
            moveFlage=Left;
        break;
    case Qt::Key_Tab://开始
            gametimer->start(time);
            foodtimer->start(time*30);
            timer->start(10*time);
        break;
    case Qt::Key_Alt://重新开始
        if(gameOver){
            snake.clear();
            food.clear();
            moveFlage = Up;
            snake.append(QRectF(300,300,snakefoodWidth,snakefoodHeight));
            addTopRectF();
            addTopRectF();
            //首先生成一个奖励节点
            food.append(QRectF(100,100,snakefoodWidth,snakefoodHeight));
            gametimer->start(time);
            foodtimer->start(time*30);
            timer->start(10*time);
            sqlcreate(id);
            gameOver = false;
        }
            break;
     case Qt::Key_Space://暂停和恢复游戏
         if(gameStart && !gameOver){//恢复游戏
             gametimer->start(time);
             foodtimer->start(time*30);
             timer->start(10*time);
             gameStart = false;
         }else if(!gameStart && !gameOver){//暂停
             gametimer->stop();
             foodtimer->stop();
             timer->stop();
             gameStart = true;
         }
         break;
    default:break;
    }
}
界面刷新
void snakesgame::flash_timeout()//界面刷新
{
    int flag=1;
    for(int i=0;i<food.length();i++)
    {
        if(food.at(i).contains(snake.at(0).topLeft()+QPointF(snakefoodWidth/2,snakefoodHeight/2)))//吃到豆子,判断方法是蛇头的中心坐标碰到了任何一个豆子
        {
            if(food.at(i).width()>snakefoodWidth){//大的豆子
             flag+=1;//奖励分数+1
             Countdown+=1;
            }
            flag+=1;
            Countdown+=1;
            food.removeAt(i);
            break;
        }
    }
    while(flag--)//向对应的方向添加吃到的节点数+1
    {
        switch (moveFlage) {
        case Up:
            addTopRectF();
            break;
        case Down:
            addDownRectF();
            break;
        case Right:
            addRightRectf();
            break;
        case Left:
            addLeftRectf();
            break;
        default:
            break;
        }
    }
    deleteLastRectf();//删掉蛇的最后一个节点,因为一开始flag就是1,而且也能表现出移动的效果
    update();
}
移动
void snakesgame::addTopRectF()//向上移动
{
//    if(snake.at(0).y()-snakefoodHeight<0){
//        snake.insert(0,QRectF(QPointF(snake.at(0).x(),600-snakefoodHeight),
//                                     QPointF(snake.at(0).x()+snakefoodWidth,600)));//蛇可以穿墙的情况
//           }else{
               snake.insert(0,QRectF(snake.at(0).topLeft()+QPointF(0,-snakefoodHeight),snake.at(0).topRight()));//在位置0添加矩形结点
//           }
}
void snakesgame::addDownRectF()//向下移动
{
//    if(snake.at(0).y()+snakefoodHeight*2 > 600){
//            snake.insert(0,QRectF(QPointF(snake.at(0).x(),snakefoodHeight),
//                                  QPointF(snake.at(0).x()+snakefoodWidth,0)));
//        }else{
           snake.insert(0,QRectF(snake.at(0).bottomLeft(),snake.at(0).bottomRight()+QPointF(0,snakefoodHeight)));
//        }
}
void snakesgame::addLeftRectf()//向左移动
{
//    if(snake.at(0).x()-snakefoodWidth < 0){
//           snake.insert(0,QRectF(QPointF(600-snakefoodWidth,snake.at(0).y()),
//                                 QPointF(600,snake.at(0).y()+snakefoodHeight)));
//       }else{
           snake.insert(0,QRectF(snake.at(0).topLeft()+QPointF(-snakefoodWidth,0),snake.at(0).bottomLeft()));
//       }
}

void snakesgame::addRightRectf()//向右移动
{
//       if(snake.at(0).x()+snakefoodWidth*2 > 600){
//               snake.insert(0,QRectF(QPointF(0,snake.at(0).y()),
//                                     QPointF(snakefoodWidth,snake.at(0).y()+snakefoodHeight)));
//           }else{
               snake.insert(0,QRectF(snake.at(0).topRight(),snake.at(0).bottomRight()+QPointF(snakefoodWidth,0)));
//           }
}
void snakesgame::deleteLastRectf()
{
    snake.removeLast();
}
蛇死亡
bool snakesgame::snakedead()
{
    if(snake.at(0).y()-snakefoodHeight<0 || snake.at(0).y()+snakefoodHeight*2 > 600 ||
           snake.at(0).x()-snakefoodWidth < 0 || snake.at(0).x()+snakefoodWidth*2 > 600)//撞墙
        {
            timer->stop();      //暂停定时器
            return true;
        }

    for(int i=0; i<snake.length(); i++){//撞到自己
            for(int j=i+1; j<snake.length(); j++){
                if(snake.at(i) == snake.at(j)){
                    timer->stop();
                    return true;
                }
            }
        }
        return false;
}
刷新奖励
void snakesgame::food_timeout()//刷新奖励
{
   qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));//生成随机数
   if(food.length() > 5){
       food.removeAt(qrand()%5);//界面只能有五个奖励
   }
   food.append(QRectF(qrand()%(600/20)*20,qrand()%(600/20)*20,snakefoodWidth,snakefoodHeight));
   if(qrand()%5 == 3){
       food.append(QRectF(qrand()%(600/20)*20-5,qrand()%(600/20)*20-5,snakefoodWidth*2,snakefoodHeight*2));//生成大的奖励
   }
}
游戏时间
void snakesgame::game_timeout()
{
    lcd->display(Countdown);//倒计时
    Countdown--;
}
snakesgame::~snakesgame()
{

}

游戏截图

登陆界面:
登陆界面
游戏界面一开始:
游戏界面一开始
重新开始过后的游戏
重新开始过后的游戏

实现视频

代码链接

百度云链接:https://pan.baidu.com/s/1i7jJbq-_Olz4hZkM0u46vQ
提取码:0802

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值