我是靠谱客的博主 清秀小霸王,最近开发中收集的这篇文章主要介绍【C++】2048游戏系列---功能模块第四稿【结束检测】一、结束的大前提二、检测思路三、添加位置四、全部代码五、测试基础部分结语,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
2048游戏系列---功能模块第四稿【结束检测】
(更新中……)
参考博客:https://blog.csdn.net/qq_39151563/article/details/104283217
由于放在一篇会导致篇幅太长,所以分成了几篇。
(可能有个10篇吧=.=)
2048游戏系列—总览篇
2048游戏系列—功能模块第一稿【矩阵操作】
2048游戏系列—功能模块第二稿【键盘输入】
2048游戏系列—功能模块第三稿【添加新数】
本篇介绍游戏结束的检测逻辑和实现
一、结束的大前提
只有当EmptyBlock<=0
时才需要检测是否结束,如果有空格,无需检测
二、检测思路
grid
相邻元素都不相等时,游戏就应该结束了。
检测逻辑(横和纵一起检测):
bool gameOver()
{
EmptyBlock = CalculateEmpty();
if(EmptyBlock>0) return false;
for(int i=0;i<4;i++)
{
int t1=0,t2=1;
while(t2<=3)
{
if(grid[i][t1]==grid[i][t2] || grid[t1][i]==grid[t2][i])//
横 || 纵
{
return false;
}
else
{
t1++;
t2++;
}
}
}
return true;
}
t1,t2分别代表前后两个数
i 在不同的判断中有不同的含义:
grid[i][t] 中代表一行,及横的检测
grid[t][i] 中代表一列,及纵的检测
三、添加位置
在for循环最后,需要检测是否结束。
四、全部代码
为了测试把 grid
写满一些
//测试矩阵
int grid[4][4] = {
{1,2,3,4},
{4,5,6,7},
{7,8,9,10},
{1,1,1,0}
};
#include <iostream>
#include "graphics.h"
using namespace std;
//测试矩阵
int grid[4][4] = {
{1,2,3,4},
{4,5,6,7},
{7,8,9,10},
{1,1,1,0}
};
int EmptyBlock = 4 ; //空格数
int dir = -1;
// 0-左,1-上,2-右,3-下
//打印函数
void PrintGrid()
{
for(int i=0; i<4; i++)
{
for(int j=0; j<4; j++)
cout << grid[i][j] << " ";
cout << endl;
}
cout << endl;
}
//计算空格函数
int CalculateEmpty()
{
int cnt = 0;
for(int i=0; i<4; i++)
for(int j=0; j<4; j++)
if(grid[i][j]==0)
cnt++;
return cnt;
}
//显示信息
void ShowInfo()
{
cout << "dir = " << dir << endl;
cout<< "EmptyBlock = " << CalculateEmpty() << endl;
cout << "grid[4][4] = " << endl;
PrintGrid();
}
//移动函数
static int x0[4] = {0, 0, 3, 0};
static int y0[4] = {0, 0, 0, 3};
static int firstOffset[4][2]
= {{1,0},{0,1},{-1,0},{0,-1}};
static int secondOffset[4][2] = {{0,1},{1,0},{0,1} ,{1,0}};
void Move(int dir)
{
//bool moved = false;
if(dir==-1) return;
int tx, ty;
int t1x, t1y;
int t2x, t2y;
for(int i=0; i<4; i++)
{
tx = x0[dir] + i*secondOffset[dir][0];
ty = y0[dir] + i*secondOffset[dir][1];
//cout << "(" << tx << ", " << ty << ")" << endl;
t1x = tx;
t1y = ty;
t2x = tx + firstOffset[dir][0];
t2y = ty + firstOffset[dir][1];
for( ;t2x>=0&&t2x<=3&&t2y>=0&&t2y<=3; t2x+=firstOffset[dir][0],t2y+=firstOffset[dir][1])
{
if(grid[t2y][t2x]!=0)
{
if(grid[t1y][t1x]==0)
{
grid[t1y][t1x] = grid[t2y][t2x];
grid[t2y][t2x] = 0;
// moved = true;
}
else if(grid[t1y][t1x]==grid[t2y][t2x])
{
grid[t1y][t1x]++;
grid[t2y][t2x] = 0;
t1x += firstOffset[dir][0];
t1y += firstOffset[dir][1];
// moved = true;
}
else if(t1x+firstOffset[dir][0]!=t2x||t1y+firstOffset[dir][1]!=t2y)
{
grid[t1y+firstOffset[dir][1]][t1x+firstOffset[dir][0]] = grid[t2y][t2x];
grid[t2y][t2x] = 0;
t1x += firstOffset[dir][0];
t1y += firstOffset[dir][1];
//cout << "Move Test" << endl;
// moved = true;
}
else
{
t1x += firstOffset[dir][0];
t1y += firstOffset[dir][1];
}
}
}
}
//return moved;
}
//添加新数
void addnum(int n)
{
while(n--)//添加n个
{
EmptyBlock = CalculateEmpty();
if(EmptyBlock<=0)
{
//cout << "addnum EmptyBlock = " << EmptyBlock << endl;
//cout << "addnum Test1" << endl;
return;
}
int cnt = random(EmptyBlock)+1;//随机得到一个空格数以内的数
//cout << "找到第" << cnt << "个空位" << endl;
//cout << "cnt = " << cnt << endl;
int *p = &grid[0][0]-1;//记录矩阵首地址前一个 ,因为后面的 p 在找到时还会 ++
//cout << "n = "<< n <<endl;
for(int i=0; i<4&&cnt; i++)
for(int j=0; j<4&&cnt; j++)
{
if(grid[i][j]==0 && cnt)//如果有空格并且cnt有效
{
//cout << "cnt = " << cnt << endl;
cnt--;//找到一个划一个
}
p++;//p 指向下一个再进行判断
}
//循环结束时 p 指向我们之前随机指定的空格
*p = (random(10)==0)?2:1;// 0.1 的概率为2,0.9 的概率为1
//cout << "插入成功" << endl;
//*p = (random(10)==0)+1;//这样写也可以
EmptyBlock--;
}
}
bool gameOver()
{
EmptyBlock = CalculateEmpty();
if(EmptyBlock>0) return false;
for(int i=0;i<4;i++)
{
int t1=0,t2=1;
while(t2<=3)
{
if(grid[i][t1]==grid[i][t2] || grid[t1][i]==grid[t2][i])//
横 ||纵
{
return false;
}
else
{
t1++;
t2++;
}
}
}
return true;
}
int main()
{
initgraph(200, 200);
addnum(2); //在随机2个位置添加新数
ShowInfo();
for ( ; is_run(); delay_fps(60) )
{
//cleardevice();
// todo: 逻辑更新(数据更新)
//按键检测
while(kbmsg())
{
key_msg keyMsg = getkey();
if(keyMsg.msg == key_msg_down)
{
switch(keyMsg.key)
{
case 'A':case key_left
: dir = 0; break;//左
case 'W':case key_up
: dir = 1; break;//上
case 'D':case key_right : dir = 2; break;//右
case 'S':case key_down : dir = 3; break;//下
}
}
}
// todo: 图形更新
if(dir!=-1)
{
system("cls");
switch(dir)
{
case
0: cout << "按下了 A/左 键" << endl; break;//左
case
1: cout << "按下了 W/上 键" << endl; break;//上
case
2: cout << "按下了 D/右 键" << endl; break;//右
case
3: cout << "按下了 S/下 键" << endl; break;//下
}
bool flag = false;
//移动标志位
int tempGrid[4][4];
//暂存数组
int i,j;
for(i=0;i<4;i++)
for(j=0;j<4;j++)
tempGrid[i][j] = grid[i][j];
{
//cout << "tempGrid[4][4] = " << endl;
//
for(i=0; i<4; i++)
//
{
//
for(j=0; j<4; j++)
//
cout << tempGrid[i][j] << " ";
//
cout << endl;
//
}
//
cout << endl;
}
Move(dir);
//比较
for(i=0; i<4; i++)
for(j=0; j<4; j++)
if(grid[i][j]!=tempGrid[i][j])
{
flag = true;
break;
}
if(flag)
{
cout << "有效移动" << endl;
addnum(1);
}
else cout << "无效移动" << endl;
ShowInfo();
dir = -1;//将 dir 置为无效,否则控制台会一直刷新
}
if(gameOver())
{
cout << "Game Over!" << endl;
break;
}
}
getch();
closegraph();
return 0;
}
五、测试
基础部分结语
这下子基础部分终于写完了。
本来以为上一篇就写完了“基础”部分,后来写优化篇的时候,要放GameOver
的照片,发现还有结束逻辑没写。。。
OK,小结一下几个部分吧,都是按照总体流程图来的:
- 移动逻辑
- 键盘输入控制
- 添加新数字
- 检测结束
PS:没想到写博客这么累,不过我会坚持下去的,加油!
接下来节奏稍微放缓一些,不过也会保持一周一更。
优化篇(暂定):
- 将数字用图形替代
- 加入计分
- 类封装
最后
以上就是清秀小霸王为你收集整理的【C++】2048游戏系列---功能模块第四稿【结束检测】一、结束的大前提二、检测思路三、添加位置四、全部代码五、测试基础部分结语的全部内容,希望文章能够帮你解决【C++】2048游戏系列---功能模块第四稿【结束检测】一、结束的大前提二、检测思路三、添加位置四、全部代码五、测试基础部分结语所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复