用户登录
用户注册

分享至

QT实现贪吃蛇游戏

  • 作者: 充电5分钟_装B3小时
  • 来源: 51数据库
  • 2021-09-02

为了熟悉qt的相关知识,我用了大约8个小时的时间用qt再次写了一遍贪吃蛇。

因为qt的机制和平时写的程序流程不同,所以程序中可能没有遵守代码规范。

运行效果:

程序内除了实现贪吃蛇的基本功能外,还添加了记录得分、调节游戏速度、重新开始游戏等功能。

游戏内容使用qpainter类进行绘制。

编译环境:

windows qt 5.9.0 qt creator 4.3.0

思路:

数组存储蛇节点坐标的贪吃蛇游戏思路。

因为编写过程中使用了分文件编写,且qt框架的其他部分较多,这里仅展示程序实现主要代码。

代码:

mainwindow.h 主窗口类头文件

#ifndef widget_h
#define widget_h

#include <qwidget>
#include <qpainter>     //画家类
#include "snake.h"      //蛇类
#include <qkeyevent>    //键盘事件
#include "food.h"       //食物类
#include <qtimer>       //定时器类

namespace ui {
class widget;
}

class widget : public qwidget
{
    q_object

public:
    explicit widget(qwidget *parent = 0);
    ~widget();

    //绘图事件
    void paintevent(qpaintevent *);

    //游戏结束的情况
    void gameover();

private:
    ui::widget *ui;

    snake snake;        //蛇对象
    char key = 'd';     //接收键值,初始向右
    food food;          //食物对象
    //创建定时器
    qtimer *timer = new qtimer(this);
    bool gameflag = false;//游戏结束标记
    int score = 0;      //记录得分
    int timerspeed = 200; //定时器速度
    bool bugflag = false; //用于解决操控过快导致撞死自己的bug的标志

    //键盘事件,改变键值
    void keypressevent(qkeyevent *ev);
};

#endif // widget_h

mainwindow.cpp函数实现

#include "mainwindow.h"
#include "ui_widget.h"
#include <qlabel>
#include <qpushbutton>

//主窗口构造函数
widget::widget(qwidget *parent) : qwidget(parent), ui(new ui::widget)
{
    ui->setupui(this);      //初始化出.ui界面

    //一个格子宽高25像素,地图宽高600像素,每行有24个格子

    //设置固定窗口大小
    setfixedsize(1000,600);

    //设置得分标签控件的属性
    ui->label->setfont(qfont("黑体", 20, qfont::bold, false));

    //设置游戏速度标签内容
    ui->label_2->setfont(qfont("楷体", 16, qfont::bold, false));
    ui->label_2->settext("游戏速度:");

    //滑动条控件,这里将数值按一定比例放大缩小
    ui->horizontalslider->setvalue(200 >> 2);

    //监听滑动条控件滑动时,改变定时器速度为滑动条的值
    connect(ui->horizontalslider,qslider::valuechanged,[=]()
    {
        timerspeed = ui->horizontalslider->value() << 2;
    });

    //设置重新开始按钮属性和内容
    ui->pushbutton_3->setfont(qfont("黑体",12));
    ui->pushbutton_3->settext("重新开始");

    //监听重新开始按钮
    connect(ui->pushbutton_3,qpushbutton::clicked,[=]()
    {
        snake.reset();      //重置蛇
        score = 0;          //得分清0
        key = 'd';          //key值向右
        timerspeed = 200 << 2;//重置游戏速度
        timer->start(timerspeed);//重置定时器
        ui->horizontalslider->setvalue(200 >> 2);//重置滑动条
        gameflag = false;   //重置游戏结束标志
    });

    //开启定时器
    timer->start(timerspeed);

    //监听定时器的信号,执行表达式内容
    connect(timer,&qtimer::timeout,[=]()
    {
        timer->start(timerspeed); //调整定时器的速度

        snake.move(key);    //蛇移动函数

        //吃到食物的情况
        (food.getfoodx() == snake.snakevec.at(0).x && food.getfoody() == snake.snakevec.at(0).y) ?
        score++, food.randfood():    //得分+1,随机产生一个食物坐标
        snake.snakevec.pop_back();   //删除蛇尾

        gameover();    //游戏失败的情况

        update();      //调用绘图函数

        //更新标签控件的文本内容
        ui->label->settext(qstring("得分:%1").arg(score));
    });
}

//游戏失败情况
void widget::gameover()
{
    //撞墙失败
    if(snake.snakevec.at(0).x >= 24 * 25 || snake.snakevec.at(0).x < 0 ||
       snake.snakevec.at(0).y < 0 || snake.snakevec.at(0).y >= 24 * 25)
    {
        gameflag = true;
        timer->stop();      //暂停定时器
        return;
    }

    //撞自己失败
    for(int i = 1; i < snake.snakevec.size(); i++)
    {
        if(snake.snakevec.at(0).x == snake.snakevec.at(i).x &&
           snake.snakevec.at(0).y == snake.snakevec.at(i).y)
            gameflag = true, timer->stop();
    }
}


//绘图事件
void widget::paintevent(qpaintevent *)
{
    //创建画家对象,指定绘图设备为this主窗口
    qpainter painter(this);

    //设置画刷为红色
    qbrush brush1(qt::red);
    //让画家使用画刷
    painter.setbrush(brush1);
    //画食物
    painter.drawrect(qrect(food.getfoodx(),food.getfoody(),25,25));

    //设置画刷为黑色
    qbrush brush2(qt::blue);
    painter.setbrush(brush2);

    //遍历蛇坐标容器,画出代表蛇身的矩形
    for(auto snakenodei : snake.snakevec)
        //蛇头画圆形
        (snakenodei.x == snake.snakevec.at(0).x &&
         snakenodei.y == snake.snakevec.at(0).y) ?
        //蛇头画圆形
        painter.setrenderhint(qpainter::antialiasing),  //用抗锯齿画圆
        painter.drawellipse(qpoint(snakenodei.x + 12,snakenodei.y + 12),12,12):
        //蛇身画矩形
        painter.drawrect(qrect(snakenodei.x,snakenodei.y,25,25));

    bugflag = false;    //在画出蛇之后将标志设为假

    //设置画刷为黑色
    qbrush brush3(qcolor(128, 64, 0));
    painter.setbrush(brush3);

    //画出墙壁
    for(int i = 0; i < 24; i++)
          painter.drawrect(qrect(25 * 25, i * 25, 25, 25));

    //游戏结束时的绘图
    if(gameflag)
    {   //设置文字属性
        qfont font("楷体", 80, qfont::bold, false);
        painter.setfont(font);      //使用字体
        painter.drawtext(qrect(240, 200, 1000, 500), "游戏结束");   //画出游戏结束文字
    }
}

//键盘事件,改变贪吃蛇移动方向
void widget::keypressevent(qkeyevent *ev)
{
    if(bugflag)     //bug标志为真直接返回
        return;

    switch (ev->key())
    {
    case qt::key_w:
        if(key == 's') break;   //按下与当前方向相反按键时break
        key = 'w';
        bugflag = true; break;        //按键之后将标志设为真
    case qt::key_s:
        if(key == 'w') break;
        key = 's';
        bugflag = true; break;
    case qt::key_a:
        if(key == 'd') break;
        key = 'a';
        bugflag = true; break;
    case qt::key_d:
        if(key == 'a') break;
        key = 'd';
        bugflag = true; break;
    case qt::key_space:     //空格键暂停,这里有点问题
        timer->stop(); break;
    default:                //其他键重启定时器
        timer->start(timerspeed);
    }
}

//析构
widget::~widget()
{
    delete ui;
}

snake.h 蛇类头文件

#ifndef snake_h
#define snake_h

#include <qwidget>
#include <qvector>      //qt动态数组类

class snake : public qwidget
{
    q_object
private:
    //蛇坐标结构
    struct  snakecoor
    {
        int x;
        int y;
    };

public:
    explicit snake(qwidget *parent = nullptr);

    //蛇坐标容器
    qvector<snakecoor> snakevec;

    //蛇移动主要函数
    void move(char key);

    //根据key值确定蛇的移动方向
    void detedirmove(char key, snakecoor &nexthead);

    //重置蛇
    void reset();

signals:

public slots:
};

#endif // snake_h

snake.cpp 蛇类函数实现

#include "snake.h"

//构造函数初始化一条蛇
snake::snake(qwidget *parent) : qwidget(parent)
{
    snakecoor snakenode;            //临时结构变量用于创建蛇
    for (int i = 5; i >= 0; i--) //从右向左创建5节蛇身,容器的第一个元素为蛇头
    {
        snakenode.x = 25 * 8 + i * 25;//每个格子宽25像素
        snakenode.y = 25 * 8;
        snakevec.push_back(snakenode);//将蛇节点插入到数组中
    }
}

//确定蛇的移动方向,确定新蛇头的坐标位置
inline void snake::detedirmove(char key, snakecoor &nexthead)
{
    switch (key)
    {
    case 'w':
        //新蛇头坐标根据旧蛇头坐标改变
        nexthead.x = snakevec.front().x;
        nexthead.y = snakevec.front().y - 25;
        break;
    case 's':
        nexthead.x = snakevec.front().x;
        nexthead.y = snakevec.front().y + 25;
        break;
    case 'a':
        nexthead.x = snakevec.front().x - 25;
        nexthead.y = snakevec.front().y;
        break;
    case 'd':
        nexthead.x = snakevec.front().x + 25;
        nexthead.y = snakevec.front().y;
    }
}

//蛇移动主要函数
void snake::move(char key)
{
    snakecoor nexthead;  //创建一个新的蛇头

    detedirmove(key, nexthead);  //确定新蛇头的位置

    snakevec.insert(snakevec.begin(), nexthead);    //将新蛇头插入到容器头部
}

//重置蛇函数
void snake::reset()
{
    snakevec.clear();   //清空容器

    //初始化蛇
    snakecoor snakenode;
    for (int i = 5; i >= 0; i--)
    {
        snakenode.x = 25 * 8 + i * 25;
        snakenode.y = 25 * 8;
        snakevec.push_back(snakenode);
    }
}

food.h 食物类头文件

#ifndef food_h
#define food_h

#include <qwidget>

class food : public qwidget
{
    q_object
public :
    int food_x = 0;     //食物坐标
    int food_y = 0;

public:
    explicit food(qwidget *parent = nullptr);

    void randfood();    //随机产生食物坐标
    int getfoodx();     //返回食物坐标
    int getfoody();

signals:

public slots:
};

#endif // food_h

food.cpp 食物类函数实现

#include "food.h"
#include <ctime>

food::food(qwidget *parent) : qwidget(parent)
{
    randfood();     //创建对象时产生就一个随机坐标

}

//随机产生食物坐标
void food::randfood()
{
    srand((unsigned)time(null));
    food_x = (rand() % 24) * 25;
    food_y = (rand() % 24 )* 25;
}

//获取食物的坐标
int food::getfoodx()
{
    return food_x;
}

int food::getfoody()
{
    return food_y;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

软件
前端设计
程序设计
Java相关