c语言贪吃蛇-单人模式&双人对抗

    技术2024-05-09  83

    一、项目说明

    ​ 使用c语言编写,实现了如下功能:

    ​ 1、较简单的用户界面,提供多种模式供选择

    ​ 2、贪吃蛇的四向移动、吃到食物后长度增长、分数增长并实时刷新等基本功能

    ​ 3、创新双人模式玩法,设置积分上限,让玩家相互竞争与攻击

    二、 代码/设计结构说明

    1、头文件使用说明:

    #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<windows.h> #include<stdlib.h> #include<time.h>// #include<conio.h>// #include<string.h>

    ​ windows.h: windows窗口相关头文件,用于定义窗口尺寸、编写用户界面;

    ​ time.h:日期和时间头文件,用于需要时间方面的函数,用于控制时间;

    ​ string.h:字符串相关操作;

    ​ stdlib.h:standard library标准库函数头文件;

    ​ conio.h:控制台输入输出文件;

    2、分别定义蛇、玩家等的结构体,用结构体更加清楚的表达蛇的节点数、节点位置、当前状态,以及玩家的名称、分数等信息,并用main函数内的while循环实时刷新相关信息。

    struct FOOD{ int x; int y; }; struct SNAKE{ int x[maxsize]; int y[maxsize];//坐标 int len ;//设定长度 int speed;//蛇移动的速度 char key; }; struct INFO { char name[7]; char moshi[6]; int score; };

    3、光标相关函数

    /定义隐藏光标函数,更加美观 void HideCursor() { CONSOLE_CURSOR_INFO cursor; cursor.bVisible = FALSE; cursor.dwSize = sizeof(cursor); HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorInfo(handle, &cursor); } //将光标移动到控制台的(int x,int y)处,非常重要的函数 void movefile(int x,int y) { COORD coord;//坐标结构 coord.X=x; coord.Y=y; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),coord);//定义设置控制台光标位置。 HideCursor(); }

    4、运动控制函数

    //键盘控制函数 void keycontrl() { //fflush(stdin); if(_kbhit())//响应键盘输入事件 { fflush(stdin);//清空缓冲区的字符 keys=_getch(); keys=_getch(); } if(keys!=72&&keys!=80&&keys!=77&&keys!=75) keys=pre_key; //防止蛇直接反向行进 if (pre_key == 72 && keys == 80) keys = 72; if (pre_key == 80 && keys == 72) keys = 80; if (pre_key == 75 && keys == 77) keys = 75; if (pre_key == 77 && keys == 75) keys = 77; pre_key=keys; movefile(81,31); } /** *控制台按键所代表的数字 *“↑”:72 *“↓”:80 *“←”:75 *“→”:77 *"W":87 *“A”:65 *"S":83 *"D":68*/ //判断蛇头应该往哪个方向移动 //运动相关函数 void runcontrl() { //若没有吃到食物,即flag=0,则在移动时抹去最后一位的字符 if(flag==0) { movefile(snake.x[snake.len-1],snake.y[snake.len-1]); printf(" "); for(int i=snake.len-1;i>0;i--)//画蛇身 { snake.x[i]=snake.x[i-1]; snake.y[i]=snake.y[i-1]; } } else if(flag==1) { movefile(snake.x[snake.len-2],snake.y[snake.len-2]); printf(" "); for(int i=snake.len-1;i>0;i--)//画蛇身 { snake.x[i]=snake.x[i-1]; snake.y[i]=snake.y[i-1]; } flag=0; } switch (keys) { case 75: snake.x[0] -= 2;//往左 pre_key=keys; break; case 77: snake.x[0] += 2;//往右 pre_key=keys; break; case 72: snake.y[0]--;//往上 pre_key=keys; break; case 80: snake.y[0]++;//往下 pre_key=keys; break; default: keys=pre_key; break; } //打印出蛇头 movefile(snake.x[0], snake.y[0]); printf("◆"); //由于目前没有吃到食物,flag值为0 }

    ​ 前一个函数为键盘控制函数,用于读取键盘的键入情况,并记录在int key中,第二个函数用于处理第一个函数的结果,移动蛇头部的坐标以达到蛇移动的效果。

    5、判断函数

    int judge() { int i=0;//判断结果传递参数 if(snake.y[0]==0||snake.y[0]==maxheight-2)//蛇撞上上下边界视为失败 i=1; if(snake.x[0]==0||snake.x[0]==54)//蛇撞上左后边界视为失败 i=1; for(int j=1;j<snake.len+1;j++) { if(snake.x[j]==snake.x[0]&&snake.y[j]==snake.y[0])//蛇头撞上自身身体视为失败 i=1; } return i; }

    使用int型变量i传递结果,蛇撞到上下界和自身算为失败。

    6、双人模式与单人模式的不同

    1、键盘函数(以左蛇的控制函数为例)
    void keycontrl1() { if (GetAsyncKeyState(VK_UP)) { if (snake1.key!= down)snake1.key= up; } else if (GetAsyncKeyState(VK_DOWN)) { if (snake1.key!= up)snake1.key = down; } else if (GetAsyncKeyState(VK_RIGHT)) { if (snake1.key!= left)snake1.key= right; } else if (GetAsyncKeyState(VK_LEFT)) { if (snake1.key != right)snake1.key = left; } //若没有吃到食物,即flag=0,则在移动时抹去最后一位的字符 if(flag==0) { movefile(snake1.x[snake1.len-1],snake1.y[snake1.len-1]); printf(" "); for(int i=snake1.len-1;i>0;i--)//画蛇身 { snake1.x[i]=snake1.x[i-1]; snake1.y[i]=snake1.y[i-1]; } } else if(flag==1) { movefile(snake1.x[snake1.len-2],snake1.y[snake1.len-2]); printf(" "); for(int i=snake1.len-1;i>0;i--)//画蛇身 { snake1.x[i]=snake1.x[i-1]; snake1.y[i]=snake1.y[i-1]; } flag=0; } switch (snake1.key) { case right:snake1.x[0] += 2; break; case left:snake1.x[0]-= 2; break; case up:snake1.y[0] -= 1; break; case down:snake1.y[0] += 1; break; } //打印出蛇头 movefile(snake1.x[0], snake1.y[0]); printf("◆"); movefile(81,31); }

    单人模式使用数字键码代表键盘键入的内容,双人模式直接使用虚拟键码控制,更加便捷与清楚。

    2、判断函数
    //判断是否结束 int judge2(){ int i=0;//判断结果传递参数 int k=0; if(snake1.y[0]==0||snake1.y[0]==maxheight-2)//蛇撞上上下边界视为失败 i=1; if(snake1.x[0]==0||snake1.x[0]==54)//蛇撞上左后边界视为失败 i=1; for(int j=1;j<snake1.len+1;j++) { if(snake1.x[j]==snake1.x[0]&&snake1.y[j]==snake1.y[0])//蛇头撞上自身身体视为失败 i=1; } if(info1.score==maxscore) k=1;//分数达到上限结束 for(int j=1;j<snake1.len+1;j++) { if(snake1.x[j]==snake2.x[0]&&snake1.y[j]==snake2.y[0])//另一蛇头撞上自身身体视为失败 k=1; } if(snake2.y[0]==0||snake2.y[0]==maxheight-2)//蛇撞上上下边界视为失败 k=1; if(snake2.x[0]==0||snake2.x[0]==54)//蛇撞上左后边界视为失败 k=1; for(int j=1;j<snake2.len+1;j++) { if(snake2.x[j]==snake2.x[0]&&snake2.y[j]==snake2.y[0])//蛇头撞上自身身体视为失败 k=1; } for(int j=1;j<snake2.len+1;j++) { if(snake2.x[j]==snake1.x[0]&&snake2.y[j]==snake1.y[0])//另一蛇头撞上自身身体视为失败 i=1; } if(info2.score==maxscore) i=1;//分数达到上限结束 if(k==1&&i==1) return 1; else if(k==0&&i==1) return 0; else if(k==1&&i==0) return -1; else return 2;

    除了碰撞的判定,还加入了分数上限的判定。

    三、 难点与解决

    ​ 双人模式中两蛇的操作相互干扰:更换了键盘键入的读取形式后解决了该问题

    四、 参考资料

    [1]贪吃蛇算法:https://blog.csdn.net/zs120197/article/details/88420297?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase

    [2]窗口相关:https://blog.csdn.net/liluo_2951121599/article/details/66474233

    五、完整代码

    https://download.csdn.net/download/qzl19/12573923

    Processed: 0.014, SQL: 10