(更新中……)
参考博客:https://blog.csdn.net/qq_39151563/article/details/104283217
由于放在一篇会导致篇幅太长,所以分成了几篇。
(可能有个10篇吧=.=)
前一篇:2048游戏系列—总览篇
本篇介绍如何根据 dir 的值对 grid 进行操作。
各模块的实现
根据流程图可以把其分为以下几个模块:
- 1-根据 dir 的值对 grid 进行操作(本稿实现部分)
- 2-键盘输入
- 3-在随机位置添加数值
- 4-游戏结束检测
##1-根据 dir 的值对 grid 进行操作
-
(1) 根据 dir 的值对 grid 进行遍历
假想我们要对以下左边矩阵进行向左滑(dir=0)的操作,矩阵会变成右边的样子
{{0,1,2,3}, {{1,2,3,0},
{0,1,2,3}, {1,2,3,0},
{0,1,2,3}, {1,2,3,0},
{0,1,2,3},}; {1,2,3,0},};
我们遍历的起点 (x0,y0) 是(0,0),同理,向上滑,向左滑, 向下滑的遍历起点分别是(0,0)、(3,0)、(0,3)
把 x0 , y0 的值分开存储,另外,我们定义两组偏转数组(具体解释如图):
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}};
具体代码如下(承接上一篇博客代码):
#include <iostream>
using namespace std;
int grid[4][4] = {
{0,1,2,3},
{0,1,2,3},
{0,1,2,3},
{0,1,2,3}
};
int EmptyBlock = 16;
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;
}
int dir;
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)
{
int tx, ty;
for(int i=0; i<4; i++)
{
tx = x0[dir] + i*secondOffset[dir][0];
ty = y0[dir] + i*secondOffset[dir][1];
for(int j=0; j<4; j++)
{
cout << "(" << tx << ", " << ty << ")" << "\t";
tx += firstOffset[dir][0];
ty += firstOffset[dir][1];
}
cout << endl;
}
}
int main(){
PrintGrid();
cout<< "EmptyBlock = " << CalculateEmpty() << endl;
Move(0);
return 0;
}
上面是运行结果,也可以试试把 dir 改为 1、2、3,分别对应着相应方向的遍历顺序
-
(2)遍历的时候,利用前后指针比较进行相应操作
在上面第二个循环中,(tx,ty)值的遍历代表 grid 的一行或一列,移动合并等操作在逻辑上可以降为一维
我们另外建立一个 test 程序来说明一维数组中的合并移动:
arr[10] = {0,1,1,2,3,3,1,1,0,0};
合并移动之后变为:
arr[10] = {2,2,6,2,0,0,0,0,0,0};
逻辑如图:
#include <iostream> using namespace std; int arr[10] = {0,1,1,2,3,3,1,1,0,0}; void Print() { for(int i=0; i<10; i++) cout << arr[i] << " "; cout << endl; } void Merge() { int left, right; for(left=0,right=1; right<10; right++) { if(arr[right]!=0)//找到一个非空格子 { if(arr[left]==0)//left 是空格,right值前移至空格 { arr[left] = arr[right]; arr[right] = 0; } else if(arr[left]==arr[right])//两个相同,合并 { arr[left] *= 2; arr[right] = 0; left++; } else if(left+1 != right)//两数不同,中间有空格,移动至left下一个空格 { arr[left+1] = arr[right]; arr[right] = 0; left++; } else//最后的情况是两个数不同,并且相邻,不移动 { left++; } } } } int main() { Print(); Merge(); Print(); return 0; }
输出结果:
现在将逻辑改到二维数组的遍历中:
一维数组arr 二维数组grid 初始化 left=0;right=1 t1x = tx;
t1y = ty;
t2x = tx + firstOffset[dir][0];
t2y = ty + firstOffset[dir][1];移向下一个 left++
(right++)t1x += firstOffset[dir][0];
t1y += firstOffset[dir][1];
(t2x += firstOffset[dir][0];
t2y += firstOffset[dir][1])所指向的值是否相等 arr[left]==arr[right] grid[t1y][t1x]==grid[t2y][t2x] 合并 arr[left] *=2;
arr[right]=0grid[t1y][t1x]++;
(没有乘2是与图片的存储有关)
grid[t2y][t2x] = 0具体代码如下:
#include <iostream> using namespace std; int grid[4][4] = { {0,1,2,3}, {0,1,2,3}, {0,1,2,3}, {0,1,2,3} }; int EmptyBlock = 16; 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; } int dir; 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) { 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; } else if(grid[t1y][t1x]==grid[t2y][t2x]) { grid[t1y][t1x]++; grid[t2y][t2x] = 0; t1x += firstOffset[dir][0]; t1y += firstOffset[dir][1]; } 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]; } else { t1x += firstOffset[dir][0]; t1y += firstOffset[dir][1]; } } } } } int main() { int dir = 0; cout<< "EmptyBlock = " << CalculateEmpty() << endl; PrintGrid(); Move(dir); cout<< "EmptyBlock = " << CalculateEmpty() << endl; PrintGrid(); return 0; }
dir = 0, 模拟向左滑动结果如下:
改变 dir 的值为1,2,3可以得到相应的结果(一定要试试哦)。
很好,到此,我们已经能根据 dir 的值对 grid 进行操作。
!移动合并逻辑是这个游戏编程的核心,本篇有很多的逻辑跳点,希望大家能够理解到位。
下一篇是功能模块之二:2048游戏系列—功能模块第二稿【键盘输入】
这个主要与EGE库的函数语法相关,建议看看
这位博主关于EGE库的教程:https://blog.csdn.net/qq_39151563;
还有EGE官网的教程:https://xege.org/manual/index.htm