QT实现贪吃蛇

QT上实现贪吃蛇

设备描述

  1. Linux操作系统
  2. QT5.5.1

关键点分析

  1. 贪吃蛇的身体用什么形式展现
  2. 当方向改变时,蛇身如何实现转向前进
  3. 如何记录蛇身的每一个坐标
  4. 如何判断游戏结束

实现步骤

  1. 首先有两种办法实现,第一:用QPushButton按键类,每个一个按键就是蛇的一部分身体,另外:用QPaintEvent绘图事件画出蛇的身体,个人认为用QPushButton实现比较简单粗暴,表面上看起来效果都一样。效果展示图

  2. 之前在想这个问题的时候很头痛,进入了一个误区,一直在想蛇头可以根据转向而立刻改变,但是蛇尾该如何慢慢转变过去呢,蛇身每转一次就有一个转折点,后面的蛇身都需要根据这个转折点来转向,心想还需要记录每一个转折点地址。但是后面发现根本就没用这么复杂,只需要将蛇身的每一个点根据上一个点的坐标走,第一个蛇身点根据蛇头走就可以了。

  3. 由于我的蛇身每一个节点都是一个QPushButton对象,而这个类有一个获取坐标的函数geometry();和设置控件坐标的函数setGeometry();这样我们只需要用一个指针数组记录下每一个QPushButton的地址,通过遍历数组的方式就可知道每一个蛇身节点的地址

QPushButton *dot1 = new QPushButton;
Snake_buff[buff_ip++] = (unsigned int *)dot1;

  1. 游戏结束有两种情况,第一:当蛇头碰到活动边界时,游戏结束。第二:当蛇头碰到蛇身体时,游戏结束。这里就要注意用全局变量存放活动边界的坐标。

代码讲解

main.h文件

#include <QMainWindow>
#include <QPushButton>
#include <QTimer>
#include <QPaintEvent>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    virtual void paintEvent(QPaintEvent*);
    void over();
    void SnakeInit();
public slots:
    void onButStart();
    void onButUp();
    void onButDown();
    void onButLift();
    void onButRight();
    void onTimer();
private:
    Ui::MainWindow *ui;
    QPushButton* dot;               //蛇头
    QPushButton* new_dot;           //食物
    QTimer* timerId;                //定时器
    int direction;                  //行驶方向
    unsigned int* Snake_buff[100];  //蛇身
    int buff_ip;                    //蛇身长度,同时也是游戏得分体现
    int Snake_food[3];              //食物坐标,状态
};

复写void paintEvent(QPaintEvent*)绘图函数,画四条边线。头文件
#include"QPaintEvent"

void MainWindow::paintEvent(QPaintEvent *)
{
    // 画一条直线
        QPainter* painter = new QPainter(this);             // 创建QPainter一个对象
        QPen pen;
        pen.setColor(Qt::black);           // 设置画笔为黑色
        painter->setPen(pen);                // 设置画笔
        painter->drawLine(line_lift,line_up,line_right,line_up);
        painter->drawLine(line_lift,line_down,line_right,line_down);
        painter->drawLine(line_lift,line_up,line_lift,line_down);
        painter->drawLine(line_right,line_up,line_right,line_down);
}

main.cpp主函数
主要实现功能:初始化界面,初始化定时器,链接信号与槽

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setWindowIcon(QIcon(":/new/prefix1/icon/dot_head.png"));
    setWindowTitle("贪吃蛇");
    timerId = new QTimer(this);
    connect(timerId,SIGNAL(timeout()),this,SLOT(onTimer()));
    ui->start->setStyleSheet(
    "border-image: url(:/new/prefix1/icon/dot_green.png);font: 28pt Sans;");
    ui->start->setText("开始");
    dot = NULL;
    new_dot = NULL;
    connect(ui->start,SIGNAL(clicked(bool)),this,SLOT(onButStart()));
    connect(ui->lift,SIGNAL(clicked(bool)),this,SLOT(onButLift()));
    connect(ui->right,SIGNAL(clicked(bool)),this,SLOT(onButRight()));
    connect(ui->up,SIGNAL(clicked(bool)),this,SLOT(onButUp()));
    connect(ui->down,SIGNAL(clicked(bool)),this,SLOT(onButDown()));
    }

main.cpp定时器函数
主要实现功能:蛇的运动过程,判断是否吃到食物,判断是否游戏结束

void MainWindow::onTimer()
{
    int x = dot->geometry().x();                //获取蛇头坐标
    int y = dot->geometry().y();
    if(x==Snake_food[0] && y==Snake_food[1])        //判断蛇头与食物坐标是否相同,相同表示吃到食物
    {
        QPushButton *dot1 = new QPushButton;        //创
        Snake_buff[buff_ip++] = (unsigned int *)dot1;//将新的节点存入数组
        dot1->setEnabled(0);                        //设置按钮为不可点击状态
        dot1->setParent(this);                      //设置新建按钮显示在当前界面
        dot1->setStyleSheet("border-image: url(:/new/prefix1/icon/dot_green.png);");
        QPushButton* dot2 = (QPushButton*)Snake_buff[buff_ip-1];
        int x1 = dot2->geometry().x();              //获取当前蛇身的最后一个节点
        int y1 = dot2->geometry().y();
        dot1->setGeometry(x1,y1,dot_size,dot_size);  //将新节点加入蛇身末尾
        dot1->show();                               //显示出该节点
        Snake_food[2] = 1;                          //食物已被吃标志
    }
    switch (direction) {                            //判断当前行驶方向
    case 1:
        if(y>=line_up)
            dot->setGeometry(x,y-dot_size,dot_size,dot_size);//改变蛇头坐标
        //当向左或右行驶时,下一个方向只能是上,或着下
        //当向上或下行驶时,下一个方向只能是左,或者右
        ui->up->setEnabled(0);
        ui->down->setEnabled(0);                    //设置按钮状态为不可点击
        ui->lift->setEnabled(1);                    //设置按钮状态为可以点击
        ui->right->setEnabled(1);
        break;
    case 2:
        if(y<=line_down)
            dot->setGeometry(x,y+dot_size,dot_size,dot_size);
        ui->up->setEnabled(0);
        ui->down->setEnabled(0);
        ui->lift->setEnabled(1);
        ui->right->setEnabled(1);
        break;
    case 3:
        if(x>=line_lift)
            dot->setGeometry(x-dot_size,y,dot_size,dot_size);
        ui->up->setEnabled(1);
        ui->down->setEnabled(1);
        ui->lift->setEnabled(0);
        ui->right->setEnabled(0);
        break;
    case 4:
        if(x<=line_right)
            dot->setGeometry(x+dot_size,y,dot_size,dot_size);
        ui->up->setEnabled(1);
        ui->down->setEnabled(1);
        ui->lift->setEnabled(0);
        ui->right->setEnabled(0);
        break;
    default:
        break;
    }
    if(buff_ip)              //当蛇身长度大于等于一时,将蛇身的后一个节点等于前一个节点的坐标
    {
        for(int i=buff_ip-1;i>0;i--)    //遍历蛇身所有节点
        {
            QPushButton* dot1 = (QPushButton*)Snake_buff[i];
            QPushButton* dot2 = (QPushButton*)Snake_buff[i-1];
            int x1 = dot2->geometry().x();
            int y1 = dot2->geometry().y();
            dot1->setGeometry(x1,y1,dot_size,dot_size);
        }
        QPushButton* dot1 = (QPushButton*)Snake_buff[0];
        dot1->setGeometry(x,y,dot_size,dot_size);
    }
    //当贪吃蛇碰到边界时,游戏结束
    if(y<line_up || y>=line_down || x<line_lift || x>=line_right)
        over();
     //当贪吃蛇碰到自己尾巴时,游戏结束
    for(int i=2;i<buff_ip;i++)
    {
        QPushButton* dot2 = (QPushButton*)Snake_buff[i];
        if(x==dot2->geometry().x() && y==dot2->geometry().y())
            over();
    }
    if(Snake_food[2])           //当食物被吃掉时,创建下一个食物坐标
    {
        qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));//生成随机数
        int new_x = qrand()%1000/56*20+line_lift;
        qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
        int new_y = qrand()%100/8*20+line_up;
        Snake_food[0] = new_x;                          //记录下食物的坐标
        Snake_food[1] = new_y;
        new_dot->setGeometry(new_x,new_y,dot_size,dot_size);
        new_dot->show();
        Snake_food[2] = 0;                              //设置食物未被吃掉标志
    }
    ui->label->setText(QString::number(buff_ip));        //显示当前游戏得分
    //设置蛇行驶速度,得分越高,速度越快
    if(buff_ip==5)
        timerId->setInterval(300);
    else if(buff_ip==10)
        timerId->setInterval(250);
    else if(buff_ip==20)
        timerId->setInterval(200);
    else if(buff_ip==50)
        timerId->setInterval(150);
}

项目的工程文件在我的资源文件里面,大家感兴趣的可以去下载。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值