200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > C语言实现彩色版贪吃蛇(详细代码及思路讲解)

C语言实现彩色版贪吃蛇(详细代码及思路讲解)

时间:2020-03-10 18:29:26

相关推荐

C语言实现彩色版贪吃蛇(详细代码及思路讲解)

本人是机械专业学生,学完C语言后就考了一个二级,没有像软件学院那样有一个实习,所以决定做几个项目锻炼一下自己,这个贪吃蛇是最简单的一个项目。

我原先在网上查看了一些做好的贪吃蛇,可以运行起来,但是做的很粗糙,而那些界面精美一点的都用到了图形库,我觉得太麻烦了。这个代码用到了一点Windows编程的东西,没有用到图形库,实现起来也不复杂,界面也说的过去,如下图:

下面是这个程序的源码(写了7个多小时),具体的函数有哪些作用下面都有:

#include <stdio.h>#include <windows.h>#include <conio.h>#include <malloc.h>#include <time.h>#include <stdlib.h>void setmouth(int x, int y);//设置光标void background();//背景生成void setcolour(int a);//设置颜色void init();//初始化void hidemouth();//隐藏光标void startfood();//初始创建食物void startsnack();//初始创建小蛇void snackmove(int,int);//小蛇移动int checksnack(int);//小蛇碰撞检测void snackdie();//小蛇死亡void showing();//输出最新的showvoid screenRefresh(int);//屏幕刷新void newfood();//创建新食物void updategoal();//更新得分int movedire(int,int);//获取小蛇的移动方向int snacklength = 3;//小蛇长度int snackhead=2;//蛇头int snacktail=0;//蛇尾int MaxLine = 40, MaxLie = 40;//定义最大行数,列数//结构体保存各个事物的属性struct map {int colour;int kind;char *display;}show[40][40], //展示地图wall = { 0x6C,1,"■" },//墙体livearea = { 0x7F,2,"□" },//小蛇活动区域food = { 0x7C,3,"★" },//食物snack = { 0x7A,4,"●" };//小蛇蛇体的属性struct SnackMap{int x;int y;}SnackSite[100],FoodSite;/***************************************主程序****************************************/int main(){int olddirection='w'; //初始键盘信号int newdirection =0;//获取键盘信号init();//初始化setmouth(60, 0);setcolour(0xF0);printf("\n得分:");printf("%d\n", snacklength - 3);printf("请切换为英文输入法\n");printf("W A S D键分别表示:上 左 下 右\n");printf("Copyright [.9.9] by [松鼠君] ");while (1) {if (_kbhit()) { //检测缓冲区中是否有数据newdirection = tolower(_getch()); //将缓冲区中的数据以字符的形式读出if (newdirection == 27) {break;}else {//获取小蛇新的移动方向newdirection=movedire(olddirection, newdirection);if (newdirection != olddirection){olddirection = newdirection;}}}screenRefresh(newdirection);Sleep(10);}return 0;}//更新得分void updategoal(){setcolour(0xF0);setmouth(60, 0);printf("\n得分:%d", snacklength - 3);}//碰撞检测int checksnack(int newdirection){switch (newdirection){case 'w':if ((show[SnackSite[snackhead].x - 1][SnackSite[snackhead].y].kind)==1){snackdie();return 0;}else if((show[SnackSite[snackhead].x - 1][SnackSite[snackhead].y].kind) == 4){snackdie();return 0;}else if ((show[SnackSite[snackhead].x - 1][SnackSite[snackhead].y].kind) == 3){return 1;}else {return 2;}break;case 's':if ((show[SnackSite[snackhead].x + 1][SnackSite[snackhead].y].kind) == 1){snackdie();return 0;}else if ((show[SnackSite[snackhead].x + 1][SnackSite[snackhead].y].kind) == 4){snackdie();return 0;}else if ((show[SnackSite[snackhead].x + 1][SnackSite[snackhead].y].kind) == 3){return 1;}else {return 2;}break;case 'a':if ((show[SnackSite[snackhead].x][SnackSite[snackhead].y-1].kind) == 1){snackdie();return 0;}else if ((show[SnackSite[snackhead].x][SnackSite[snackhead].y-1].kind) == 4){snackdie();return 0;}else if ((show[SnackSite[snackhead].x][SnackSite[snackhead].y-1].kind) == 3){return 1;}else {return 2;}break;case 'd':if ((show[SnackSite[snackhead].x][SnackSite[snackhead].y+1].kind) == 1){snackdie();return 0;}else if ((show[SnackSite[snackhead].x][SnackSite[snackhead].y+1].kind) == 4){snackdie();return 0;}else if ((show[SnackSite[snackhead].x][SnackSite[snackhead].y+1].kind) == 3){return 1;}else {return 2;}break;}}//创建新食物void newfood(){srand((unsigned)time(NULL));FoodSite.x = rand() % 38 + 1;FoodSite.y = rand() % 38 + 1;}//刷新屏幕void screenRefresh(int newdirection){int re = 0;int i = 0;re = checksnack(newdirection);snackmove(newdirection, re);background();show[FoodSite.x][FoodSite.y] = food;for (i = 0; i <= snackhead; i++){if (i == snackhead) {show[SnackSite[i].x][SnackSite[i].y] = snack;show[SnackSite[i].x][SnackSite[i].y].colour = 0x75;}else {show[SnackSite[i].x][SnackSite[i].y] = snack;}}showing();if (re == 1){snacklength++;updategoal();newfood();}}/*********************************************获取最新的方向**********************************************/int movedire(int olddirection, int newdirection){if (newdirection == 'w' || newdirection == 'a' || newdirection == 's' || newdirection == 'd'){return newdirection;}else {return olddirection;}}/**********************************展示最新的show*********************************/void showing(){int line, lie;for (line = 0; line < MaxLine; line++){for (lie = 0; lie < MaxLie; lie++){setmouth(line, lie);setcolour(show[line][lie].colour);printf("%s",show[line][lie].display);}}}/******************************************小蛇死亡*******************************************/void snackdie(){setmouth(20, 5);printf("Game over! 按任意键结束游戏!");Sleep(5000);_getch();exit(0);}//小蛇移动void snackmove(int newdirection,int re){int i = 0;switch (newdirection){case 'w':for (i = 0; i < snackhead;i++) {SnackSite[i].x = SnackSite[i + 1].x;SnackSite[i].y = SnackSite[i + 1].y;}SnackSite[snackhead].x -= 1;if (re == 1){snackhead += 1;SnackSite[snackhead].x = SnackSite[snackhead-1].x-1;SnackSite[snackhead].y = SnackSite[snackhead - 1].y;}break;case 's':for (i = 0; i < snackhead; i++) {SnackSite[i].x = SnackSite[i + 1].x;SnackSite[i].y = SnackSite[i + 1].y;}SnackSite[snackhead].x += 1;if (re == 1){snackhead += 1;SnackSite[snackhead].x = SnackSite[snackhead - 1].x + 1;SnackSite[snackhead].y = SnackSite[snackhead - 1].y;}break;case 'a':for (i = 0; i < snackhead; i++) {SnackSite[i].x = SnackSite[i + 1].x;SnackSite[i].y = SnackSite[i + 1].y;}SnackSite[snackhead].y -= 1;if (re == 1){snackhead += 1;SnackSite[snackhead].x = SnackSite[snackhead - 1].x ;SnackSite[snackhead].y = SnackSite[snackhead - 1].y-1;}break;case 'd':for (i = 0; i < snackhead; i++) {SnackSite[i].x = SnackSite[i + 1].x;SnackSite[i].y = SnackSite[i + 1].y;}SnackSite[snackhead].y += 1;if (re == 1){snackhead += 1;SnackSite[snackhead].x = SnackSite[snackhead - 1].x;SnackSite[snackhead].y = SnackSite[snackhead - 1].y+1;}break;}}//初始食物void startfood(){FoodSite.x = 5;FoodSite.y = 10;show[5][10] = food;}//初始小蛇void startsnack(){SnackSite[0].x = 35;SnackSite[0].y = 13;SnackSite[1].x = 35;SnackSite[1].y = 12;SnackSite[2].x = 35;SnackSite[2].y = 11;show[35][11] = snack;show[35][11].colour = 0x75;show[35][12] = snack;show[35][13] = snack;}/*******************************初始化生成show结构体数组*******************************/void init(){//设置窗口大小system("mode con:cols=140 lines=50");//隐藏光标hidemouth();//生成背景图background();//创建初始食物startfood();//创建初始小蛇蛇体startsnack();//显示showing();}/**************************************生成背景图**************************************/void background(){int line, lie;for (line = 0; line < MaxLine; line++){for (lie = 0; lie < MaxLie; lie++){setmouth(line, lie);if (lie == 0 || lie == MaxLie-1 || line == 0 || line == MaxLine-1) {show[line][lie] = wall;}else {show[line][lie] = livearea;}}}}/********************************定义光标位置*********************************/void setmouth(int x, int y){COORD coord;coord.X = y*2; //第3列coord.Y = x; //第3行//获取控制台缓冲区句柄HANDLE ConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);//设置光标位置SetConsoleCursorPosition(ConsoleHandle, coord);}//设置种类的颜色void setcolour(int a){HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleTextAttribute(hConsole, a);}//隐藏光标void hidemouth(){HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息CursorInfo.bVisible = 0; //隐藏控制台光标SetConsoleCursorInfo(handle, &CursorInfo);//设置控制台光标状态}

下面是上面程序的大体流程图:

本程序的思路是这样的,我们每次刷新屏幕都会重新生成一张图片,也就是show结构体数组,每个元素都包含了一个“像素点”的信息,这个信息是用结构体 map来定义的,包含了像素点的属性【种类(食物"★" ,小蛇蛇体"●",墙体"■",可活动的区域"□"),颜色(colour)和输出图形(char)】。将每次生成的新的show输出,就形成了小蛇的移动。

难点:

我在写程序的时候有一个问题,想了很久,就是小蛇的生长和移动到底怎么来实现?上面我们想到用像素点的方式来生成画面,从这个思路入手进一步发挥。我们知道小蛇每次移动一格(即屏幕刷新一次),就相当于头节点向控制方向前进一个位置,并且删除尾巴节点。小蛇生长,就是在小蛇移动过后,再在头节点前加一个节点。本来我准备用链表来做,可是实现起来太复杂了,后来晚上洗澡的时候想到一个办法。我用数组来做,把蛇的节点的位置坐标倒序存进一个数组,每次移动就让尾节点等于前一个节点的坐标,到头节点,就直接向控制的方向增加就好。生成新show的时候,将这个数组的像素点定义称蛇体,再播放就形成了小蛇的移动。生长,就在数组尾部再增加一个节点,生成像素点会被加上去。这个过程在实现的时候是最难的,想了好久才想到的,蛇体位置点倒序存放在数组里。

关于windows API 的东西,下面链接里面都有:

/C1664510416/article/details/82559357

/C1664510416/article/details/82559395

/C1664510416/article/details/82559419

/C1664510416/article/details/82559440

代码的含义注释写的很清楚了,如果还有疑问欢迎留言交流。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。