使用Qt实现简单贪吃蛇小游戏(带登录界面)

贪吃蛇

创建项目时使用QWidget,项目名随意,

首先各种类的生命
1.贪吃蛇本体使用小方块来代替
2.使用QList类来保存贪吃蛇的本体
3.使用定时器来设定奖励以及贪吃蛇本体的刷新时间
4.使用随机函数,来在屏幕上随机生成奖励节点
5.使用keyPressEvent来监控按键的按下,控制贪吃蛇的移动
6.通过添加新文件QDialog实现登录界面

登录界面实现

dialog.h文件
#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QMessageBox>

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private slots:
    void on_login_clicked();
    void on_Exit_clicked();

private:
    Ui::Dialog *ui;
};

#endif // DIALOG_H
dialog.cpp文件
#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);

    this->setWindowTitle("GreedySnake!");
    ui->passwordline->setEchoMode(QLineEdit::Password);
}

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

void Dialog::on_login_clicked()
{
    if(ui->nameline->text().trimmed() == "Baiyang" && ui->passwordline->text() == "123456")//登录用户名和密码可自行修改
    {
        this->accept();
    }
    else
    {
        QMessageBox::warning(this,tr("警告!"),tr("用户名或密码错误!"),QMessageBox::Yes);
        ui->nameline->clear();
        ui->passwordline->clear();
        ui->nameline->setFocus();
    }
}

void Dialog::on_Exit_clicked()
{
    reject();
    Dialog::close();
}
修改main.cpp如下
#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Dialog dialog;
    if(dialog.exec() == QDialog::Rejected)
        return 0;
        
    Widget w;
    w.show();

    return a.exec();
}

注:修改main函数是为了通过dialog界面,也就是登录界面来判断是否打开游戏界面

dialog.ui设计

在这里插入图片描述
注:图中控件的名字和text内容自行修改
注:Widget的ui界面通过代码去实现,所以不用自行设计

Widget.h声明

#ifndef WIDGET_H
#define WIDGET_H

#include "dialog.h"
#include <QWidget>
#include <QKeyEvent>
#include <QPen>
#include <QBrush>
#include <QRectF>
#include <QPainter>
#include <QDebug>
#include <QTime>
#include <QTimer>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

protected:
    void paintEvent(QPaintEvent *);
    void keyPressEvent(QKeyEvent *);

private:
    void TopRectF();
    void DownRectF();
    void LeftRectF();
    void RightRectF();
    void deleteLastRectF();
    bool snakeStrike();
    enum Move{Left,Right,Up,Down};

protected slots:
    void timeOut();
    void rewardTimeOut();

private:
    Ui::Widget *ui;
    QList<QRectF>rewardNode;
    QList<QRectF>snake;
    int snakeNodeWidth = 10;
    int snakeNodeHeight = 10;
    QTimer *timer;
    QTimer *rewardTimer;
    int time = 100;
    int moveFlog = Up;
    bool gameOver = false;
    bool gameStart = false;
};

#endif // WIDGET_H

Widget类函数的实现

构造函数

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    resize(500,500);
    setStyleSheet("QWidget{background:black}");
    setWindowOpacity(0.8);

    snake.append(QRectF(200,500,snakeNodeWidth,snakeNodeHeight));
    TopRectF();

    rewardNode.append(QRectF(qrand()%(this->width()/20)*20,qrand()%(this->height()/20)*20,snakeNodeWidth,snakeNodeWidth));

    timer = new QTimer;
    connect(timer,SIGNAL(timeout()),this,SLOT(timeOut()));

    rewardTimer = new QTimer;
    connect(rewardTimer,SIGNAL(timeout()),this,SLOT(rewardTimeOut()));
}
Widget::~Widget()
{
    delete ui;
}

奖励节点与贪吃蛇本体刷新

void Widget::timeOut()
{
    int flage = 1;
    for(int i=0;i<rewardNode.length();i++)
    {
        if(rewardNode.at(i).contains(snake.at(0).topLeft()+QPointF(snakeNodeWidth/2,snakeNodeHeight/2)))
        {
            if(rewardNode.at(i).width()>snakeNodeWidth)
                flage += 2;
            flage++;
            rewardNode.removeAt(i);
            break;
        }
    }
    while(flage--)
    {
        switch (moveFlog) {
        case Up:
            TopRectF();
            break;
        case Down:
            DownRectF();
            break;
        case Left:
            LeftRectF();
            break;
        case Right:
            RightRectF();
            break;
        default:
            break;
        }
    }
    deleteLastRectF();

    update();
}
void Widget::rewardTimeOut()
{
    qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
    if(rewardNode.length() > 5)
        rewardNode.removeAt(qrand()%5);
    rewardNode.append(QRectF(qrand()%(this->width()/20)*20,qrand()%(this->height()/20)*20,snakeNodeWidth,snakeNodeWidth));
    if(qrand()%5 == 3)
        rewardNode.append(QRectF(qrand()%(this->width()/20)*20-5,qrand()%(this->height()/20)*20-5,snakeNodeWidth*2,snakeNodeWidth*2));

}

向上移动

void Widget::TopRectF()
{
    if(snake.at(0).y()-snakeNodeHeight < 0)
    {
        snake.insert(0,QRectF(QPointF(snake.at(0).x(),this->height()-snakeNodeHeight),QPointF(snake.at(0).x()+snakeNodeWidth,this->height())));
    }
    else
    {
        snake.insert(0,QRectF(snake.at(0).topLeft()+QPointF(0,-snakeNodeHeight),snake.at(0).topRight()));
    }
}

向下移动

void Widget::DownRectF()
{
    if(snake.at(0).y()+snakeNodeHeight*2 > this->height())
    {
        snake.insert(0,QRectF(QPointF(snake.at(0).x(),snakeNodeHeight),QPointF(snake.at(0).x()+snakeNodeWidth,0)));
    }
    else
    {
        snake.insert(0,QRectF(snake.at(0).bottomLeft(),snake.at(0).bottomRight()+QPointF(0,snakeNodeHeight)));
    }
}

向左移动

void Widget::RightRectF()
{
    if(snake.at(0).x()+snakeNodeWidth*2 > this->width())
    {
        snake.insert(0,QRectF(QPointF(0,snake.at(0).y()),QPointF(snakeNodeWidth,snake.at(0).y()+snakeNodeHeight)));
    }
    else
    {
        snake.insert(0,QRectF(snake.at(0).topRight(),snake.at(0).bottomRight()+QPointF(snakeNodeWidth,0)));
    }
}

向右移动

void Widget::LeftRectF()
{
    if(snake.at(0).x()-snakeNodeWidth < 0)
    {
        snake.insert(0,QRectF(QPointF(this->width()-snakeNodeWidth,snake.at(0).y()),
                              QPointF(this->width(),snake.at(0).y()+snakeNodeHeight)));
    }
    else
    {
        snake.insert(0,QRectF(snake.at(0).topLeft()+QPointF(-snakeNodeWidth,0),snake.at(0).bottomLeft()));
    }
}

删除结尾数据

void Widget::deleteLastRectF()
{
    snake.removeLast();
}

绘图

void Widget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    QPen pen;
    QBrush brush;
    QFont font("方正舒体",12,QFont::ExtraLight,false);

    painter.setRenderHint(QPainter::Antialiasing);

    pen.setColor(Qt::green);
    brush.setColor(Qt::yellow);
    brush.setStyle(Qt::SolidPattern);

    painter.setPen(pen);
    painter.setBrush(brush);

    for(int i=0;i<snake.length();i++)
        painter.drawRect(snake.at(i));

    brush.setColor(Qt::red);
    painter.setBrush(brush);
    for(int i=0;i<rewardNode.length();i++)
        painter.drawEllipse(rewardNode.at(i));

    pen.setColor(Qt::white);
    painter.setPen(pen);
    painter.setFont(font);
    painter.drawText(20,20,QString("当前得分:")+QString("%1").arg(snake.length()));

    if(snakeStrike())
    {
        QFont font("方正舒体",30,QFont::ExtraLight,false);
        painter.setFont(font);
        painter.drawText((this->width()-300)/2,(this->height()-30)/2,QString("GAME OVER!"));
        timer->stop();
        rewardTimer->stop();
        gameOver = true;
    }
    QWidget::paintEvent(event);
}

按键事件

void Widget::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    case Qt::Key_Up:
        if(moveFlog != Down)
            moveFlog = Up;
        break;
    case Qt::Key_Down:
        if(moveFlog != Up)
            moveFlog = Down;
        break;
    case Qt::Key_Right:
        if(moveFlog != Left)
            moveFlog = Right;
        break;
    case Qt::Key_Left:
        if(moveFlog != Right)
            moveFlog = Left;
        break;
    case Qt::Key_Enter:
    case Qt::Key_Return:
        if(gameOver)
        {
            snake.clear();
            rewardNode.clear();
            moveFlog = Up;
            snake.append(QRectF(200,500,snakeNodeWidth,snakeNodeHeight));
            TopRectF();
            TopRectF();
            rewardNode.append(QRectF(qrand()%(this->width()/20)*20,qrand()%(this->height()/20)*20,snakeNodeWidth,snakeNodeWidth));
            timer->start(time);
            rewardTimer->start(time*30);
            gameOver = false;
        }
        break;
    case Qt::Key_Space:
        if(gameStart && !gameOver)
        {
            timer->start(time);
            rewardTimer->start(time*30);
            gameStart = false;
        }
        else if(!gameStart && !gameOver)
        {
            timer->stop();
            rewardTimer->stop();
            gameStart = true;
        }
        break;
    default:
        break;
    }
}

判断蛇头是否与蛇身相撞

bool Widget::snakeStrike()
{
    for(int i=0;i<snake.length();i++)
    {
        for(int j=i+1;j<snake.length();j++)
        {
            if(snake.at(i) == snake.at(j))
                return true;
        }
    }
    return false;
}

实现效果如下:

在这里插入图片描述
在这里插入图片描述

注:双击空格开始游戏
注:登录界面只实现了登录,并未实现注册,如果要实现注册,通过添加数据库,或者链表来保存用户数据即可。

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值