Qt制作贪吃蛇游戏

贪吃蛇想必大家都玩过~童年回忆~

那么我们如何制作一款属于自己的贪吃蛇小游戏呢?

今天给大家带来的是Qt制作贪吃蛇游戏(附源码)

变量和函数的声明,方便后续代码的理解

enum game_state //游戏的状态
{
    WAIT,
    START,
    PAUSE,
    OVER
};
    void food_create();//食物生成函数

    //蛇移动函数
    void move_up();
    void move_down();
    void move_left();
    void move_right();

    void Is_eat_food();//判断蛇是否吃到食物
    void Is_game_over();//判断是否结束游戏
    void update_message();//更新游戏信息

    QList food_x; //食物x轴坐标
    QList food_y; //食物y轴坐标
    QList snake_x;//蛇x轴坐标
    QList snake_y;//蛇y轴坐标
    int Width;//窗口的宽
    int Height;//窗口的高
    QList food_r = {6,7,8,9,10};//食物的半径
    QList snake_body_r = {6,7,8,9,10};//蛇身半径
    QList snake_head_r = {8,9,11,12,13};//蛇头半径
    int snake_body_num = 5;//初始蛇身数量
    int score = 0;//当前得分
    int level = 0;//控制食物和蛇身规模的变量
    int eat_food_collision_offset = 3*(snake_head_r.at(level) - food_r.at(level));//蛇吃食物碰撞检测的偏移量
    int snake_collision_body_offset = 3*(snake_head_r.at(level) - snake_body_r.at(level));
    int snake_collision_wall_offset = snake_head_r.at(level);
    int snake_collision_up_offset = snake_collision_wall_offset+snake_collision_wall_offset/4;
    char move_pos = 'U';//蛇移动的方向
    const int food_maxnum = 40;//食物的最大数量
    int Game_State = WAIT; //游戏状态
    QColor snake_head_color = Qt::gray; //蛇头颜色
    QColor snake_body_color = Qt::gray; //蛇身颜色
    QColor food_color = Qt::red;//食物颜色
    QString map = ":/new/prefix1/src/none.png"; //地图
    QTimer* food_create_timer;//食物生成定时器
    QTimer* painter_timer;//画家定时器

核心分析

该游戏的核心就是重写paintEvent()函数对主窗口不断的重绘,构建出动态的效果(食物不断随机生成,蛇的不断移动等等)

void paintEvent(QPaintEvent *event)override;

贪吃蛇游戏两个重要组成当然就是蛇和食物,我来分开分析

①食物生成

可以把每个食物理解为一个坐标,我们只要有一个坐标,就可以用QPainter画出我们想要的食物,为了方便管理这些食物,使用一个容器存储食物的坐标,并使用定时器不间断的生成随机坐标(当然随机坐标要限制范围,即要在窗口内,否则生成的坐标就没有意义了,反而还会增加计算量,导致程序效率下降),这里为了程序持久良好的运行,我限制了能够生成的食物的最大数量,否则如果一个玩家吃的不够快,食物蹭蹭蹭无限制的递增,程序效率会下降

void MainWindow::food_create()
{
    if(food_x.size()==food_maxnum) //如果食物数量超过40个,减少10个食物
    {
        for(int i = 0;i<10;i++)
        {
             food_x.removeFirst();
             food_y.removeLast();
        }
    }
    qsrand(food_r.at(level)+1);//设置随机数种子,qrand生成随机数的起始值
    int x = QRandomGenerator::global()->bounded(Width - 2*food_r.at(level));
    qsrand(food_r.at(level)+ui->menubar->height()+1);
    int y = QRandomGenerator::global()->bounded(Height - 2*food_r.at(level));
    food_x.append(x);
    food_y.append(y);
}

②蛇的移动

如果说一个食物是一个坐标的话,那么一条蛇就是一串连续的坐标,每个坐标都映射一个实体,一长串的看起来就像一条蛇一样了,同样蛇的坐标也是用容器存储起来方便维护,然后我们该如何控制蛇的移动呢?想想在电脑上玩贪吃蛇,是不是↑↓↔控制的,这里也一样,既然要按键,自然要用到Qt的键盘事件,重写keyPressEvent()函数,根据用户的按键来判断蛇该如何移动,然后像前面说的一样,蛇是一串连续的坐标,想让其看起来是整体移动的,想象一下,一个数组中有10个元素,1~10,现在我让你把这10个元素都后移一位,再后移一位,相较于开始,从结果来看,这10个元素是不是就移动2个位置,我们上帝视角看是不是就好像这10个元素“动起来了”,蛇的移动就是这个原理,就是蛇的坐标不断发生改变,然后QPainter不断重绘,给我们看起来就是蛇动起来了,那么蛇的坐标该怎么变呢?可以理解为当蛇向上移动时,蛇的x坐标不变,y坐标不断减小,向左移动时,x坐标不断减小,y坐标不变,右和下方向同理,这样只要定义一个方向的标志,来确定此时蛇的运动方向,不断改变蛇的坐标,用户的按键不断更新方向的标志,从而改变蛇的运动方向,QPainter不间断的重绘,就达到了按键控制蛇的移动

void MainWindow::move_up()
{
    //首部增加元素
    snake_x.push_front(snake_x.front());
    snake_y.push_front(snake_y.front() - 2*snake_body_r.at(level));
    //尾部删除元素
    snake_x.pop_back();
    snake_y.pop_back();
}

void MainWindow::move_down()
{
    //首部增加元素
    snake_x.push_front(snake_x.front());
    snake_y.push_front(snake_y.front() + 2*snake_body_r.at(level));
    //尾部删除元素
    snake_x.pop_back();
    snake_y.pop_back();
}

void MainWindow::move_left()
{
    //首部增加元素
    snake_x.push_front(snake_x.front() - 2*snake_body_r.at(level));
    snake_y.push_front(snake_y.front());
    //尾部删除元素
    snake_x.pop_back();
    snake_y.pop_back();
}

void MainWindow::move_right()
{
    //首部增加元素
    snake_x.push_front(snake_x.front() + 2*snake_body_r.at(level));
    snake_y.push_front(snake_y.front());
    //尾部删除元素
    snake_x.pop_back();
    snake_y.pop_back();
}

③碰撞检测

这个主要是判断蛇是否吃到食物,是否撞到自己的身体,是否撞到墙的检测,毕竟这标志着蛇的变大边长,游戏是否结束等,原理也很简单,不断的对食物容器的坐标和蛇头的坐标进行循环检测,坐标一致时,代表蛇头吃到食物了,蛇的身体加一,并在食物容器中删除对应的食物,撞墙和撞自己也是一样的原理

void MainWindow::Is_eat_food()
{

    for(int i = 0;i=snake_x.at(0))
        &&(food_y.at(i) - eat_food_collision_offset<=snake_y.at(0)&&food_y.at(i)+eat_food_collision_offset>=snake_y.at(0)))//蛇吃到食物
        {
            //蛇身加长
            snake_x.append(snake_x.back());
            snake_y.append(snake_y.back());
            //食物消失
            food_x.removeAt(i);
            food_y.removeAt(i);
            snake_body_num++;
            score++;
        }
    }
}
void MainWindow::Is_game_over()
{
    //游戏结束的两种情况
    //蛇头与蛇身相碰撞
    //蛇头撞墙
    for(int i = 1;i=snake_x.at(i)-snake_collision_body_offset)
           &&(snake_y.at(0)<=snake_y.at(i)+snake_collision_body_offset&&snake_y.at(0)>=snake_y.at(i)-snake_collision_body_offset))
            Game_State = OVER;
    }
    if(snake_x.at(0)-snake_collision_wall_offset<=0||snake_y.at(0)-snake_collision_up_offset-ui->menubar->height()<=0||
            snake_x.at(0)+snake_collision_wall_offset>=Width||snake_y.at(0)+snake_collision_wall_offset>=Height)
        Game_State = OVER;
}

这三点就是贪吃蛇游戏最核心的三点了,其余的蛇头蛇身配色,地图选择,蛇吃的越多会越来越大什么的功能,可以在文章最后的项目源码里查看,也可以评论或者私信我~

项目展示

游戏主界面

Qt制作贪吃蛇游戏_第1张图片

菜单栏:

可以自定义蛇头,蛇身,食物的颜色以及切换地图(均可实时切换)

Qt制作贪吃蛇游戏_第2张图片

游戏开始,方向键盘控制蛇身移动

Qt制作贪吃蛇游戏_第3张图片按下空格键可暂停/继续游戏

Qt制作贪吃蛇游戏_第4张图片

可以实时切换蛇头,蛇身,食物颜色以及地图

并且随着吃的食物越来越多,蛇的体型也会越来越大

Qt制作贪吃蛇游戏_第5张图片

 蛇撞墙或者吃到自己的身体,蛇就会死亡,游戏结束

Qt制作贪吃蛇游戏_第6张图片

项目源码:https://github.com/17359830697/GluttonousSnake

喜欢的话就点个收藏关注我吧~

有什么意见建议也可以评论喔~

你可能感兴趣的:(Qt,游戏,qt)