广告位联系
返回顶部
分享到

QT实现贪吃蛇游戏

C语言 来源:转载 作者:秩名 发布时间:2021-05-17 18:45:22 人浏览
摘要

因为QT的机制和平时写的程序流程不同,所以程序中可能没有遵守代码规范。 运行效果: 程序内除了实现贪吃蛇的基本功能外,还添加了记录得分、调节游戏速度、重新开始游戏等功能。 游戏内容使用QPainter类进行绘制。 编译环境: Windows Qt 5.9.0 Qt Creator

因为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;
}


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://blog.csdn.net/qq_46239972/article/details/105846248
相关文章
  • C++中类的六大默认成员函数的介绍

    C++中类的六大默认成员函数的介绍
    一、类的默认成员函数 二、构造函数Date(形参列表) 构造函数主要完成初始化对象,相当于C语言阶段写的Init函数。 默认构造函数:无参的构
  • C/C++实现遍历文件夹最全方法总结介绍

    C/C++实现遍历文件夹最全方法总结介绍
    一、filesystem(推荐) 在c++17中,引入了文件系统,使用起来非常方便 在VS中,可以直接在项目属性中调整: 只要是C++17即以上都可 然后头文件
  • C语言实现手写Map(数组+链表+红黑树)的代码

    C语言实现手写Map(数组+链表+红黑树)的代码
    要求 需要准备数组集合(List) 数据结构 需要准备单向链表(Linked) 数据结构 需要准备红黑树(Rbtree)数据结构 需要准备红黑树和链表适配策略
  • MySQL系列教程之使用C语言来连接数据库

    MySQL系列教程之使用C语言来连接数据库
    写在前面 知道了 Java中使用 JDBC编程 来连接数据库了,但是使用 C语言 来连接数据库却总是连接不上去~ 立即安排一波使用 C语言连接 MySQL数
  • 基于C语言实现简单学生成绩管理系统

    基于C语言实现简单学生成绩管理系统
    一、系统主要功能 1、密码登录 2、输入数据 3、查询成绩 4、修改成绩 5、输出所有学生成绩 6、退出系统 二、代码实现 1 2 3 4 5 6 7 8 9 10 11
  • C语言实现共享单车管理系统

    C语言实现共享单车管理系统
    1.功能模块图; 2.各个模块详细的功能描述。 1.登陆:登陆分为用户登陆,管理员登陆以及维修员登录,登陆后不同的用户所执行的操作
  • C++继承与菱形继承的介绍

    C++继承与菱形继承的介绍
    继承的概念和定义 继承机制是面向对象程序设计的一种实现代码复用的重要手段,它允许程序员在保持原有类特性的基础上进行拓展,增加
  • C/C++指针介绍与使用介绍

    C/C++指针介绍与使用介绍
    什么是指针 C/C++语言拥有在程序运行时获得变量的地址和操作地址的能力,这种用来操作地址的特殊类型变量被称作指针。 翻译翻译什么
  • C++进程的创建和进程ID标识介绍
    进程的ID 进程的ID,可称为PID。它是进程的唯一标识,类似于我们的身份证号是唯一标识,因为名字可能会和其他人相同,生日可能会与其他
  • C++分析如何用虚析构与纯虚析构处理内存泄漏

    C++分析如何用虚析构与纯虚析构处理内存泄漏
    一、问题引入 使用多态时,如果有一些子类的成员开辟在堆区,那么在父类执行完毕释放后,没有办法去释放子类的内存,这样会导致内存
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计