c语言贪吃蛇-单人模式&双人对抗
一、项目说明
使用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
本文地址:https://blog.csdn.net/qzl19/article/details/107112929
上一篇: Android APP 架构设计集合
下一篇: 整数拆分,减绳子(动态规划)