、构造蛇身:定义一个坐标数组,存放的是蛇的每一节蛇身所在的坐标位置。这样就将移动蛇身的操作转换为移动数组的操作,将吃食物增加蛇身体长度的操作转换为在数组后面追加元素的操作。
、移动效果:每次移动时,将每一节蛇身(蛇头除外)依次往前移动一节,然后擦去蛇的最后一节,最后确定蛇头的方向,再绘制一个蛇头。这样就会显示一个移动效果。
3、身体增加效果:每次移动时候,判断蛇头是否碰到了食物,如果碰到了食物,则吃掉它,并且只进行前移蛇身和增加蛇头的操作,不进行擦除蛇尾的操作(可以用一个标记变量判断是否吃掉了食物,然后在擦除蛇尾那里判断是否需要擦除蛇尾),这就会显示蛇身体增加的效果。
预备知识控制台窗口控制台窗口每一个位置都有它的坐标,且坐标系如下图所示,随箭头方向坐标逐渐增大。
通过代码将光标移动到控制台指定位置这里用到了c语言windows编程中句柄的概念,不知道的可以百度。实在不会也没关系,可以当做一个函数模板来使用,无需做太多了解。
#includestdio.h#includeWindows.h//将光标移动到控制台的(x,y)坐标点处voidgotoxy(intx,inty){COORDcoord;coord.X=x;coord.Y=y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);}intmain(){gotoxy(50,5);//将光标移动到控制台的(50,5)处printf("HelloWorld\n");system("pause");return0;}
从运行结果可以看到,程序在指定位置输出了待输出的内容。
程序框架定义相关头文件
定义函数结构以及相关属性
完成各代码块
具体操作定义相关头文件本程序所用到的头文件如下所示:
#includestdio.h#includestdlib.h#includeWindows.h//windows编程头文件#includetime.h#includeconio.h//控制台输入输出头文件定义函数结构以及相关属性
首先需要确定游戏的边框大小:
#defineSNAKESIZE00//蛇的身体最大节数#defineMAPWIDTH8//宽度#defineMAPHEIGHT9//高度
其次要定义食物的坐标,以及蛇自身的相关属性:
//食物的坐标struct{intx;inty;}food;//蛇的相关属性struct{intspeed;//蛇移动的速度intlen;//蛇的长度intx[SNAKESIZE];//组成蛇身的每一个小方块中x的坐标inty[SNAKESIZE];//组成蛇身的每一个小方块中y的坐标}snake;
这里蛇的身体由一节一节的小方块■组成,将蛇的身体每一节的小方块所在的位置用一个数组来存储起来,方便以后操作。
确定游戏所用到的几个函数块
//绘制游戏边框voiddrawMap();//随机生成食物voidcreateFood();//按键操作voidkeyDown();//蛇的状态boolsnakeStatus();//从控制台移动光标voidgotoxy(intx,inty);
定义几个全局变量
intkey=7;//表示蛇移动的方向,7为按下“↑”所代表的数字//用来判断蛇是否吃掉了食物,这一步很重要,涉及到是否会有蛇身移动的效果以及蛇身增长的效果intchangeFlag=0;intsorce=0;//记录玩家的得分完成各代码块实现将光标移到指定位置的操作
//将控制台光标移到(x,y)处voidgotoxy(intx,inty){COORDcoord;coord.X=x;coord.Y=y;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);}打印游戏边框以及游戏初始画面
一个小方块字符■在x方向上占用两个位置,在y方向上占用一个位置。每一节蛇身由一个小方块构成。
voiddrawMap(){//打印上下边框for(inti=0;i=MAPWIDTH;i+=)//i+=是因为横向占用的是两个位置{//将光标移动依次到(i,0)处打印上边框gotoxy(i,0);printf("■");//将光标移动依次到(i,MAPHEIGHT)处打印下边框gotoxy(i,MAPHEIGHT);printf("■");}//打印左右边框for(inti=;iMAPHEIGHT;i++){//将光标移动依次到(0,i)处打印左边框gotoxy(0,i);printf("■");//将光标移动依次到(MAPWIDTH,i)处打印左边框gotoxy(MAPWIDTH,i);printf("■");}//随机生成初试食物while(){srand((unsignedint)time(NULL));food.x=rand()%(MAPWIDTH-4)+;food.y=rand()%(MAPHEIGHT-)+;//生成的食物横坐标的奇偶必须和初试时蛇头所在坐标的奇偶一致,因为一个字符占两个字节位置,若不一致//会导致吃食物的时候只吃到一半if(food.x%==0)break;}//将光标移到食物的坐标处打印食物gotoxy(food.x,food.y);printf("★");//初始化蛇的属性snake.len=3;snake.speed=00;//在屏幕中间生成蛇头snake.x[0]=MAPWIDTH/+;//x坐标为偶数snake.y[0]=MAPHEIGHT/;//打印蛇头gotoxy(snake.x[0],snake.y[0]);printf("■");//生成初试的蛇身for(inti=;isnake.len;i++){//蛇身的打印,纵坐标不变,横坐标为上一节蛇身的坐标值+snake.x=snake.x[i-]+;snake.y=snake.y[i-];gotoxy(snake.x,snake.y);printf("■");}//打印完蛇身后将光标移到屏幕最上方,避免光标在蛇身处一直闪烁gotoxy(MAPWIDTH-,0);return;}编写按键操作的代码
voidkeyDown(){intpre_key=key;//记录前一个按键的方向if(_kbhit())//如果用户按下了键盘中的某个键{fflush(stdin);//清空缓冲区的字符//getch()读取方向键的时候,会返回两次,第一次调用返回0或者4,第二次调用返回的才是实际值key=_getch();//第一次调用返回的不是实际值key=_getch();//第二次调用返回实际值}/**蛇移动时候先擦去蛇尾的一节*changeFlag为0表明此时没有吃到食物,因此每走一步就要擦除掉蛇尾,以此营造一个移动的效果*为表明吃到了食物,就不需要擦除蛇尾,以此营造一个蛇身增长的效果*/if(changeFlag==0){gotoxy(snake.x[snake.len-],snake.y[snake.len-]);printf("");//在蛇尾处输出空格即擦去蛇尾}//将蛇的每一节依次向前移动一节(蛇头除外)for(inti=snake.len-;i0;i--){snake.x=snake.x[i-];snake.y=snake.y[i-];}//蛇当前移动的方向不能和前一次的方向相反,比如蛇往左走的时候不能直接按右键往右走//如果当前移动方向和前一次方向相反的话,把当前移动的方向改为前一次的方向if(pre_key==7key==80)key=7;if(pre_key==80key==7)key=80;if(pre_key==75key==77)key=75;if(pre_key==77key==75)key=77;/***控制台按键所代表的数字*“↑”:7*“↓”:80*“←”:75*“→”:77*///判断蛇头应该往哪个方向移动switch(key){case75:snake.x[0]-=;//往左break;case77:snake.x[0]+=;//往右break;case7:snake.y[0]--;//往上break;case80:snake.y[0]++;//往下break;}//打印出蛇头gotoxy(snake.x[0],snake.y[0]);printf("■");gotoxy(MAPWIDTH-,0);//由于目前没有吃到食物,changFlag值为0changeFlag=0;return;}实现生成食物的代码
voidcreateFood(){if(snake.x[0]==food.xsnake.y[0]==food.y)//蛇头碰到食物{//蛇头碰到食物即为要吃掉这个食物了,因此需要再次生成一个食物while(){intflag=;srand((unsignedint)time(NULL));food.x=rand()%(MAPWIDTH-4)+;food.y=rand()%(MAPHEIGHT-)+;//随机生成的食物不能在蛇的身体上for(inti=0;isnake.len;i++){if(snake.x==food.xsnake.y==food.y){flag=0;break;}}//随机生成的食物不能横坐标为奇数,也不能在蛇身,否则重新生成if(flagfood.x%==0)break;}//绘制食物gotoxy(food.x,food.y);printf("★");snake.len++;//吃到食物,蛇身长度加sorce+=0;//每个食物得0分snake.speed-=5;//随着吃的食物越来越多,速度会越来越快changeFlag=;//很重要,因为吃到了食物,就不用再擦除蛇尾的那一节,以此来造成蛇身体增长的效果}return;}判断蛇运动是否符合规范
boolsnakeStatus(){//蛇头碰到上下边界,游戏结束if(snake.y[0]==0
snake.y[0]==MAPHEIGHT)returnfalse;//蛇头碰到左右边界,游戏结束if(snake.x[0]==0
snake.x[0]==MAPWIDTH)returnfalse;//蛇头碰到蛇身,游戏结束for(inti=;isnake.len;i++){if(snake.x==snake.x[0]snake.y==snake.y[0])returnfalse;}returntrue;}main函数
intmain(){drawMap();while(){keyDown();if(!snakeStatus())break;createFood();Sleep(snake.speed);}gotoxy(MAPWIDTH/,MAPHEIGHT/);printf("GameOver!\n");gotoxy(MAPWIDTH/,MAPHEIGHT/+);printf("本次游戏得分为:%d\n",sorce);Sleep();return0;}运行效果图预览时标签不可点收录于话题#个上一篇下一篇