逆向软件开发和设计——贪吃蛇游戏(C++)
原项目介绍和分析
项目介绍
Github地址:https://github.com/silence1772/GreedySnake
这是一个由C++11标准所编写的控制台贪吃蛇项目。以下先给出原系统的部分运行截图
主页面
游戏过程
项目运行
在GitHub上将源文件下载下来后,我们将会得到7个头文件和8个源文件。
以下以VS为例:
- 新建项目
- 将项目头文件和源文件分别导入
- 因为VS的特殊性,需要将sprintf()、getch()、kbhit函数分别修改为sprintf_s()、_getch()、_kbhit()。
- 需要将项目的编码改为UTF-8(BOM)
做完以上操作即可正常编译运行
项目分析
该项目是一个简易的贪吃蛇小游戏,通过操作光标来实现色块的输入和删除以实现贪吃蛇游戏的效果。
经过简单的游玩测试和代码分析,我得到了该项目的运行流程并针对其功能模块不同绘制了如下流程图:
通过流程图不难发现其运行逻辑并不复杂,但是在实际操作中仍然可以发现些许问题:
- 在暂停游戏后回到难度选择界面时,其开场动画产生的SNAKE图会消失
- 通过代码分析发现其贪吃蛇中产生的食物并不是等概率在地图中产生
项目改进
问题修改
- 修改贪吃蛇食物的生成逻辑,保证了x,y在地图上的等概率分别
/*int tmp_x = rand() % 30;
int tmp_y = rand() % 30;
if(tmp_x < 2) tmp_x += 2;
if(tmp_y < 2) tmp_y += 2;*/
//以上为原生成逻辑,以下为新生成逻辑
int tmp_x = rand() % 28+2;
int tmp_y = rand() % 28+2;
- 在返回难度选择界面的实现区加入了新的代码,使得返回主页面时SNAKE图画再次生成
void Controller::Game()
{
Start();
while (true)
{
Select();
DrawGame();
int tmp = PlayGame();
if (tmp == 1)
{
system("cls");
StartInterface* start_t = new StartInterface();
start_t->clear();
SetColor(2);
start_t->PrintThird();
delete start_t;
//在此处重新添加SNAKE动画
continue;
}
else if (tmp == 2)
{
break;
}
else
{
break;
}
}
}
void StartInterface::clear()//新的函数声明,用于清空动画的蛇的部分,只生成文字动画
{
this->startsnake.clear();
}
细节修改和程序优化
- 添加了一段代码以取消掉贪吃蛇运动过程中的光标闪烁
void ShowConsoleCursor(bool showFlag)
{
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cursorInfo;
GetConsoleCursorInfo(out, &cursorInfo);
cursorInfo.bVisible = showFlag;//取消光标闪烁
SetConsoleCursorInfo(out, &cursorInfo);
}
- 由于代码通过四个难度直接最高难度和最低难度的速度设计不够合理,故取消两个难度,改为加速模式(贪吃蛇的速度随着分数的提高而不断提高,直到峰值)
if (csnake->GetFood(*cfood)) //吃到食物
{
csnake->Move();//蛇增长
UpdateScore(1);//更新分数,1为分数权重
RewriteScore();//重新绘制分数
if (key == 4 && speed >= 50) speed -= 5;//加速模式的加速
cfood->DrawFood(*csnake);//绘制新食物
}
- 在右上角的当局游戏状态中添加了当前难度用户的取得的最高分数
通过维护一个max_score数组来实现四个难度下取得的最高分数
int max_score[5];
/*蛇死亡*/
delete csnake;
delete cfood;
int tmp = GameOver();
max_score[key] = max(max_score[key], score);
- 针对在出现限时食物时,限时食物闪烁出现显示异常的状况,进行了修改
void Food::FlashBigFood()//闪烁限时食物
{
SetCursorPosition(big_x, big_y);
SetColor(11);
if (flash_flag)
{
std::cout << " " ;
flash_flag = false;
}
else
{
std::cout << "■" ;
flash_flag = true;
}
SetCursorPosition(26, 0);
SetColor(11);
for (int i = 42; i >= progress_bar; --i)
std::cout << "\b \b" ;
--progress_bar;
if (progress_bar == 0) {
SetCursorPosition(big_x, big_y);
std::cout << " " ;
big_flag = false;
big_x = 0;
big_y = 0;
}
}
SetColor函数的参数原代码为18,而此函数只能显示0-15对应的16个颜色,所以出现了显示错误
修改小结
总结
经过这次实验设计,我有如下几点收获:
- 在GitHub开源社区中可以找到很多值得学习和改进的项目
- 为了保证代码在不同系统和编译环境下的可运行性,编写和上传源码以及使用文档时要注意其可移植性以及对应说明
- 对于一个开始具有一定规模的项目来说,尽管可以运行,但是细节之处还是会有很多可以优化之初。
- 对于一个游戏项目,应当着重于优化其游玩趣味和游玩体验,以及保证其游玩中个部分运行逻辑的合理性
- 通过这类逆向软件开发,大大增强了我的代码阅读能力,以及对于整个项目优化的思考能力。在原有的项目之上做出优化以及做出创新性的功能,这对于我的这类能力的培养是有很大益处的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通