当前位置: 首页 > news >正文

贪吃蛇游戏的实现:C++ 控制台版

功能概述

  • 控制蛇的移动:使用WASD键控制蛇的移动方向。
  • 随机生成食物:蛇吃到食物后,食物会在游戏区域内随机生成。
  • 显示分数:游戏中会显示当前分数。
  • 游戏结束条件:当蛇碰到自己或走出边界时,游戏结束并显示“游戏失败”消息。
  • 清屏防止闪屏:使用光标控制函数

代码解释

游戏初始化 (Setup 函数)

  • dir = STOP;: 初始化蛇的移动方向为停止状态。
  • snake.clear();: 清空蛇的身体。
  • snake.push_back({ WIDTH / 2, HEIGHT / 2 });: 将蛇的头部放置在游戏区域的中心。
  • score = 0;: 重置分数。
  • food = { rand() % WIDTH, rand() % HEIGHT };: 随机生成食物的位置。
  • gameOver = false;: 游戏状态设置为“未结束”。

绘制游戏界面 (Draw 函数)

  • system("cls");: 清除控制台屏幕。
  • for (int i = 0; i < WIDTH + 2; i++) cout << "#";: 绘制游戏区域的边框。
  • for (int y = 0; y < HEIGHT; y++) { ... }: 绘制游戏区域的每一行。
  • if (x == food.x && y == food.y) cout << "F";: 在食物位置绘制F
  • if (x == 0) cout << "#";: 绘制左边框。
  • if (x == WIDTH - 1) cout << "#";: 绘制右边框。
  • if (gameOver) { ... }: 如果游戏结束,显示游戏结束消息。

处理用户输入 (Input 函数)

  • if (_kbhit()) { char c = _getch(); ... }: 检测并读取用户的键盘输入。
  • case 'a':: 处理向左移动。
  • case 'd':: 处理向右移动。
  • case 'w':: 处理向上移动。
  • case 's':: 处理向下移动。
  • case 'x':: 处理退出游戏。

更新游戏逻辑 (Logic 函数)

  • Point prev = snake[0];: 保存蛇头的当前坐标。
  • snake[0].x += (dir == RIGHT) - (dir == LEFT);: 根据当前方向更新蛇头的x坐标。
  • snake[0].y += (dir == DOWN) - (dir == UP);: 根据当前方向更新蛇头的y坐标。
  • if (snake[0].x >= WIDTH || snake[0].x < 0 || snake[0].y >= HEIGHT || snake[0].y < 0): 检查蛇是否走出边界。
  • if (snake[0].x == food.x && snake[0].y == food.y): 检查蛇是否吃到食物。
  • for (int i = 1; i < snake.size(); i++): 检查蛇是否碰到自己。
  • for (int i = 1; i < snake.size(); i++) { prev2 = snake[i]; snake[i] = prev; prev = prev2; }: 移动蛇的身体。

清屏防止闪屏

原理: 通过控制光标的位置来实现清屏和更新内容,而不是使用 system("cls") 这样的全屏清除方法。

实现:

  • 使用 gotoxy(int x, int y) 函数移动光标到指定位置。
  • 在每次更新屏幕时,先将光标移动到屏幕的起始位置 (0, 0) 清除内容,然后绘制新的内容。
  • 当然,你也可以使用别的方法:双缓冲

优点: 避免了整个屏幕的清除和重绘,减少了闪烁。

效果图

源代码

编译时在连接器命令行加入以下命令

-std=c++11

#include <iostream>
#include <conio.h> // 用于 _getch() 读取键盘输入
#include <windows.h> // 用于 Sleep() 暂停游戏
#include <vector>
#include <ctime>
#include <cstdlib>using namespace std;// 定义游戏常量
const int WIDTH = 15;  // 游戏区域的宽度
const int HEIGHT = 15; // 游戏区域的高度
int score = 0;         // 玩家得分
bool gameOver = false; // 游戏是否结束的标志// 定义方向控制的枚举
enum Direction { STOP = 0, LEFT, RIGHT, UP, DOWN };
Direction dir; // 当前蛇的移动方向// 表示二维空间中的一个点
struct Point {int x, y;
};// 存储蛇的身体段的向量
vector<Point> snake;
Point food; // 当前食物的位置// 函数声明
void Setup();
void Draw();
void Input();
void Logic();
void gotoxy(int x, int y); // 函数声明:移动光标到指定位置// 初始化游戏状态的函数
void Setup() {dir = STOP; // 设置蛇的初始移动方向为停止snake.clear(); // 清空蛇的身体snake.push_back({ WIDTH / 2, HEIGHT / 2 }); // 将蛇的头部放置在游戏区域的中心score = 0; // 重置分数food = { rand() % WIDTH, rand() % HEIGHT }; // 随机生成食物的位置gameOver = false; // 游戏状态设置为“未结束”
}// 移动光标到指定位置
void gotoxy(int x, int y) {HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); // 获取标准输出设备的句柄COORD pos = { static_cast<SHORT>(x), static_cast<SHORT>(y) }; // 设置光标位置SetConsoleCursorPosition(handle, pos); // 移动光标
}// 绘制游戏界面的函数
void Draw() {gotoxy(0, 0); // 移动光标到控制台的左上角// 绘制游戏区域的上边框for (int i = 0; i < WIDTH + 2; i++)cout << "#";cout << endl;// 绘制游戏区域的每一行for (int y = 0; y < HEIGHT; y++) {for (int x = 0; x < WIDTH; x++) {if (x == 0)cout << "#"; // 绘制左边框if (x == food.x && y == food.y)cout << "F"; // 绘制食物else {bool print = false;// 检查当前坐标是否被蛇的身体占据for (auto s : snake) {if (s.x == x && s.y == y) {cout << "O"; // 绘制蛇的身体段print = true;}}if (!print)cout << " "; // 空白区域}if (x == WIDTH - 1)cout << "#"; // 绘制右边框}cout << endl;}// 绘制游戏区域的下边框for (int i = 0; i < WIDTH + 2; i++)cout << "#";cout << endl;// 显示当前得分cout << "Score: " << score << endl;// 如果游戏结束,显示“游戏结束”消息if (gameOver) {cout << "Game Over! Press any key to exit..." << endl;}
}// 处理用户输入的函数
void Input() {if (_kbhit()) { // 检测是否有键盘输入char c = _getch(); // 获取按下的键switch (c) {case 'a': // 向左移动if (dir != RIGHT) // 确保蛇不会反向移动dir = LEFT;break;case 'd': // 向右移动if (dir != LEFT)dir = RIGHT;break;case 'w': // 向上移动if (dir != DOWN)dir = UP;break;case 's': // 向下移动if (dir != UP)dir = DOWN;break;case 'x': // 退出游戏gameOver = true;break;}}
}// 更新游戏逻辑的函数
void Logic() {if (gameOver) return; // 如果游戏结束,跳过逻辑更新// 更新蛇头的位置Point prev = snake[0];Point prev2;snake[0].x += (dir == RIGHT) - (dir == LEFT); // 根据方向更新蛇头的x坐标snake[0].y += (dir == DOWN) - (dir == UP); // 根据方向更新蛇头的y坐标// 检查蛇是否超出边界if (snake[0].x >= WIDTH || snake[0].x < 0 || snake[0].y >= HEIGHT || snake[0].y < 0) {gameOver = true; // 游戏结束}// 检查蛇是否碰到自己for (int i = 1; i < snake.size(); i++) {if (snake[i].x == snake[0].x && snake[i].y == snake[0].y) {gameOver = true; // 游戏结束}}// 检查蛇是否吃到食物if (snake[0].x == food.x && snake[0].y == food.y) {score++; // 增加分数food = { rand() % WIDTH, rand() % HEIGHT }; // 生成新的食物位置snake.push_back(prev); // 将新的一节添加到蛇的身体}// 移动蛇的身体for (int i = 1; i < snake.size(); i++) {prev2 = snake[i];snake[i] = prev;prev = prev2;}
}// 主函数
int main() {srand(static_cast<unsigned>(time(0))); // 用当前时间作为随机数生成的种子Setup(); // 初始化游戏while (!gameOver) { // 游戏循环Draw(); // 绘制游戏界面Input(); // 处理用户输入Logic(); // 更新游戏逻辑Sleep(100); // 暂停100毫秒}Draw(); // 绘制结束界面显示“游戏结束”_getch(); // 等待用户输入后退出程序return 0;
}

C++控制台去呈现一些图形游戏确实不太方便,最好可以使用EASYX/QT等图形库实现。

送大家一段话:
笔走龙蛇,意境深远。言之有物,情真意切。
辞藻华丽,意蕴深厚。文思敏捷,才华横溢。
洞若观火,鞭辟入里。文采飞扬,笔力雄健。
行云流水,流畅自然。精辟入里,洞察秋毫。
妙语连珠,引人入胜。深入骨髓,发人深省。
豁然开朗,醍醐灌顶。言之凿凿,掷地金声。
言近旨远,韵味无穷。淋漓尽致,曲尽其妙。
独具匠心,匠心独运。笔底春风,笔下生花。
字字玑珠,句句珠玑。意味深长,耐人寻味。

人话
写作技巧高超,文章意境深远。内容真实感人,情感表达真诚。用词华丽而富有内涵,作者思维敏捷且才华出众。观察事物深刻透彻,分析问题直击要害。文笔生动活泼,才华横溢。文章如同行云流水般流畅自然。分析精辟,能够洞察细微之处。言语中充满智慧,让人读来兴趣盎然。剖析问题深入本质,能引发读者深思。给人以豁然开朗的感觉,像醍醐灌顶一般让人清醒。言辞确凿有力,话语坚定响亮。言简意赅却含义深远,令人回味无穷。表达淋漓尽致,把事情描绘得细致入微。构思独特巧妙,展现了作者的独特匠心。文笔优美,仿佛春风拂面,笔下的文字如同花朵盛开。每个字都精心雕琢,每一句话都充满力量。文章意味深长,值得反复品味。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • PyTorch:从零实现一个双向循环神经网络
  • MySQL-MHA高可用配置及故障切换
  • 凸分析与凸优化精解【1】
  • Oracle-OracleConnection
  • JavaScript高阶笔记总结(Xmind格式):第三天
  • 如何在阿里云环境中通过 Jenkins 实现 .NET Core 应用的 Docker 化部署:从 GitLab 拉取代码到自动化 CI/CD 流程的完整指南
  • x264 编码器 SSIM 算法源码分析
  • 【Python】基础语法介绍
  • Github Copilot 使用技巧
  • 连锁店收银系统源码
  • 介绍springmvc-水文
  • uni-app开发微信小程序注意事项,不要用element-ui
  • 【大模型理论篇】GPT系列预训练模型原理讲解
  • WebDeveloper靶机复现
  • Github 2024-08-13 开源项目日报 Top10
  • 【Leetcode】101. 对称二叉树
  • [iOS]Core Data浅析一 -- 启用Core Data
  • CODING 缺陷管理功能正式开始公测
  • Cumulo 的 ClojureScript 模块已经成型
  • idea + plantuml 画流程图
  • IDEA常用插件整理
  • javascript 哈希表
  • javascript面向对象之创建对象
  • k8s如何管理Pod
  • October CMS - 快速入门 9 Images And Galleries
  • PHP的Ev教程三(Periodic watcher)
  • React-Native - 收藏集 - 掘金
  • RxJS 实现摩斯密码(Morse) 【内附脑图】
  • tab.js分享及浏览器兼容性问题汇总
  • vue从入门到进阶:计算属性computed与侦听器watch(三)
  • 道格拉斯-普克 抽稀算法 附javascript实现
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 前端存储 - localStorage
  • 深度学习入门:10门免费线上课程推荐
  • 腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?
  • 微信小程序填坑清单
  • #Datawhale AI夏令营第4期#多模态大模型复盘
  • #Lua:Lua调用C++生成的DLL库
  • #控制台大学课堂点名问题_课堂随机点名
  • #微信小程序(布局、渲染层基础知识)
  • $redis-setphp_redis Set命令,php操作Redis Set函数介绍
  • (39)STM32——FLASH闪存
  • (70min)字节暑假实习二面(已挂)
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (vue)el-checkbox 实现展示区分 label 和 value(展示值与选中获取值需不同)
  • (ZT)出版业改革:该死的死,该生的生
  • (笔记)M1使用hombrew安装qemu
  • (差分)胡桃爱原石
  • (附源码)springboot猪场管理系统 毕业设计 160901
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (附源码)计算机毕业设计大学生兼职系统
  • (算法)区间调度问题
  • (一)Java算法:二分查找
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树