【C/C++】10分钟教你用C++写一个贪吃蛇附带AI功能(附源代码详解和下载)(下)

简介: 【C/C++】10分钟教你用C++写一个贪吃蛇附带AI功能(附源代码详解和下载)

04 贪吃蛇类

定义贪吃蛇的移动,打印,吃食物等等。这节课我们暂时不讨论AI功能,先把手动操作的贪吃蛇做了跑起来,下节课再做AI功能的介绍。该类大体如下:

微信图片_20220421150411.jpg

4.1 成员变量

成员变量m_direction记录每次移动的方向。m_is_alive记录贪吃蛇是否还活着。m_coordinate则是贪吃蛇身体坐标的记录。贪吃蛇是一节一节的,整条蛇必然是由许多节组成的。因此用了一个vector来存储蛇身,每节类型是COORDINATE结构体的。

4.2 默认构造函数

默认构造函数Snake()里面主要是做了初始贪吃蛇的生成,以及移动方向的定义等。初始的蛇为3节。在中间位置,向上移动。代码如下:

1        //移动方向向上
 2    m_direction = 1;
 3    m_is_alive = true;
 4    COORDINATE snake_head;
 5    //蛇头生成位置
 6    snake_head.x = GameSetting::window_width / 2 - 15;
 7    snake_head.y = GameSetting::window_height / 2;
 8
 9    this->m_coordinate.push_back(snake_head);
10    snake_head.y++;
11    this->m_coordinate.push_back(snake_head);
12    snake_head.y++;
13    this->m_coordinate.push_back(snake_head); //初始蛇身长度三节

4.3 监听键盘

监听键盘用了C里面的一个库函数。_kbhit()非阻塞函数,可以不断监听键盘的情况从而不产生阻塞。有键盘按下的时候,就获取按下的键盘是哪个。然后做出相应的变化,其实是方向的调整。需要注意的是,当我们的蛇往上走的时候,按下方向的键,我们是不做处理的。其它方向一样。还有一个调整游戏速度的,speed是休眠时间,speed越小,速度越快。反之速度越慢。

1    //监听键盘
 2void listen_key_borad()
 3{
 4    char ch;
 5
 6    if (_kbhit())                    //kbhit 非阻塞函数 
 7    {
 8        ch = _getch();    //使用 getch 函数获取键盘输入 
 9        switch (ch)
10        {
11        case 'w':
12        case 'W':
13            if (this->m_direction == DOWN)
14                break;
15            this->m_direction = UP;
16            break;
17        case 's':
18        case 'S':
19            if (this->m_direction == UP)
20                break;
21            this->m_direction = DOWN;
22            break;
23        case 'a':
24        case 'A':
25            if (this->m_direction == RIGHT)
26                break;
27            this->m_direction = LEFT;
28            break;
29        case 'd':
30        case 'D':
31            if (this->m_direction == LEFT)
32                break;
33            this->m_direction = RIGHT;
34            break;
35        case '+':
36            if (speed >= 25)
37            {
38                speed -= 25;
39            }
40            break;
41        case '-':
42            if (speed < 250)
43            {
44                speed += 25;
45            }
46            break;
47        }
48    }
49}

4.4 移动贪吃蛇

移动贪吃蛇,我们用了一个方向变量,在监听键盘的时候获取移动的方向,然后在根据方向移动贪吃蛇的蛇头。这里的移动我们是这样处理的,首先,贪吃蛇每移动一次,需要改变的只有蛇头和蛇尾两节。我们只需要把新的蛇头插进去,最后再画出来就可以了。至于蛇尾,如果我们不删除蛇尾的话,蛇会不断变长的。因此我们的做法是:吃到食物的时候插入蛇头而不删除蛇尾,没有吃到食物的时候插入蛇头同时删除蛇尾。这样就完美搞定了。

1    //移动贪吃蛇
 2void move_snake()
 3{
 4    //监听键盘
 5    listen_key_borad();
 6    //蛇头
 7    COORDINATE head = m_coordinate[0];
 8    //direction方向:1 上  2 下  3 左  4 右
 9    switch (this->m_direction)
10    {
11    case UP:
12        head.y--;
13        break;
14    case DOWN:
15        head.y++;
16        break;
17    case LEFT:
18        head.x--;
19        break;
20    case RIGHT:
21        head.x++;
22        break;
23    }
24    //插入移动后新的蛇头。是否删除蛇尾,在后续吃到食物判断那里做
25    m_coordinate.insert(m_coordinate.begin(), head);
26}

4.5 是否吃到食物

判断是否吃到食物,就是看看蛇头的坐标等不等于食物的坐标。如果等于,就重新生成食物,不删除蛇尾,蛇变长一节。不等于,就删除蛇尾,蛇长不变。

1bool is_eat_food(Food & f)
 2{
 3    //获取食物坐标
 4    COORDINATE food_coordinate = f.GetFoodCoordinate();
 5    //吃到食物,食物重新生成,不删除蛇尾
 6    if (m_coordinate[HEAD].x == food_coordinate.x && m_coordinate[HEAD].y == food_coordinate.y)
 7    {
 8        f.RandomXY(m_coordinate);
 9        return true;
10    }
11    else
12    {
13        //没有吃到食物,删除蛇尾
14        m_coordinate.erase(m_coordinate.end() - 1);
15        return false;
16    }
17}

4.6判断蛇是否还存活

判断蛇是否GG,主要是看是否超出边界,是否碰到自己身体其他部分。

1//判断贪吃蛇死了没
 2bool snake_is_alive()
 3{
 4    if (m_coordinate[HEAD].x <= 0 ||
 5        m_coordinate[HEAD].x >= GameSetting::window_width - 29 ||
 6        m_coordinate[HEAD].y <= 0 ||
 7        m_coordinate[HEAD].y >= GameSetting::window_height - 1)
 8    {
 9        //超出边界
10        m_is_alive = false;
11        return m_is_alive;
12    }
13    //和自己碰到一起
14    for (unsigned int i = 1; i < m_coordinate.size(); i++)
15    {
16        if (m_coordinate[i].x == m_coordinate[HEAD].x && m_coordinate[i].y == m_coordinate[HEAD].y)
17        {
18            m_is_alive = false;
19            return m_is_alive;
20        }
21    }
22    m_is_alive = true;
23
24    return m_is_alive;
25}

4.7 画出贪吃蛇

画出贪吃蛇比较简单,gotoxy到身体的每一节,然后cout就行。在此之前设置了颜色为浅绿色。

1//画出贪吃蛇
 2void draw_snake()
 3{
 4    //设置颜色为浅绿色
 5    setColor(10, 0);
 6    for (unsigned int i = 0; i < this->m_coordinate.size(); i++)
 7    {
 8        gotoxy(m_coordinate[i].x, m_coordinate[i].y);
 9        cout << "*";
10    }
11    //恢复原来的颜色
12    setColor(7, 0);
13}

4.8 清除屏幕上的贪吃蛇

我们是死循环不断刷新打印贪吃蛇的,因此每移动一次,必然会在屏幕上留下上一次贪吃蛇的痕迹。因此我们每次在画蛇之前,不是添足,而是清理一下上次遗留的蛇身。我们知道,蛇每次移动,变的只有蛇头和蛇尾,因此该函数我们只需要清理蛇尾就行。gotoxy到蛇尾的坐标,cout<<" ";就行。

1gotoxy(m_coordinate[this->m_coordinate.size()-1].x, m_coordinate[this->m_coordinate.size() - 1].y);
2cout << " ";

05 主函数,组装我们的游戏

我们的游戏在主函数里面进行组装。然后开始运行。
首先我们做游戏相关的初始化和模式选择。

1GameSetting setting;
 2PrintInfo print_info;
 3Snake  snake;
 4//初始化游戏
 5setting.GameInit();
 6//游戏模式选择
 7print_info.DrawChoiceInfo();
 8
 9char ch = _getch();
10switch (ch)
11{
12case '1':
13    snake.set_model(true);
14    speed = 50;
15    break;
16case '2':
17    snake.set_model(false);
18    break;
19default:
20    gotoxy(GameSetting::window_width / 2 - 10, GameSetting::window_height / 2 + 3);
21    cout << "输入错误,Bye!" << endl;
22    cin.get();
23    cin.get();
24    return 0;
25}
26gotoxy(GameSetting::window_width / 2 - 10, GameSetting::window_height / 2 + 3);
27system("pause");

然后就是画地图边框,打印游戏相关信息和说明。生成食物了。

1//画地图
2print_info.DrawMap();
3print_info.DrawGameInfo(snake.GetModel());
4//生成食物
5Food food(snake.m_coordinate);

最后就是游戏死循环,在死循环里面,我们需要不断移动蛇,画蛇,判断蛇的状态,判断食物的状态,是否吃到食物等等。具体代码:

1//游戏死循环
 2while (true)
 3{
 4    //打印成绩
 5    print_info.DrawScore(snake.GetSnakeSize());
 6    //画出食物
 7    food.DrawFood();
 8    //清理蛇尾,每次画蛇前必做
 9    snake.ClearSnake();
10    //判断是否吃到食物
11    snake.is_eat_food(food);
12    //根据用户模式选择不同的调度方式
13    if (snake.GetModel() == true)
14    {
15        snake.move_snake();
16    }
17    else
18    {
19        snake.AI_find_path(food);
20        snake.AI_move_snake();
21    }
22    //画蛇
23    snake.draw_snake();
24    //判断蛇是否还活着
25    if (!snake.snake_is_alive())
26    {
27        print_info.GameOver(snake.GetSnakeSize());
28        break;
29    }
30    //控制游戏速度
31    Sleep(speed);
32}

最终,我们的代码就可以Run起来了。具体效果放在开头了。界面算不上好看,但是整个程序向大家展示了最基本最核心的功能和代码,大家可以在这个基础上开发自己喜欢的各种美丽的界面哦。

06 AI部分和完善

代码是画了几天间间断断写出来的,水平不算很高,代码也写得乱七八糟的。不过代码会在后期不断优化,尽量做到精简优美。至于AI功能,等下一篇博文写吧。

相关文章
|
2月前
|
存储 C++ UED
【实战指南】4步实现C++插件化编程,轻松实现功能定制与扩展
本文介绍了如何通过四步实现C++插件化编程,实现功能定制与扩展。主要内容包括引言、概述、需求分析、设计方案、详细设计、验证和总结。通过动态加载功能模块,实现软件的高度灵活性和可扩展性,支持快速定制和市场变化响应。具体步骤涉及配置文件构建、模块编译、动态库入口实现和主程序加载。验证部分展示了模块加载成功的日志和配置信息。总结中强调了插件化编程的优势及其在多个方面的应用。
305 63
|
2月前
|
人工智能 IDE 开发工具
C++中的AI编程助手添加
【10月更文挑战第16天】AI 对我们来说就是一个可靠的编程助手,给我们提供了实时的建议和解决方案,无论是快速修复错误、提升代码质量,或者查找关键文档和资源,AI 作为编程助手都能让你事半功倍。
|
5月前
|
人工智能 JavaScript 开发工具
C++中的AI编程助手添加
今天为大家推荐一款适配了 Viusal Studio(本文使用),VS Code(本文使用),JetBrains系列以及Vim等多种编译器环境的插件 Fitten Code,Fitten Code 是由非十大模型驱动的 AI 编程助手,它可以自动生成代码,提升开发效率,帮您调试 Bug,节省您的时间,另外还可以对话聊天,解决您编程碰到的问题。 Fitten Code免费且支持 80 多种语言:Python、C++、Javascript、Typescript、Java等。
|
3月前
|
图形学 C++ C#
Unity插件开发全攻略:从零起步教你用C++扩展游戏功能,解锁Unity新玩法的详细步骤与实战技巧大公开
【8月更文挑战第31天】Unity 是一款功能强大的游戏开发引擎,支持多平台发布并拥有丰富的插件生态系统。本文介绍 Unity 插件开发基础,帮助读者从零开始编写自定义插件以扩展其功能。插件通常用 C++ 编写,通过 Mono C# 运行时调用,需在不同平台上编译。文中详细讲解了开发环境搭建、简单插件编写及在 Unity 中调用的方法,包括创建 C# 封装脚本和处理跨平台问题,助力开发者提升游戏开发效率。
260 0
|
6月前
|
人工智能 Serverless 开发者
活动回顾丨飞天技术沙龙 Serverless + AI 专场(上海站)回顾 & PPT 下载
活动回顾丨飞天技术沙龙 Serverless + AI 专场(上海站)回顾 & PPT 下载。
活动回顾丨飞天技术沙龙 Serverless + AI 专场(上海站)回顾 & PPT 下载
|
6月前
|
人工智能 容器 运维
活动回顾丨AI 原生应用架构专场·北京站 PPT 下载
5 月 24 日,飞天技术沙龙首个 AI 原生应用架构专场在北京举办。
466 15
|
6月前
|
人工智能 运维 Cloud Native
活动回顾丨云原生技术实践营 Serverless + AI 专场 (深圳站) 回顾 & PPT 下载
云原生技术实践营 Serverless + AI 专场 (深圳站) 回顾。
|
6月前
|
存储 人工智能 C++
【PTA】L1-064 估值一亿的AI核心代码(详C++)
【PTA】L1-064 估值一亿的AI核心代码(详C++)
49 1
|
5月前
|
人工智能
AI绘画,Stable Diffusion如何使用中文简体包,黑色页面切换参数http://127.0.0.1:7860/?__theme=dark 两个__,中文包下载和安装
AI绘画,Stable Diffusion如何使用中文简体包,黑色页面切换参数http://127.0.0.1:7860/?__theme=dark 两个__,中文包下载和安装
|
5月前
|
人工智能
AI绘画---Stable Diffusion checkpoint 插件无法安装,中文包无法下载怎么办?这里该如何解决,扩展无法出现
AI绘画---Stable Diffusion checkpoint 插件无法安装,中文包无法下载怎么办?这里该如何解决,扩展无法出现