2048作为一个经典的小游戏,对于C语言的逻辑练习是一个比较好的案例了,看似很复杂,但是如果掌握了设计思路,那么就不会觉得难了,而且会了这个之后对今后编程的也会有很大的帮助。
先分析游戏逻辑,游戏其实很简单,一共16个格子,开局两个有数字的方块,2或者4,然后通过控制方向来使得原有的方块移动并且产生新的方块,
一种是方块移动的方向没有其他方块
一种是方块移动的方向已经有了方块,但是数字不一样
还有一种就是方块移动的方向已经有了方块,数字一样。
我认为代码其实就分为两个部分,一个是初始化,一个是移动过程。
初始化部分的话先建一个二维数组,存储16个方块的值,接下来分为两个步骤,生成第一个方块和生成第二个方块
生成第一个方块的话其实就很简单,0-15随机生成一个值,生成的值就代表第几个方块的值为2,其余值都为0
void set_value1()
{
unsigned int i, j;
int n,a;
srand((unsigned int)time(0));//加入time,使得每次随机值都不一样
n = rand()%16;
for(i = 0; i < 4; i++)
{
for(j = 0; j < 4; j++)
{
nub[i][j] = n == 0 ? 2 : 0;//如果n的值等于0,那么就给nub[i][j]值赋2,否则0
n--;
}
}
}
那么第一个方块的值便给好了,但是问题来了,第二块方块的值你不能再用这种方法,因为如果生成的值一样,那么方块就重合了。而且不止是第二个方块的值不能这样生成,后续所有方块的值都不能这样生成。这个时候就必须使用另一种方法。
先获取16个格子空格的个数,也就是二维数组里面值为0的个数
int get_null_count()
{
unsigned int i, j;
unsigned int n = 0;
for(i = 0; i < 4; i++)
{
for(j = 0; j < 4; j++)
{
if(nub[i][j] == 0)
n++;
}
}
return n;
}
获取了空格的个数就可以确定循环的次数,并且判断nub[i][j]的值,如果不等于0就说明有方块了,跳过,这里使用的是逻辑与,如果nub[i][j] == 0不成立的话便不会执行n--了,这样确保遍历每一个空格,需要注意的是根据游戏机制,2和4的生成概率是不一样的,所以通过生成随机值的方式来判断是生成2还是4,在0-10之间,如果随机值为0便生成2,否则生成4,这样生成2和4的概率便为10:1。
void set_value2()
{
unsigned int i, j , n = 0;;
srand((unsigned int)time(0));
n = rand()%get_null_count();
for(i = 0; i < 4; i++)
{
for(j = 0; j < 4; j++)
{
if(nub[i][j] == 0 && n-- == 0)
{
nub[i][j] = rand()%10 == 0 ? 4 : 2;
}
}
}
}
至此,第一部分便完成了。
移动过程其实就是通过输入方向来控制方块的移动,并产生新的方块。
先获取输入状态
void move()
{
switch(key_in)
{
case 1:move_left();
break;
case 2:move_up();
break;
case 3:move_right();
break;
case 4:move_down();
break;
default :break;
}
}
接着具体来看移动的控制的逻辑,拿向左移动为例,首先还是遍历二维数组,找到每一个方块,由于我这里是向左移动,由于最左边的方块是不需要移动的,所以从每一行的第二个方块开始,先移动第二个方块,再第三个,第四个,依次移动,如果此方块左边没有方块,那么交换值,并且原来位置值清0,如果此方块左边的方块和此方块值相同,那么左边的值变为原来的2倍,原来位置值清0。如果左边的值和原来值不同,那么便不做处理,不移动。
void move_left()
{
int i, j , k, n = 0;
for(i = 0; i < 4; i++)
{
for(j = 1; j < 4; j++)
{
if(nub[i][j] > 0)//找到方块
{
for(k = j - 1; k > -1; k--)//根据位置判断最大移动次数,决定循环次数
{
if(nub[i][k] == 0)//如果左边没有方块
{
nub[i][k] = nub[i][k+1];
nub[i][k+1] = 0;
}
else if(nub[i][k] == nub[i][k+1])//如果左边的方块等于这个方块的值
{
nub[i][k] = nub[i][k+1]*2;
nub[i][k+1] = 0;
}
}
}
}
}
}
明白向左移动的逻辑后,其他的方向也是这个道理
void move_left()
{
int i, j , k, n = 0;
for(i = 0; i < 4; i++)
{
for(j = 1; j < 4; j++)
{
if(nub[i][j] > 0)
{
for(k = j - 1; k > -1; k--)
{
if(nub[i][k] == 0)
{
nub[i][k] = nub[i][k+1];
nub[i][k+1] = 0;
}
else if(nub[i][k] == nub[i][k+1])
{
nub[i][k] = nub[i][k+1]*2;
nub[i][k+1] = 0;
}
}
}
}
}
}
void move_up()
{
int i, j , k, n = 0;
for(i = 1; i < 4; i++)
{
for(j = 0; j < 4; j++)
{
if(nub[i][j] > 0)
{
for(k = i - 1; k > -1; k--)
{
if(nub[k][j] == 0)
{
nub[k][j] = nub[k+1][j];
nub[k+1][j] = 0;
}
else if(nub[k][j] == nub[k+1][j])
{
nub[k][j] = nub[k+1][j] * 2;
nub[k+1][j] = 0;
}
}
}
}
}
}
void move_right()
{
int i, j , k, n = 0;
for(i = 0; i < 4; i++)
{
for(j = 2; j > -1; j--)
{
if(nub[i][j] > 0)
{
for(k = j + 1; k < 4; k++)
{
if(nub[i][k] == 0)
{
nub[i][k] = nub[i][k-1];
nub[i][k-1] = 0;
}
else if(nub[i][k] == nub[i][k-1])
{
nub[i][k] = nub[i][k-1]*2;
nub[i][k-1] = 0;
}
}
}
}
}
}
void move_down()
{
int i, j , k, n = 0;
for(i = 2; i > -1; i--)
{
for(j = 0; j < 4; j++)
{
if(nub[i][j] > 0)
{
for(k = i + 1; k < 4; k++)
{
if(nub[k][j] == 0)
{
nub[k][j] = nub[k-1][j];
nub[k-1][j] = 0;
}
else if(nub[k][j] == nub[k-1][j])
{
nub[k][j] = nub[k-1][j] * 2;
nub[k-1][j] = 0;
}
}
}
}
}
}
最后在每次移动过后再生成一个新的方块,至此,移动过程部分也完成了,整个游戏大致框架便完成了。
由于开发平台不一致,剩下的细节可能不太一样,但是只要能明白这个思路,那么便能很快的完成这个游戏,希望这篇文章能对大家有所帮助。