QT实现简单的贪吃蛇小游戏

本文介绍如何使用Qt创建一个简单的贪吃蛇游戏。通过利用QWidget及其相关绘图事件,实现了游戏的基本逻辑与界面交互。文章详细展示了从项目搭建到功能实现的全过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、新建一个Qt项目

新建Qt Widgets Application,项目名称为HappySnake,基类选择QWidget,类名默认

二、添加要用到的头文件

#include <QKeyEvent>
#include <QRectF>
#include <QPainter>
#include <QPen>
#include <QBrush>
#include <QDebug>
#include <QTimer>
#include <QTime>

三、写类声明信息

  • 贪吃蛇的本体使用小方框来代替
  • 使用QList类来保存贪吃蛇的本体
  • 使用定时器来设定刷新的时间
  • 使用随机函数生成奖励的节点
  • 使用paintEvent来进行绘图
  • keyPressEvent来监测按键的按下,控制贪吃蛇的移动
class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
protected:
    void paintEvent(QPaintEvent *);
    void keyPressEvent(QKeyEvent *);

private:
    void addTopRectF();
    void addDownRectF();
    void addLeftRectF();
    void addRightRectF();
    void deleteLastRectF();
    bool snakeStrike();
    enum Move{Left,Right,Up,Down};
protected slots:
    void timeOut();
    void rewardTimeOut();

private:
    Ui::Widget *ui;
    QList<QRectF> snake;//贪吃蛇本体
    int snakeNodeWidth = 10;
    int snakeNodeHeight = 10;
    QTimer *timer;
    QTimer *rewardTimer;
    int time = 100;
    int moveFlage = Up;
    bool gameOver = false;
    bool gameStart = false;
    QList<QRectF> rewardNode;//奖励节点

};

四、对类函数的实现

  • 构造函数

    Widget::Widget(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::Widget)
    {
        ui->setupUi(this);
        resize(480,500);
        //设置窗体背景色为黑色
        setStyleSheet("QWidget{background:black}");
        setWindowOpacity(0.8);//设置窗口的透明度
    
        snake.append(QRectF(200,500,snakeNodeWidth,snakeNodeHeight));
        addTopRectF();
        addTopRectF();
        //首先生成一个奖励节点
        rewardNode.append(QRectF(100,100,snakeNodeWidth,snakeNodeWidth));
    
        timer = new QTimer;
        connect(timer, SIGNAL(timeout()),this,SLOT(timeOut()));
        //timer->start(time);
    
        rewardTimer = new QTimer;
        connect(rewardTimer,SIGNAL(timeout()),this,SLOT(rewardTimeOut()));
        //rewardTimer->start(time*30);
    }
    
    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(snake.at(0).contains(rewardNode.at(i).x()+rewardNode.at(i).width()/2,rewardNode.at(i).y()+rewardNode.at(i).height()/2)){
                if(rewardNode.at(i).width()>snakeNodeWidth){//额外奖励
                    flage += 2;
                }
                flage++;//正常奖励
                rewardNode.removeAt(i);
                break;
            }
        }
        while(flage--){
            switch (moveFlage) {
            case Up:
                addTopRectF();
                break;
            case Down:
                addDownRectF();
                break;
            case Right:
                addRightRectF();
                break;
            case Left:
                addLeftRectF();
                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::addTopRectF()
    {
        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::addDownRectF()
    {
        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::addLeftRectF()
    {
        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::addRightRectF()
    {
        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::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::black);
        brush.setColor(Qt::green);
        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(moveFlage != Down){
                moveFlage = Up;
            }
            break;
        case Qt::Key_Down:
            if(moveFlage != Up){
                moveFlage = Down;
            }
            break;
        case Qt::Key_Right:
            if(moveFlage != Left){
                moveFlage = Right;
            }
            break;
        case Qt::Key_Left:
            if(moveFlage != Right){
                moveFlage = Left;
            }
            break;
        case Qt::Key_Enter:
        case Qt::Key_Return:
            if(gameOver){
                snake.clear();
                rewardNode.clear();
                moveFlage = Up;
                snake.append(QRectF(200,500,snakeNodeWidth,snakeNodeHeight));
                addTopRectF();
                addTopRectF();
                //首先生成一个奖励节点
                rewardNode.append(QRectF(100,100,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;
    
    }
    

    五、结束

实现的效果:

提供源码在博客的资源中,Qt5.6版本正常运行。

点击下载源码

 

总结:

只是简单的使用了paintevent进行绘图,基本都是简单的对Qt的一些常用类的使用,对面向对象的编程应用的不是很好,更偏向于面向过程,所以完全可以改成C语言在Linux下实现,思路都是相同的。

### Qt 贪吃蛇游戏开发教程与示例代码 开发一个贪吃蛇游戏是学习 Qt 的一个很好的实践项目。以下是一个完整的开发教程和示例代码,涵盖了从界面设计到功能实现的各个方面。 #### 1. 游戏界面设计 游戏界面包含一个 400x400 像素的游戏区域,背景为黑色,蛇的身体为绿色,食物为红色。使用 `QPainter` 绘制这些元素。 ```python import sys from PyQt5.QtWidgets import QApplication, QWidget from PyQt5.QtCore import QTimer, Qt from PyQt5.QtGui import QPainter, QColor class SnakeGame(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setWindowTitle('贪吃蛇游戏') self.setGeometry(300, 300, 400, 400) self.timer = QTimer(self) self.timer.timeout.connect(self.update) # 定时更新界面 self.timer.start(100) # 每100毫秒更新一次 self.snake = [(200, 200)] # 蛇的初始位置 self.food = (100, 100) # 食物的初始位置 self.direction = 'right' # 初始方向 def paintEvent(self, event): painter = QPainter() painter.begin(self) self.drawSnake(painter) self.drawFood(painter) painter.end() def drawSnake(self, painter): painter.setBrush(QColor(0, 255, 0)) # 绿色 for pos in self.snake: painter.drawRect(pos[0], pos[1], 10, 10) def drawFood(self, painter): painter.setBrush(QColor(255, 0, 0)) # 红色 painter.drawRect(self.food[0], self.food[1], 10, 10) def keyPressEvent(self, event): if event.key() == Qt.Key_Up and self.direction != 'down': self.direction = 'up' elif event.key() == Qt.Key_Down and self.direction != 'up': self.direction = 'down' elif event.key() == Qt.Key_Left and self.direction != 'right': self.direction = 'left' elif event.key() == Qt.Key_Right and self.direction != 'left': self.direction = 'right' def update(self): head = self.snake[0] if self.direction == 'up': new_head = (head[0], head[1] - 10) elif self.direction == 'down': new_head = (head[0], head[1] + 10) elif self.direction == 'left': new_head = (head[0] - 10, head[1]) elif self.direction == 'right': new_head = (head[0] + 10, head[1]) self.snake.insert(0, new_head) if new_head == self.food: # 吃到食物 self.food = (new_head[0] + 10, new_head[1]) # 随机生成新食物 else: self.snake.pop() # 移除尾部 self.checkCollision() # 检测碰撞 def checkCollision(self): head = self.snake[0] if head[0] < 0 or head[0] >= 400 or head[1] < 0 or head[1] >= 400: # 撞墙 print("Game Over") self.close() if head in self.snake[1:]: # 撞到自己 print("Game Over") self.close() if __name__ == '__main__': app = QApplication(sys.argv) ex = SnakeGame() ex.show() sys.exit(app.exec_()) ``` #### 2. 功能实现 - **蛇的移动**:通过键盘事件捕获方向键输入,并根据当前方向更新蛇的位置。 - **食物生成**:当蛇吃到食物后,食物会随机生成在新的位置。 - **碰撞检测**:检测蛇是否撞到墙壁或自己的身体,如果是,则结束游戏[^1]。 - **暂停与重新开始**:可以通过添加额外的按键事件来实现暂停和重新开始的功能[^3]。 #### 3. 游戏模式扩展 可以实现以下三种游戏模式: - **正常模式**:蛇撞到墙壁或自己即游戏结束。 - **死亡模式**:蛇可以穿越墙壁,但撞到自己的排泄物会结束游戏。 - **情侣模式**:支持两名玩家共同游戏,通过不同的按键控制蛇的移动和攻击[^3]。 #### 4. 音效与背景音乐 可以使用 Qt 的多媒体模块 `QMediaPlayer` 添加音效和背景音乐,增强游戏体验[^2]。 --- ###
评论 41
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值