MFC实现2048游戏(二)
来源:互联网 发布:淘宝店铺销量排行榜 编辑:程序博客网 时间:2024/06/05 04:48
上一篇,主要介绍了UI部分,其实根本没有UI,自己做这个游戏也是就是实现一下逻辑功能,其实游戏的逻辑是最难的,UI谁都可以学会,逻辑却是需要理解的!
主要的逻辑:
选择了二维数组 与 双端队列(deque);因为双端队列(queue)可以操作[]下标,用起来比较方便:
int tempArray[Count][Count];
memcpy(tempArray,m_nArray,sizeof(int)*Count*Count);
deque<int> lst[Count];//声明一个deque<int>类型的数组 数组长度为4,也就是4个deque<int>
首先界面的初始化:
//重置,重新开始界面初始化void CMy2048Dlg::Reset(void){for(int i = 0; i < Count; i++){for (int j = 0; j < Count; j++){m_nArray[i][j] = 0;}}RandonNum();RandonNum();}
这个没有什么,RandNum()是随机生成数字的函数
以向下为例子:我们要用 双端队列数组lst 对二维数组进行分组:
原先的数组 00 01 02 03
10 11 12 13
20 21 22 23
30 31 32 33
分组后 第一个队列:lst[0] : 00 10 20 30
第二个队列:lst[1] : 01 11 21 31
第三个队列:lst[2] : 02 21 22 32
第四个队列:lst[3] : 03 13 23 33
所以分组后:
lst[0][0] = tempArray[0][0];
lst[0][1] = tempArray[1][0];
lst[0][2] = tempArray[2][0];
上面的分析只是相对假设的情况,实际上不是如此 因为分组有个条件:m_nArray[i][j] != 0
所以它只是会对不是0的数据进行分组
现在分析一个情况: 原先数组的第一列为 4
2
0
0
那么分组后 其实 lst[0] 只要两个数据: lst[0][0]: 4; lst[0][1]:2;
我们看分组的代码实现:
int tempArray[Count][Count];memcpy(tempArray,m_nArray,sizeof(int)*Count*Count);deque<int> lst[Count];//声明一个deque<int>类型的数组 数组长度为4,也就是4个deque<int>for (int i = 0; i < Count; i++){for (int j = 0; j < Count; j++){if (m_nArray[i][j] != 0){lst[j].push_front(m_nArray[i][j]);}}}
所以分组后:lst[0] 只要两个数据: lst[0][0]: 4; lst[0][1]:2;
原先数组是 4 2 0 0 ,那我们按向下的按钮它应该变为 0 0 4 2:
在这之间我们要对 lst里面的数据进行 加的处理 和 反转的处理:
//实现累加void CMy2048Dlg::Add( deque<int> &list){for(int i = 0; i < list.size(); i++){if (list[i] == 0)continue;for (int j = i+1; j < list.size(); j++){if (list[i] == list[j]){list[i] *= 2;list[j] = 0;break;}//如果当前的值不为0 跳出内循环,没必要再比较例如: 4 2 2 ; 当 list[0]=4,list[1]=2//list[1] = 2 != 0,直接跳出循环, 没必要再比较 list[2]与 list[0]if (list[j] != 0) {break;}}}//重新排列顺序,不足补0;//例如 4 2 经过上面的代码其实没有任何变化累加,但是累加最后的结果要变为 4 2 0 0 deque<int> tempLst;for (int i = 0; i < list.size(); i++){//双端队列支持对元素的下标访问if (list[i] != 0){tempLst.push_back(list[i]);}}list = tempLst; //这个时候 list的元素为: 4 2 ,所以下面要补0for (int i = list.size(); i < Count; i++ ){list.push_back(0); //list 的元素为: 4 2 0 0 }}
//反转数据void CMy2048Dlg::ReservedLst(deque<int> &lst){deque<int> tempLst;while (lst.size() != 0){tempLst.push_back(lst.back());lst.pop_back();}lst = tempLst; //反转后的list元素为 0 0 2 4}
再看向下的代码:
bool CMy2048Dlg::Down(void){int tempArray[Count][Count];memcpy(tempArray,m_nArray,sizeof(int)*Count*Count);deque<int> lst[Count];//声明一个deque<int>类型的数组 数组长度为4,也就是4个deque<int>for (int i = 0; i < Count; i++){for (int j = 0; j < Count; j++){if (m_nArray[i][j] != 0){lst[j].push_front(m_nArray[i][j]);}}}//累加for (int i = 0; i < Count; i++){Add(lst[i]); //这里假设对于 lst[0];相加后为: lst[0][0]: 4; lst[0][1]:2;没有变化这种情况//因为相加的时候是 以lst[0][0], lst[1][0]为基准,所以这里向下相加后,就要反转一下ReservedLst(lst[i]);}//重新赋值for (int i = 0; i < Count; i++){for (int j = 0; j < Count; j++){m_nArray[i][j] = lst[j][i]; //注意这里是 lst[j][i] 赋值给 m_nArray[i][j]}}//检测变动for (int i = 0; i < Count; i++){for (int j = 0; j < Count; j++){if (m_nArray[i][j] != tempArray[i][j]){return true;}}}return false;}
这个过程用实例演示:
比如现在 第一列是 2
2
0
0
那么它经过分组后 lst[0]: 有两个数据: lst[0][0]为 2 lst[0][1] 为2
Add(lst[0]); 经过Add后 lst 首先变为 4 0, 再变为 4 0 0 0
ReservedLst(lst[i]);经过ReservedLst后 lst 变为 0 0 0 4;
达到我们的效果!
向上,向左,向右的代码基本一样:
有两个地方需要注意:
向下 与 向右 分组的时候 是前端插入队列:
for (int i = 0; i < Count; i++){for (int j = 0; j < Count; j++){if (m_nArray[i][j] != 0){lst[j].push_front(m_nArray[i][j]);}}}
向上 与 向左 分组的时候 是后端插入队列:
for (int i = 0; i < Count; i++){for (int j = 0; j < Count; j++){if (m_nArray[i][j] != 0){lst[i].push_back(m_nArray[i][j]);}}}
至于为什么两者不一样,主要是因为反转那里的原因!
最后就是结束的逻辑,
只要两两都不相同,游戏就结束了:
//处理游戏结束的逻辑:bool CMy2048Dlg::CalcEnd(void){//首先处理横轴:for (int i = 0; i < Count; i++){for (int j = 0; j < Count; j++){if (m_nArray[i][j] == 0){return false;}if (j+1 == Count){break;}if (m_nArray[i][j] == m_nArray[i][j+1]){return false;}}}//处理纵轴for (int i = 0; i < Count; i++){for (int j = 0; j < Count; j++){if (m_nArray[i][j] == 0){return false;}if (i+1 == Count){break;}if (m_nArray[i][j] == m_nArray[i+1][j]){return false;}}}return true;}
游戏面盘的设计:就是把一个客户区划分为16个小块,没个小块对应每一个数组元素的数字显示:
else //初始化游戏面盘{CRect rect;GetClientRect(rect);//获取窗口客户区的坐标 客户区坐标是相对窗口客户区的左上角而言的,因此左上角坐标为(0,0)。rect.left += 5;rect.right -= 5;rect.top += 5;rect.bottom -= 5;CPaintDC dc(this);int nWidth = rect.Width()/Count; //每个单元格的宽度int nHeight = rect.Height()/Count;//每个单元格的高度CFont font;font.CreatePointFont(nHeight*5, _T("Arial"),&dc); //创建字体和大小CFont* oldFont = dc.SelectObject(&font);//保存旧的字体dc.SetBkMode(TRANSPARENT);//设置背景颜色为透明for(int i = 0; i < Count; i++){for (int j = 0; j < Count; j++){CRect rectChild;rectChild.left = rect.left + j*nWidth;rectChild.top = rect.top + i*nHeight;rectChild.right = rectChild.left + nWidth;rectChild.bottom = rectChild.top + nHeight;dc.Draw3dRect(rectChild,RGB(255,0,0),RGB(255,0,0));if (m_nArray[i][j] != 0){CString strText;strText.Format(_T("%d"),m_nArray[i][j]);//该函数的功能是在指定的矩形里写入格式化文本,根据指定的方法对文本格式化//(扩展的制表符,字符对齐、折行等)dc.DrawText(strText,rectChild,DT_CENTER|DT_VCENTER);}}}CDialogEx::OnPaint();dc.SelectObject(oldFont);//选则回原来的字体font.DeleteObject();//删除字体}
然后处理键盘消息;键盘消息的截获要重载PreTranslateMessage()函数:
//对键盘消息进行截获BOOL CMy2048Dlg::PreTranslateMessage(MSG* pMsg){bool bRet = false;if (pMsg->message == WM_KEYDOWN){switch (pMsg->wParam){case VK_DOWN:bRet = Down();break;case VK_UP:bRet = Up();break;case VK_LEFT:bRet = Left();break;case VK_RIGHT:bRet = Right();break;default:break;}if (CalcEnd()){AfxMessageBox(_T("GameOver!"));Reset();}else{if (bRet){RandonNum();Invalidate(TRUE);if (CalcEnd()){AfxMessageBox(_T("GameOver!"));Reset();}}}Invalidate(TRUE);}return CDialogEx::PreTranslateMessage(pMsg);}
感觉用文字解释还是真的比较难,就是为自己梳理了下思路:
源码下载地址:点击打开链接;大神勿看,写的差 ;新手可以看看一起学习!文字解释比较难解释,还是看代码慢慢理解!
- MFC实现2048游戏(二)
- MFC实现2048游戏(一)
- MFC设计局域网对战五子棋游戏(二)实现GDI+自绘按钮
- 《MFC游戏开发》笔记八 游戏特效的实现(二):粒子系统
- 《MFC游戏开发》笔记八 游戏特效的实现(二):粒子系统
- 《MFC游戏开发》笔记八 游戏特效的实现(二):粒子系统
- 《MFC游戏开发》笔记八 游戏特效的实现(二):粒子系统
- MFC版哈希值计算器的实现(二)
- MFC截图程序的实现(二)
- MFC实现俄罗斯方块二
- MFC实现游戏Launcher效果
- flowerboard游戏MFC+GDIPLUS实现
- 扑克游戏架构及其实现(二)
- (之二)实现游戏的算法
- JavaScript--2048游戏二()
- 基于MFC框架的C++游戏开发(三)游戏贴图与透明特效的实现
- MFC渐入渐出框实现方式二
- MFC渐入渐出框实现方式二
- iOS--GCD(二)
- 浅谈虎书中Java垃圾回收器(复制收集 )的实现
- HPUOJ 题目1079 假币问题(三分)
- VS2005调试技巧集合
- python3抓取代理服务器ip
- MFC实现2048游戏(二)
- 在一个TextView中字体显示不同颜色
- android ndk c++ 调用 JAVA程序
- 查找主ip地址
- java注解Annotation,的基本作用和用法的简明介绍
- python中半角与全角互相转换
- 搜索引擎的技术架构
- 69MainActivity的透传消息
- MFC Activex与JavaScript的接口交互