Qt C++制作贪吃蛇游戏(在Qt5.4.2可以正常运行)

源码素材下载:http://download.csdn.net/download/u011314012/10191968

1、开机界面 第一个按键为开始按键,第二个按键为退出按键,当点击时提示是否退出。 

Qt C++制作贪吃蛇游戏(在Qt5.4.2可以正常运行)_第1张图片


2、点击开始按键时进入游戏界面,游戏的等级和分数可以自己去设置,细节问题,自己可以去调试。

贪吃蛇的难点,就是蛇的移动,与绘制蛇身蛇尾。代码里面有备注。


Qt C++制作贪吃蛇游戏(在Qt5.4.2可以正常运行)_第2张图片

main.cpp

#include "mainwidget.h"
#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    mainWidget w;
    w.show();

    return a.exec();
}

mainwidget.h

#ifndef MAINWIDGET_H
#define MAINWIDGET_H

#include 
#include 
#include  //调色板
#include    //笔刷
#include 
#include 
#include 
#include "gamewidget.h"

class mainWidget : public QWidget
{
    Q_OBJECT

public:
    mainWidget(QWidget *parent = 0);
    ~mainWidget();

/*只能在类的成员函数中访问*/
private:
    QPushButton *startbtn;
    QPushButton *exitbtn;
    GameWidget *gamewidget; //游戏区

public slots:
    void startbtn_click();
    void exitbtn_click();

};

#endif // MAINWIDGET_H

mainwidget.cpp


#include "mainwidget.h"


mainWidget::mainWidget(QWidget *parent)
    : QWidget(parent)
{

    //设置主窗口大小
    this->resize (480, 310);
    //设置标题
    this->setWindowIcon (QIcon("img/icon.png"));
    this->setWindowTitle (tr("贪吃蛇"));

    //设置背景色(并且对图片进行缩放)
    QPalette palette;
    palette.setBrush (QPalette::Background, QBrush(QPixmap("img/back.jpg").scaled (this->size ())));
    this->setPalette (palette);

    startbtn = new QPushButton(this);
    //开始按钮图标
    startbtn->setIcon (QIcon("img/start.png"));
    startbtn->setIconSize (QSize(80, 80));
    //设置按键的坐标x, y, w, h
    startbtn->setGeometry (QRect(250, 190, 72, 72));
    //消除按钮的边框
    startbtn->setFlat (true);

    exitbtn = new QPushButton(this);
    //退出按钮图标
    exitbtn->setIcon (QIcon("img/quit.png"));
    exitbtn->setIconSize (QSize(70, 70));
    //设置按钮的坐标x, y, w, h
    exitbtn->setGeometry (QRect(350, 190, 70, 70));
    //消除按钮的边框
    exitbtn->setFlat (true);

    this->connect(startbtn, SIGNAL(clicked(bool)), this, SLOT(startbtn_click()));
    this->connect (exitbtn, SIGNAL(clicked(bool)), this, SLOT(exitbtn_click()));

}

/*对象消耗完自动调用析构函数*/
mainWidget::~mainWidget()
{
    /*释放空间防止内存泄露*/
    delete startbtn;
    delete exitbtn;
}

/*按键控制开始函数*/
void mainWidget::startbtn_click ()
{
    gamewidget = new GameWidget(this);
    gamewidget->show ();
}
/*按键控制退出函数*/
void mainWidget::exitbtn_click ()
{
    /*静态成员函数,可以用::直接引用*/
    if(QMessageBox::question (this, tr("提示"), tr("您是否要退出?"),
       QMessageBox::Ok | QMessageBox::Yes) == QMessageBox::Yes)
    {
        delete this;    //释放自己的资源
        exit(0);
    }
}

gamewidget.h

#ifndef GAMEWIDGET_H
#define GAMEWIDGET_H

#include 
#include 
#include 
#include  //调色板
#include    //笔刷
#include 
#include 
#include  //引用画笔
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

class GameWidget : public QWidget
{
    Q_OBJECT
public:
    explicit GameWidget(QWidget *parent = 0);
    //重载虚函数
    void paintEvent(QPaintEvent *);

private:
    QLabel *score_label;
    QLabel *level_label;
    QLineEdit *score_lineEdit;
    QLineEdit *level_lineEdit;
    QPushButton *leftbtn;
    QPushButton *rightbtn;
    QPushButton *upbtn;
    QPushButton *downbtn;
    QPushButton *startbtn;
    QPushButton *returnbtn;
    QPushButton *stopbtn;
    QPushButton *gameoverbtn;
    QFont ft;
    int direction;  //蛇移动的方向

    //画食物
    int foodx;
    int foody;
    int foodcount;
    int score;
    int level;
    QTimer *timer;
    int snake[100][2];  //保存蛇的每个节点的坐标
    int snake1[100][2]; //备份坐标数组
    void change_score(int count);

public slots:
    void leftbtn_click();
    void rightbtn_click();
    void upbtn_click();
    void downbtn_click();
    void startbtn_click();
    void stopbtn_click();
    void returnbtn_click();
    void timeroutslot();
    void change_level();

};

#endif // GAMEWIDGET_H

gamewidget.cpp

#include "gamewidget.h"

#define ROW 15
#define COL 15
#define UP 0
#define DOWN 1
#define LEFT 2
#define RIGHT 3

GameWidget::GameWidget(QWidget *parent)
    : QWidget(parent)
    , direction(0)
    , foodx(0)
    , foody(0)
    , foodcount(0)
    , score(0)
    , level(1)

{
    this->setAutoFillBackground (true);//覆盖父窗口
    //设置主窗口大小
    this->resize (480, 310);
    //设置标题
    this->setWindowIcon (QIcon("img/icon.png"));
    this->setWindowTitle (tr("贪吃蛇"));

    //设置背景色(并且对图片进行缩放)
    QPalette palette;
    palette.setBrush (QPalette::Background, QBrush(QPixmap("img/green.jpg").scaled (this->size ())));
    this->setPalette (palette);

    //分数
    score_label = new QLabel("score:", this);
    ft.setPointSize (16);
    score_label->setFont (ft);
    score_label->setGeometry (310, 8, 80, 35);
    score_lineEdit = new QLineEdit(this);
    ft.setPointSize (16);
    score_lineEdit->setFont (ft);
    score_lineEdit->setAlignment (Qt::AlignRight);
    score_lineEdit->setGeometry (390, 8, 80, 35);

    //等级
    level_label = new QLabel("level:", this);
    ft.setPointSize (16);
    level_label->setFont (ft);
    level_label->setGeometry (310, 50, 80, 35);
    level_lineEdit = new QLineEdit(this);
    ft.setPointSize (16);
    level_lineEdit->setFont (ft);
    level_lineEdit->setAlignment (Qt::AlignRight);
    level_lineEdit->setGeometry (390, 50, 80, 35);

    //按钮
    upbtn = new QPushButton("↑", this);
    upbtn->setGeometry (373, 115, 40, 30);

    leftbtn = new QPushButton("←", this);
    leftbtn->setGeometry (328, 155, 40, 30);

    downbtn = new QPushButton("↓", this);
    downbtn->setGeometry (373, 195, 40, 30);

    rightbtn = new QPushButton("→", this);
    rightbtn->setGeometry (418, 155, 40, 30);

    startbtn = new QPushButton("开始", this);
    startbtn->setGeometry (315, 245, 50, 30);

    stopbtn = new QPushButton("停止", this);
    stopbtn->setGeometry (370, 245, 50, 30);

    returnbtn = new QPushButton("返回", this);
    returnbtn->setGeometry (425, 245, 50, 30);

    connect (leftbtn, SIGNAL(clicked(bool)), this, SLOT(leftbtn_click()));
    connect (rightbtn, SIGNAL(clicked(bool)), this, SLOT(rightbtn_click()));
    connect (upbtn, SIGNAL(clicked(bool)), this, SLOT(upbtn_click()));
    connect (downbtn, SIGNAL(clicked(bool)), this, SLOT(downbtn_click()));
    connect (returnbtn, SIGNAL(clicked(bool)), this, SLOT(returnbtn_click()));
    connect (startbtn, SIGNAL(clicked(bool)), this, SLOT(startbtn_click()));
    connect (stopbtn, SIGNAL(clicked(bool)), this, SLOT(stopbtn_click()));
    connect (level_lineEdit, SIGNAL(textEdited(QString)), this, SLOT(change_level()));

    //产生行列存储坐标
    snake[0][0] = qrand () % COL;   //行存储
    snake[0][1] = qrand () % ROW;   //列存储
    direction = qrand () % 4;       //方向控制

    //产生食物
    int i;
    do{
        i++;
        foodx = qrand () % COL;
        foody = qrand() % ROW;
    }while(foodx == snake[i][0] && foody == snake[i][1]);


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

//绘图事件
void GameWidget::paintEvent (QPaintEvent *)
{
    int i, j;
    QPainter painter(this);

    //绘制游戏区
    for(i = 0; i < ROW; i++)
    {
        for(j = 0; j < COL; j++)
        {
           painter.drawRect (QRect(i * 20, j * 20, 20, 20));
        }
    }


    painter.drawImage (QRectF(foodx*20, foody*20, 20, 20), QImage("img/apple.png"));

    //蛇头
    switch(direction)
    {
    case UP:
        painter.drawImage (QRectF(snake[0][0] * 20, snake[0][1] * 20, 20, 20), QImage("img/headup.png"));
        break;
    case DOWN:
        painter.drawImage (QRectF(snake[0][0] * 20, snake[0][1] * 20, 20, 20), QImage("img/headdown.png"));
        break;
    case LEFT:
        painter.drawImage (QRectF(snake[0][0] * 20, snake[0][1] * 20, 20, 20), QImage("img/headleft.png"));
        break;
    case RIGHT:
        painter.drawImage (QRectF(snake[0][0] * 20, snake[0][1] * 20, 20, 20), QImage("img/headright.png"));
        break;
    default: break;
    }

    //画蛇身
    for(i = 1; i < foodcount; i++)
    {
        //右下
        if((snake[i][1] == snake[i - 1][1] && snake[i - 1][0] < snake[i][0] &&
           snake[i + 1][0] == snake[i][0] && snake[i + 1][1] < snake[i][1]) ||
          (snake[i - 1][0] == snake[i][0] && snake[i - 1][1] < snake[i][1] &&
           snake[i][1] == snake[i + 1][1] && snake[i + 1][0] < snake[i][0] ))
        {
            painter.drawImage (QRectF(snake[i][0] * 20, snake[i][1] * 20, 20, 20), QImage("img/br_corner.png"));
        }//右上
        else if((snake[i][0] == snake[i - 1][0] && snake[i][1] < snake[i - 1][1] &&
           snake[i + 1][1] == snake[i][1] && snake[i + 1][0] < snake[i][0]) ||
          (snake[i - 1][1] == snake[i][1] && snake[i - 1][0] < snake[i][0] &&
           snake[i][0] == snake[i + 1][0] && snake[i][1] < snake[i + 1][1] ))
        {
            painter.drawImage (QRectF(snake[i][0] * 20, snake[i][1] * 20, 20, 20), QImage("img/tr_corner.png"));
        }//左下
        else if((snake[i][0] < snake[i - 1][0] && snake[i][1] == snake[i - 1][1] &&
           snake[i + 1][1] < snake[i][1] && snake[i][0] == snake[i + 1][0]) ||
          (snake[i - 1][1] < snake[i][1] && snake[i][0] == snake[i - 1][0] &&
           snake[i][0] < snake[i + 1][0] && snake[i][1] == snake[i + 1][1] ))
        {
            painter.drawImage (QRectF(snake[i][0] * 20, snake[i][1] * 20, 20, 20), QImage("img/bl_corner.png"));
        }
        //左上
        else if((snake[i][0] == snake[i - 1][0] && snake[i][1] < snake[i - 1][1] &&
           snake[i][1] == snake[i + 1][1] && snake[i][0] < snake[i + 1][0]) ||
          (snake[i][1] == snake[i - 1][1] && snake[i][0] < snake[i - 1][0] &&
           snake[i][0] == snake[i + 1][0] && snake[i][1] < snake[i + 1][1] ))
        {
            painter.drawImage (QRectF(snake[i][0] * 20, snake[i][1] * 20, 20, 20), QImage("img/tl_corner.png"));
        }/*水平方向*/
        else if(snake[i][1] == snake[i - 1][1] && snake[i][0] != snake[i - 1][0])
        {
            painter.drawImage (QRectF(snake[i][0] * 20, snake[i][1] * 20, 20, 20), QImage("img/h_body.png"));
        }/*垂直方向*/
        else if(snake[i][1] != snake[i - 1][1] && snake[i][0] == snake[i - 1][0])
        {
            painter.drawImage (QRectF(snake[i][0] * 20, snake[i][1] * 20, 20, 20), QImage("img/v_body.png"));
        }
    }

    //蛇尾
    if((snake[foodcount][1] == snake[foodcount - 1][1] && snake[foodcount][0] < snake[foodcount - 1][0]) )
    {
        painter.drawImage (QRectF(snake[foodcount][0] * 20, snake[foodcount][1] * 20, 20, 20), QImage("img/tailright.png"));
    }
    else if(snake[foodcount][1] == snake[foodcount - 1][1] && snake[foodcount - 1][0] < snake[foodcount][0])
    {
        painter.drawImage (QRectF(snake[foodcount][0] * 20, snake[foodcount][1] * 20, 20, 20), QImage("img/tailleft.png"));
    }
    else if((snake[foodcount][0] == snake[foodcount - 1][0] && snake[foodcount][1] < snake[foodcount - 1][1]))
    {
        painter.drawImage (QRectF(snake[foodcount][0] * 20, snake[foodcount][1] * 20, 20, 20), QImage("img/taildown.png"));
    }
    else if((snake[foodcount][0] == snake[foodcount - 1][0] && snake[foodcount - 1][1] < snake[foodcount][1]))
    {
        painter.drawImage (QRectF(snake[foodcount][0] * 20, snake[foodcount][1] * 20, 20, 20), QImage("img/tailup.png"));
    }


}
//时间到的槽函数
void GameWidget::timeroutslot ()
{
    int i = 0;

    //是否吃到食物
    if(snake[0][0] == foodx && snake[0][1] == foody)
    {
        //更新食物坐标
        do{
            i++;
            foodx = qrand () % COL;
            foody = qrand() % ROW;
        }while(foodx == snake[i][0] && foody == snake[i][1]);

        //改变分数函数
        change_score(++foodcount);
    }
    //保存数据
    memcpy (snake1, snake, sizeof(snake));

    //改变蛇的每一节身子坐标
    for(i = foodcount; i > 0; i--)
    {
        snake[i][0] = snake[i - 1][0];
        snake[i][1] = snake[i - 1][1];
    }

    switch(direction)
    {
    case UP:
        snake[0][1]--;
        break;
    case DOWN:
        snake[0][1]++;
        break;
    case LEFT:
        snake[0][0]--;
        break;
    case RIGHT:
        snake[0][0]++;
        break;
    default: break;
    }

    //蛇边界检测
    if(snake[0][0] < 0 || snake[0][0] >= COL || snake[0][1] < 0 || snake[0][1] >= ROW)
    {
        //恢复数据
        memcpy (snake, snake1, sizeof(snake));
        /*静态成员函数,可以用::直接引用*/
        if(QMessageBox::question (this, tr("提示"), tr("GAME OVER"),
           QMessageBox::Yes) == QMessageBox::Yes)
        {
            this->close ();
            delete this;    //释放自己的资源
            return;         //结束这个函数
        }
    }

    //蛇自杀检测
    if(foodcount >= 3)
    {
        for(i = 3; i <= foodcount; i++)
        {
            if(snake[0][0] == snake[i][0] && snake[0][1] == snake[i][1])
            {
                //恢复数据
                memcpy (snake, snake1, sizeof(snake));

                /*静态成员函数,可以用::直接引用*/
                if(QMessageBox::question (this, tr("提示"), tr("GAME OVER"),
                   QMessageBox::Yes) == QMessageBox::Yes)
                {
                    this->close ();
                    delete this;    //释放自己的资源
                    return;         //结束这个函数
                }
            }
        }
    }

    this->update ();
}

void GameWidget::upbtn_click ()
{
    direction = UP;
}

void GameWidget::downbtn_click ()
{
    direction = DOWN;
}

void GameWidget::leftbtn_click ()
{
    direction = LEFT;
}

void GameWidget::rightbtn_click ()
{
    direction = RIGHT;
}

void GameWidget::startbtn_click ()
{
    //这个地方可以设置级别(通过改变蛇的移动时间)
    if(level == 1)
    {
        timer->start (800);
    }
    else if(level == 2)
    {
        timer->start (600);
    }else if(level == 3)
    {
        timer->start(400);
    }else if(level == 4)
    {
        timer->start (200);
    }
    level_lineEdit->setText (QString(tr("%1")).arg (level));
}

void GameWidget::returnbtn_click ()
{
    //删除GameWidget的this指针
    delete this;
}

void GameWidget::stopbtn_click ()
{
    timer->stop ();
}

void GameWidget::change_level ()
{
    bool ok;
    int level1 = QInputDialog::getInt (this, tr("标准int类型输入对话框"),
        tr("请输入等级1-3"), level_lineEdit->text ().toInt (&ok), 1, 4, 1, &ok);

    if(ok)
    {
        level = level1;
        level_lineEdit->setText (QString(tr("%1")).arg (level));

    }
    else
    {
        level_lineEdit->setText (QString(tr("%1")).arg (level));

    }
}

/*计算成绩*/
void GameWidget::change_score (int count)
{
    /*foodcount = 10 一级
      foodcount = 15 二级
      foodcount = 20 三级
      foodcount = 25 四级*/

    if(count >= 1 && count <= 10)
    {
        level = 1;
        score = count * 10;
        level_lineEdit->setText (QString(tr("%1")).arg (level));
        score_lineEdit->setText (QString(tr("%1")).arg (score));
    }
    else if(count > 10 && count <= 15)
    {
        level = 2;
        score = (count - 10) * 15 + 100 ;
        level_lineEdit->setText (QString(tr("%1")).arg (level));
        score_lineEdit->setText (QString(tr("%1")).arg (score));
    }
    else if(count > 15 && count <= 20)
    {
        level = 3;
        score = (count - 15) * 20 + 175 ;
        level_lineEdit->setText (QString(tr("%1")).arg (level));
        score_lineEdit->setText (QString(tr("%1")).arg (score));
    }
    else if(count > 20 && count <= 25)
    {
        level = 4;
        score = (count - 20) * 20 + 275 ;
        level_lineEdit->setText (QString(tr("%1")).arg (level));
        score_lineEdit->setText (QString(tr("%1")).arg (score));
    } /*静态成员函数,可以用::直接引用*/
    else if(QMessageBox::question (this, tr("提示"), tr("You are very good!"),
           QMessageBox::Yes) == QMessageBox::Yes)
    {
        this->close ();
        delete this;    //释放自己的资源
        return;         //结束这个函数
    }
}



你可能感兴趣的:(Qt5开发及实例)