一、项目说明
使用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
);
}
void movefile(int x
,int y
)
{
COORD coord
;
coord
.X
=x
;
coord
.Y
=y
;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE
),coord
);
HideCursor();
}
4、运动控制函数
void keycontrl()
{
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);
}
void runcontrl()
{
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("◆");
}
前一个函数为键盘控制函数,用于读取键盘的键入情况,并记录在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
;
}
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