Qt超简单实现贪吃蛇

这篇具有很好参考价值的文章主要介绍了Qt超简单实现贪吃蛇。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

为了能够最简单地完成程序,所以没有用类的继承等知识。感兴趣的朋友可以改写一下。

常量

const int FILE_SIZE = 30; //地图方格大小
const int FPS = 5000 / 33; //游戏运行帧率
enum Item{empty, wall, food, snake}; //方格的类型
//地图大小
const int mapWidth = 20;
const int mapHeight = 20;

Snake类

为了存储一条蛇, 我们需要的变量有:

  • 蛇的头坐标
  • 蛇的尾巴, 用一个链表存储
  • 蛇的移动方向

下面是Snake类的定义:

class Snake
{
public:
    Snake(QObject* parent, iItem ** _map, int x, int y);
    
    void setDirection(const int x, const int y);
    void move();
    void grow();
    bool eatSelf();
    int length()const{return tail.size();}
    QPoint getPos()const{return head;}

private:
    bool isMoving();
    QPoint head;
    QList<QPoint> tail;

    int moveX = 0;
    int moveY = 0;

    iItem **map;
};

贪吃蛇中的唯一难点, 就是蛇移动的逻辑了. 蛇移动不必更新身体每一个点的位置. 相反, 只要移动头, 并把头原来的位置加入身子, 并且去掉身体的最后就可以了.

函数的实现:

Snake::Snake(QObject *parent, iItem **_map, int x, int y) : Item(parent), map(_map)
{
    head = QPoint(x, y);
    map[x][y] = snake;
}

void Snake::setDirection(const int x, const int y)
{
    moveX = x;
    moveY = y;
}

void Snake::move()
{
    if(!isMoving()) return;
    QPoint newHead = head;
    //更新head的位置
    newHead.setX((newHead.x() + moveX) % mapWidth);
    newHead.setY((newHead.y() + moveY) % mapHeight);
    if(!tail.empty()){
	    //如果有尾巴的话, 将原来head作为tail的头
        tail.push_front(head);
        //剁掉尾巴的最后
        QPoint t = tail.back();
        map[t.x()][t.y()] = empty;
        tail.pop_back();
    }
    else{
	    //没有尾巴, 则把原来的地图位置置空
        map[head.x()][head.y()] = empty;
    }

    head = newHead; //更新head
    map[head.x()][head.y()] = snake; //更新地图
}

bool Snake::isMoving()
{
    return moveX != 0 || moveY != 0;
}

bool Snake::eatSelf()
{
	// 如果tail链表中包含与head坐标一样的点, 说明蛇头撞到身子了
	// contains是QList类内置的函数
    return tail.contains(head);
}

void Snake::grow() //变长
{
    QPoint t = head;
    //尾巴变长的方向和移动方向相反
    t.setX((t.x() - moveX) % mapWidth);
    t.setY((t.y() - moveY) % mapHeight);
    tail.append(t);
    map[t.x()][t.y()] = snake;
}

GameController类

class GameController : public QObject
{
    Q_OBJECT
public:
    Item** map; 
    GameController(QObject *parent);
    ~GameController();

protected:
	//这个函数由于把QMainWindow收到的键盘事件在handlerKeyPressed里处理
    virtual bool eventFilter(QObject *watched, QEvent *event) override;
    void handleKeyPressed(QKeyEvent* event);

private:
    QTimer timer;
    bool paused = false; //游戏暂停
    Snake *snake;
    QPoint foodPos;
    
    void checkCollision();
    bool snakeEatFood();
    void snakeEatSelf();
    void snakeHitWall();

    void addFood();

    void initMap(); //初始化地图

signals:
    void updateView(); //通知更新显示
    void over(); //通知游戏终止

public slots:
    void updateGame(); //更新游戏状态
    void gameover(); //游戏结束
    void stop(); //游戏暂停
    void resume(); //游戏恢复进行
    void newGame(); //再开一局
};
void GameController::initMap()
{
    for(int i = 0; i < mapWidth; ++i){
        for(int j = 0; j < mapHeight; ++j){
            map[i][j] = empty;
        }
    }
}

GameController::GameController(QObject *parent) : QObject(parent)
{
	//创建动态数组
    map = new Item*[mapWidth];
    for(int i = 0; i < mapWidth; ++i){
        map[i] = new iItem[mapHeight];
    }

    initMap(); //初始化地图

	//连接信号
    connect(&timer, &QTimer::timeout, this, &GameController::updateGame);
    timer.start(FPS); //开始计时

	//蛇初始化到地图中央
    snake = new Snake(this, map, mapWidth/2, mapHeight/2);
    addFood(); //生成食物
}

GameController::~GameController()
{
    for(int i = 0; i < mapWidth; ++i){
        delete []map[i];
    }

    delete []map;
    delete snake;
}

bool GameController::eventFilter(QObject *watched, QEvent *event)
{
    if (event->type() == QEvent::KeyPress) {
        handleKeyPressed((QKeyEvent *)event); //自定义的按键处理函数
        return true; //返回已处理
    } else {
        return QObject::eventFilter(watched, event); //不处理
        }
}

void GameController::handleKeyPressed(QKeyEvent *event)
{
    if(paused){ 
        if(event->key() == Qt::Key_Space){
            resume();
        }
        return;
    }

	//设置方向
    if(event->key() == Qt::Key_Up){
        snake->setDirection(0, -1);
    }
    else if(event->key() == Qt::Key_Down){
        snake->setDirection(0, 1);
    }
    else if(event->key() == Qt::Key_Left){
        snake->setDirection(-1, 0);
    }
    else if(event->key() == Qt::Key_Right){
        snake->setDirection(1, 0);
    }
    else if(event->key() == Qt::Key_Space){
        stop();
    }
}

void GameController::updateGame()
{
    snake->move(); //蛇移动
    checkCollision(); //检查碰撞
    emit updateView(); //更新显示
}

void GameController::checkCollision()
{
    if(snake->eatSelf()){ // head撞到身体
        gameover();
    }

    if(snakeEatFood()){ //吃食物
        addFood(); //生成下一个食物
        snake->grow(); //蛇生长
    }
}

void GameController::addFood()
{
    int n, x, y;
    do{ //随机在不是蛇的地方生成食物
        n = rand() % (mapWidth * mapHeight);
        y = n / mapWidth;
        x = n % mapWidth;
    }
    while(map[x][y] == snake);

    map[x][y] = food; //更新地图
    foodPos = QPoint(x, y); //存储食物的位置
}

void GameController::gameover()
{
    stop(); //游戏暂停
    emit over(); //更新UI
}

void GameController::stop()
{
    timer.stop();
    paused = true;
}

void GameController::resume()
{
    timer.start(FPS);
    paused = false;
}

void GameController::newGame()
{
    delete snake;
    initMap();
    snake = new Snake(this, map, mapWidth/2, mapHeight/2);
    addFood();
    resume();
}

bool GameController::snakeEatFood()
{
    return snake->getPos() == foodPos;
}

GUI显示

class MainWindow : public QMainWindow
{
    Q_OBJECT
  
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

protected:
    virtual void paintEvent(QPaintEvent* event); //绘制地图

private:
    GameController *game;

public slots:
    void showMessageBox(); //死亡时显示的提示框
    void updateView(); //更新游戏显示
};
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    setFixedSize(FILE_SIZE * mapWidth, FILE_SIZE * mapHeight); //设置窗口大小
    game = new GameController(this); //新开始游戏
    this->installEventFilter(game); //对收到的事件不接收,让game接收
	//信号连接
    connect(game, &GameController::updateView, this, &MainWindow::updateView);
    connect(game, &GameController::over, this, &MainWindow::showMessageBox);
}

MainWindow::~MainWindow()
{
    delete game;
}

void MainWindow::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);

	//画背景
    painter.fillRect(0, 0, mapWidth * FILE_SIZE, mapHeight * FILE_SIZE, Qt::gray);

	//画方格内的物体
	//蛇,食物,墙分别用不同颜色表示
    for(int i = 0; i < mapWidth; ++i){
        for(int j = 0; j < mapHeight; ++j){
            switch (game->map[i][j]) {
            case empty:
                break;
            case food:
                painter.fillRect(i * FILE_SIZE, j * FILE_SIZE, FILE_SIZE, FILE_SIZE, Qt::red);
                break;
            case snake:
                painter.fillRect(i * FILE_SIZE, j * FILE_SIZE, FILE_SIZE, FILE_SIZE, Qt::yellow);
                break;
            case wall:
                break;
            }
        }
    }
}

void MainWindow::showMessageBox()
{
    if (QMessageBox::Yes == QMessageBox::information(NULL,
                            tr("Game Over"), tr("Again?"),
                            QMessageBox::Yes | QMessageBox::No,
                            QMessageBox::Yes)) {
        game->newGame(); //如果选了Yes则重新开始
    }
    else{
        exit(0); //否则推出
    }
}

void MainWindow::updateView()
{
    update(); //更新, 会自动调用paintEvent函数
}

游戏简图

Qt超简单实现贪吃蛇,程序编程实战,qt,c++,游戏,GUI
Qt超简单实现贪吃蛇,程序编程实战,qt,c++,游戏,GUI文章来源地址https://www.toymoban.com/news/detail-797627.html

到了这里,关于Qt超简单实现贪吃蛇的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [Qt网络编程]之UDP通讯的简单编程实现

    hello!欢迎大家来到我的Qt学习系列之 网络编程之UDP通讯的简单编程实现。 希望这篇文章能对你有所帮助!!! 本篇文章的相关知识请看我的上篇文章: 目录 UDP通讯  基于主窗口的实现  基于线程的实现          UDP数据报协议是一个面向无连接的传输层报文协议 ,它简

    2024年04月25日
    浏览(59)
  • 通关大一编程实践,用C++基础和Qt实现FlappyBird小游戏

    目录 内容简介 项目要求 项目实现 素材导入 核心思路 思路的转变:从main到mainwindow 如何让游戏动起来 如何设计一个物体类 如何从键盘输入操作 如何绘制图片  如何初始化 项目源码 该项目实现了基于Qt的FlappyBird动画游戏开发,我会从素材导入开始带大家熟悉Qt开发的全过程

    2023年04月09日
    浏览(43)
  • 强化学习Agent系列(一)——PyGame游戏编程,Python 贪吃蛇制作实战教学

    大家好,未来的开发者们请上座 随着人工智能的发展,强化学习基本会再次来到人们眼前,遂想制作一下相关的教程。强化学习第一步基本离不开虚拟环境的搭建,下面用大家耳熟能详的贪吃蛇游戏为基础,制作一个Agent,完成对这个游戏的绝杀。 万里长城第一步:用pytho

    2024年01月21日
    浏览(65)
  • 十三、QPalette的简单使用(Qt5 GUI系列)

    目录 一、设计需求 二、实现代码 三、代码解析 四、总结         在实际应用中,经常需要改变某个控件的颜色外观,如背景、文字颜色等。Qt提供的调色板类 QPalette 专门用于管理对话框的外观显示。QPalette 类相当于对话框或是控件的调色板,它管理着控件或窗体的所有

    2024年01月17日
    浏览(55)
  • 十二、QProgressBar的简单使用与样式优化(Qt5 GUI系列)

    目录 一、设计需求 二、实现代码 三、代码解析 四、总结 五、扩展(自定义QProgressBar样式)         在很多应用程序中,在执行费时操作时都会展示一个进度条来展示操作进行的进度。常见的场景,如:拷贝操作、安装操作以及卸载操作。本例要求实现进度条简单使用,同

    2024年01月25日
    浏览(37)
  • MATLAB GUI游戏设计——贪吃蛇

    在MATLAB App Designer中创建一个新的App时,我们首先需要设计游戏的界面布局。贪吃蛇游戏通常需要一个网格来作为游戏空间,以及一些控制按钮和信息显示。以下是创建界面布局的步骤: 1. 创建20*20的网格 在这段代码中,我们首先创建一个面板( uipanel ),它将作为游戏网格

    2024年02月01日
    浏览(43)
  • Qt实现一个简单的应用程序——桌面助手

    1、实现不同功能之间的界面切换 2、可查看日历 3、可实现计时器功能 4、可实现计算器功能 5、ui界面及按钮部件背景的设置 6、为软件设置图标 7、程序打包成软件       1、创建工程         New Project - Application - Qt Widgets Application然后下一步,使用ui界面文件能省去很多步骤

    2024年02月08日
    浏览(69)
  • 学生学python编程---实现贪吃蛇小游戏+源码

    前言 这几年人工智能技术大发展,Python因此几乎成了第一位的语言。实际上,多年来,它不仅在软件工程师中得到广泛使用,也是各行业通用的专家语言,就是说,不管孩子以后做什么,都可能用得着。准备针对我自己上小学的孩子,每周抽出些时间,通过学习他们感兴趣的

    2023年04月09日
    浏览(44)
  • 使用Java实现一个简单的贪吃蛇小游戏

    基于java实现贪吃蛇小游戏,主要通过绘制不同的图片并以一定速度一帧一帧地在窗体上进行展示。 开发工具:eclipse java工具包:jdk1.8 代码地址:https://gitee.com/jay_musu/games-and-tools.git 创建一个新的项目,并命名。创建一个名为images的文件夹用来存放游戏相关图片。然后再在项

    2024年02月11日
    浏览(56)
  • c语言及数据结构实现简单贪吃蛇小游戏

    目录 一·贪吃蛇简单介绍: 二·贪吃蛇的实现的开始准备: 2.1:欢迎界面的实现: 2.2地图的绘制: 2.3.1初始化蛇: 2.3.2初始化食物:  三·贪吃蛇的运行操作: 3.1辅助信息的打印: 3.2蛇的下一步移动操作: 3.2.1判断玩家按键情况: 3.2.2下一步遇到食物: 3.2.3下一步不是食物:

    2024年04月27日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包