C语言游戏开发之消消乐2
在上一章中,小编主要介绍了游戏编程的思路,以及游戏界面的代码实现。
本章,小编将介绍游戏的具体过程的编程,这也是整个程序的核心所在。
话不多说,我们接着上章的内容开始吧~
4、游戏的具体过程
1)通过方向键控制光标的上下左右移动
在按键监听方面,需要在前面添加:
#define KEY_DOWN(vk_c)(GetAsyncKeyState(vk_c)&0x8000)
编程思路:由于easyx没有类似于擦除的函数,所以可以先在当前白色光标位置处绘制黑色光标,再移动光标位置,最后绘制白色光标,就像电影放映一帧帧图片一样,有一种动态的效果。
drawcursor(cur,BLACK);//绘制黑光标
cur.x-=40;//移动当前光标位置
drawcursor(cur,WHITE);//绘制白光标
其次还要注意光标移动不能超出边界,否则会出现看不到光标的现象
编程如下:
if(KEY_DOWN(VK_UP)&&cur.y>70)
{
drawcursor(cur,BLACK);//绘制黑光标
cur.y-=40;//移动当前光标位置
drawcursor(cur,WHITE);//绘制白光标
}
else if(KEY_DOWN(VK_DOWN)&&cur.y<630)
{
drawcursor(cur,BLACK);//绘制黑光标
cur.y+=40;//移动当前光标位置
drawcursor(cur,WHITE);//绘制白光标
}
else if(KEY_DOWN(VK_LEFT)&&cur.x>280)
{
drawcursor(cur,BLACK);//绘制黑光标
cur.x-=40;//移动当前光标位置
drawcursor(cur,WHITE);//绘制白光标
}
else if(KEY_DOWN(VK_RIGHT)&&cur.x<720)
{
drawcursor(cur,BLACK);//绘制黑光标
cur.x+=40;//移动当前光标位置
drawcursor(cur,WHITE);//绘制白光标
}
else if(KEY_DOWN(VK_RETURN)||KEY_DOWN(VK_SPACE))
{
//小球消失
}
编译运行后,没有反应,这是由于程序运行快的原因,还没有等我们按下键的时候,程序已经运行完gameplay()函数,因此也就没有监听到按键状态。为此,我们在以上程序段添加一个while(1)循环,使得程序一直处于按键监听状态。
但当你按下上下左右任意方向键的时候,光标都会瞬间到达边框的上下左右端,这是什么原因呢?
按键前光标位置 按键后光标位置在我们添加的宏定义中,按键监听的是按键的状态,即按键是否按下,只要是按下的状态就为真(1),否则为假(0)。而计算机运行程序的速度可快,可能只需几毫秒,而我们按键的时间可能会持续几十毫秒,所以如果你按向上键,就会在几十毫秒的时间里运行好多次,这自然不是我们期望的效果。那么,如何解决呢?
只需在while循环内部添加:Sleep()函数即可,相当于延时函数。这里我们这样写
:Sleep(100);
2)小球消失
这里,我们可以再把动作分解:
首先获得光标所在位置周围的同色小球,计算同色小球的个数,并存入数组;
其次让同色小球消失一段时间(将数组中元素置黑);
最后小球下落,补充新小球。
为计算同色小球个数,先定义一个全局变量:int index;然后再定义一个存放同色小球坐标的数组:int ballsArr[180];
先写将数组元素置黑的程序段,这个和之前写光标的程序段类似:
if (index>1){//同色小球个数大于1
for(int k=0;k<index;k++)
{
setlinecolor(BLACK);
setfillcolor(BLACK);
fillcircle(ballsArr[k].x,ballsArr[k].y,18);
}
}
现在我们再来写获得光标所在位置周围的同色小球,计算同色小球的个数,并存入数组的程序段:
我们将其写成函数的形式,其调用形式为:
getsamecolorballs(cur,getpixel(cur.x,cur.y));
这里的getpixel()函数的功能为获取所在位置的颜色~
下面,我们来写getsamecolorballs()函数,其思路大致是先判断当前光标所在位置小球的上下左右的小球颜色是否与之相同,若相同再判断那个小球周围的小球颜色,依次类推:
void getsamecolorballs(posType cur,COLORREF c1)
{ //将当前光标的位置坐标存入数组
ballsArr[index].x=cur.x;
ballsArr[index].y=cur.y;
index++;//同色小球个数加1
posType UP;
UP.x=cur.x;
UP.y=cur.y-40;
if(getpixel(UP.x,UP.y)==c1)
{
ballsArr[index].x=UP.x;
ballsArr[index].y=UP.y;
index++;
posType UP1;
UP1.x=UP.x;
UP1.y=UP.y-40;
if(getpixel(UP1.x,UP1.y)==c1)
{
ballsArr[index].x=UP1.x;
ballsArr[index].y=UP1.y;
index++;
...
}
posType DOWN;
DOWN.x=cur.x;
DOWN.y=cur.y+40;
if(getpixel(DOWN.x,DOWN.y)==c1)
{
ballsArr[index].x=DOWN.x;
ballsArr[index].y=DOWN.y;
index++;
…
}
…
}
可以看出来这是一个递归,我们换种方式来写程序段:
void getsamecolorballs(posType cur,COLORREF c1)
{
ballsArr[index].x=cur.x;
ballsArr[index].y=cur.y;
index++;
posType tempos;
//存放光标移动后的位置坐标
for(int k=0;k<4;k++)//依次判断上下左右小 球的颜色是否相同
{
switch(k){
case 0:tempos.x=cur.x;tempos.y=cur.y- 40;break;//上
case 1:tempos.x=cur.x;tempos.y=
cur.y+40;break;//下
case 2:tempos.x=cur.x-40;
tempos.y=cur.y;break;//左
case 3:tempos.x=cur.x+40;tempos.y=
cur.y;break;//右
}
if(getpixel(tempos.x,tempos.y)==c1)
//如果颜色相同,则再次调用 getsamecolorballs()函数
{
getsamecolorballs(tempos,c1);//将tempos作为当前光标位置,再次判断
}
}
}
编译运行后,程序再次出现bug,程序卡死了,你的心情正如程序一样,崩溃了~
出现这种情况,也很正常,死循环呗~
不要着急,你的问题,我来解决~
这是由于我们的没有写递归结束条件。比如,相邻的两个同色小球,选取其中一个判断周围是否有同色小球,会跳转到另外一个再次判断,如此循环下去……
找到问题所在,那么修改原来的函数调用自身的if语句的条件,就可以了~
为此,写一个判断同色小球是否合法的函数——
int isValid(posType cur,COLORREF c1)
{
if(getpixel(cur.x,cur.y)!=c1)
{
return 0;//颜色不同
}
else
{
for(int k=0;k<index;k++)//同色小球坐标已存入数组中
{
if(ballsArr[k].x==cur.x&&ballsArr[k].y==cur.y)
{
return 0;
}
}
return 1;//同色小球坐标未存入数组中
}
}
原来的程序段可以这样修改:
if(isValid(tempos,c1))
{
getsamecolorballs(tempos,c1);//将tempos作为当前光标位置,再次判断
}
按键前 按键后,同色小球消失这样,编译运行后,达到了我们预期的效果~
项目做到这里,是不是挺有成就感的,别急,我们还差小球下落的部分。这部分内容,对于新手来说,的确有些难度。
本章主要介绍了如何通过键盘上的方向键控制光标的移动、如何获取同色小球并让其消失一段时间,在下一章,小编会出详细的教程,解决小球下落以及时间与分数的刷新等,并附上消消乐的源码。希望广大读者批评指正,谢谢!
链接: C语言游戏开发之消消乐1