这是笔者用作练习C++的一个小项目,框架思路和程序上很大程度借鉴了牛客网-项目实战-2048小游戏,并在此基础上进行了功能上的拓展,增加了记录历史最高成绩和当前玩家得分两个功能。下面进行介绍
码云:https://gitee.com/hinzer/my-notes-of-C_plus/tree/master/project/
项目界面
我的系统环境是CentOS7.x,编译运行项目前,需要安装依赖
sudo yum install libncurses5-dev编译命令
g++ demo.cpp -l ncurses -o 2048
一、问题描述
对于整个项目,从IPO(输入-处理-输出)的角度来看这个游戏 1.输入:用户按按键 2.处理规则: 一次只能合并相邻的两个数字,例如 [2 2 2 2] ,向右合并以后是 [空 空 4 4] ,不是 [空 空 空 8] 每次合并的时候,合并方向优先级高,例如 [空 2 2 2],向右合并以后是 [空 空 2 4],不是 [空 空 4 2] 判断游戏胜利或者失败 每次合并以后随机新出4的概率10% 3.输出:数字元素的动态变化和用户提示语句形成的图形界面
二、问题分析
1.随机产生两个数字元素在这个"方阵"上,通过按键的上下左右来控制数字的移动,实现数字的合并。因此数字特点是离散的、和二维的。 2.每次按下按键的时刻和键值是不确定的,将按键按下视为一个事件,然后程序再进行判断。因此是事件驱动模型。 3.事件的主要信息是,按键按下产生的键值和之后对二维数字方阵的结果。因此用二维数组保存最终的二维数据。 4.游戏主要是根据二维数组或者玩家的动作(按下按键)来判断游戏玩家的状态。因此用变量来记录玩家的状态。
综上,定义一个类Game2048来描述这个游戏,通过变量status和二维数组data来表示这个游戏的属性,再有就是类的方法表示游戏的动作,比如绘制图形界面相关方法、重启初始化方法、上下左右移动方法、判断游戏结束方法。
三、开发步骤
Step1.引入curses库 终端内绘制简单的图形用户界面,这里先让其对窗口进行一系列的初始化。
Step2.绘制游戏界面 将界面框架绘制好,具体在实现draw方法的时候,利用循环结构填充字符框架,除了布局整洁之外,还要注意保持合适的间距,后面用来填充数字元素。
Step3.游戏状态切换 实现processInput方法,捕获用户按下按键的键值,能够判断QRWASD几个字母,后面会实现具体的逻辑功能。
Step4.重启初始化游戏实现restart方法,当用户按下R键时,清空界面并随机生成两个数值元素作为初始元素。在随机生成数值元素的处理程序中,先定义一个vector容器,存储当前数组中的空元素的位置(将二维坐标转换成一维坐标值表示),然后在随机选择空位置上生成2or4的元素(使用rand()函数生成随机数,用时间作为随机数种子)。
Step5.向左移动 逐行遍历每一个元素data[i][j],将前一个元素设定为比较值compareValue,进行相邻元素之间的比较。如果相邻元素值相等,将结果当前要写入的位置currentWritePos,重新设定比较值compareValue并进行下一轮比较;如果相邻元素值不相等,就将比较值写回当前要写入的位置currentWritePos,并跟新比较值compareValue,进行下一次比较。直到这行遍历完成,将比较值再写回当前要写入的位置currentWritePos(这是为了保证右边的元素不会被"清除")
Step6.向其他方向上移动 这里用了一个颇为巧妙的方法,将数组逆时针翻转90度之后的新数组,再进行step5中的想左移动,相当于原数组向上移动。将移动后的结果再翻转回去,就有了向其他方向上的移动效果。
Step7.游戏判断胜负 任意地方出现2048数字,就算赢;如果矩阵被填满并且不能再移动,就算输。具体通过查询或相邻元素比较来判断。
四、拓展
记录历史最高分,并且显示当前玩家得分。
我这里通过读写文件的方式,完成玩家历史得分的显示和记录。每次有方向移动过程中,如果一对数字组合成功,就加10分。在图形界面刷新过程中,实时显示当前玩家分数为当前分数,和读取文件的分数为历史最高。判断玩家分数是否大于历史分数,是的话就跟新文件中记录的最大值。
五、完整程序 #include #include #include #include #include #include #include using namespace std;// 格子数#define N 4// 每个格子的字符长度#define WIDTH 5// 胜利条件#define TARGET 2048// 游戏状态#define S_FAIL 0#define S_WIN 1#define S_NORMAL 2#define S_QUIT 3class Game2048{public:Game2048():status(S_NORMAL){myScore = 0;setTestData();}int getStatus(){return status;}//处理按键void processInput(){char ch = getch();bool updated = false;if( 'a'