C语言项目游戏,贪吃蛇大作战
效果图
参考代码
(使用的编译器VS2019)
#include<stdio.h>
#include<time.h>
#include<windows.h>
#include<conio.h>
#include<stdlib.h>
#define U 1
#define D 2
#define L 3
#define R 4
int zifu[6] = { 0,0,0,0,0,0 }; //用来存放欢迎界面“贪吃蛇大作战”的横坐标值
int k; //用来设定“贪吃蛇大作战”字幕的起始横坐标值
int Hscore = 0;
int score = 0, fen = 10;
int endgame = 0;
int sleeptime = 400; //蛇每次运行的时间状态,修改可以获得不同1的蛇得爬行速度
int zhuangtai; //设置蛇的运行状态
typedef struct Snake {
int x;
int y;
struct Snake* text;
}Snake; //绘制蛇的结构体变量
Snake* head, * food; //设置蛇的头指针,食物也以指针来确定
Snake* pp; //定义蛇的指针,用来调换蛇头
int color(int c);
void gotoxy(int x, int y);
void welcome(); //游戏欢迎界面
void choie(); //游戏选择框界面
void map(); //构建游戏地图
void scorerecord(); //游戏得分记录函数
void snake(); //初始化蛇身
void creatfood(); //创建随机食物
int bitemyself(); //判断蛇是否咬到自己
void ifwall(); //判断蛇是否撞到墙
void sleepdown(); //加速函数
void sleepup(); //减速函数
void move(); //蛇的控制移动方向
void keycontrol(); //按键控制蛇的移动
void shibai(); //失败函数,绘制失败界面
void end(); //游戏结束判断函数
void Filein(); //文件写入函数
void choose(); //选择函数
void File(); //文件写入函数
int color(int c)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c);
return 0;
}
void gotoxy(int x, int y)
{
COORD c;
c.X = x;
c.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
}
int main()
{
welcome();
return 0;
}
void welcome()
{
int i,j, m = 1;
int z;
int n;
while (1)
{
k = 20; //横坐标起始位置为20
for (i = 0; i < 6; i++) //给zifu数组赋值,从数组地位到高位,一次存放‘贪吃蛇大作战’的横坐标值
{
zifu[i] = k + m;
if (zifu[i] == 53) //因为横坐标起始位置为20,设定的移动长度为33,20+33=53,第一次到zifu[i]==53以后要使它重新等于20
//就需要对显示屏长度33求余,53-66之间就会使“大作战”在显示屏前面,呈现“大 作 战 贪 吃 蛇”
{ //字样,此时由于“蛇”的横坐标值达到了66,66%33==0;这时再加上20,就会出现字体重合现象。为了解决这个问题,只有
m = m + 13; //把53-66之间的数值拿走,使zifu的某个值达到53以后,之间跳转成66,所以让m=m+13;
}
z = (k + m) % 33;
zifu[i] = z + 20;
k += 4;
}
color(2);
gotoxy(zifu[0], 10);
printf("贪");
color(5);
gotoxy(zifu[1], 10);
printf("吃");
color(10);
gotoxy(zifu[2], 10);
printf("蛇");
color(9);
gotoxy(zifu[3], 10);
printf("大");
color(12);
gotoxy(zifu[4], 10);
printf("作");
color(14);
gotoxy(zifu[5], 10);
printf("战");
Sleep(500); //调用延时函数,这样才能看出移动效果,否者可能因为执行过快,而无法呈现移动效果
gotoxy(zifu[0], 10); //输出空格,制造出字体移动的效果
printf(" ");
gotoxy(zifu[1], 10);
printf(" ");
gotoxy(zifu[2], 10);
printf(" ");
gotoxy(zifu[3], 10);
printf(" ");
gotoxy(zifu[4], 10);
printf(" ");
gotoxy(zifu[5], 10);
printf(" ");
m += 2; //每次在横坐标上移动两个字节
srand(time(NULL));
n = rand() % 15 + 1;
for (i = 10; i <= 58; i++)
{
for (j = 5; j <= 15; j++)
{
if (i == 10 || i == 58)
{
color(n);
gotoxy(i, j);
printf("▊");
}
if (j == 5 || j == 15)
{
color(n % 13 + 1);
gotoxy(i, j);
printf("▃");
}
}
}
color(11);
gotoxy(60, 9);
printf("制作人:沙雕");
gotoxy(60, 10);
printf("年纪:这和游戏有什么关系");
gotoxy(60, 11);
printf("这个沙雕有话要讲:");
color(13);
gotoxy(60, 12);
printf("不知道怎么开始有吧?傻批");
gotoxy(60, 13);
printf("随便按一个键嘛,真傻!");
if (_kbhit())
{
choie();
}
}
}
void choie()
{
system("cls"); //清屏
int xuanze;
int i, j;
gotoxy(43, 18); //光标移动到指定位置,输出标题
color(11);
printf("贪吃蛇大作战"); //标题
color(14);
for(i=29;i<=74;i++) //用两个循环输出边框
for (j = 20; j <= 30; j++)
{
if (i == 29 || i == 74)
{
gotoxy(i, j);
printf("|");
}
else
if (j == 20 || j == 30)
{
gotoxy(i, j);
printf("=");
}
}
color(12);
gotoxy(33, 22);
printf("1,开始游戏");
gotoxy(52, 22);
printf("2,游戏说明");
gotoxy(33, 27);
printf("3,退出游戏");
color(3);
gotoxy(38, 33);
printf("请输入你的选择:【】\b\b");
color(14);
scanf_s("%d", &xuanze);
switch (xuanze)
{
case 1:
system("cls");
map();
snake();
creatfood();
File();
keycontrol();
end();
break;
case 2:
system("cls");
color(13);
printf("不能撞墙,不能咬自己,用方向键控制蛇的移动\n");
printf("F1加速,F2减速。空格键暂停,再按空格键继续\n");
printf("按ESC退出游戏。");
_getch();
system("cls");
choie();
break;
case 3:
exit(0);
break;
default:
gotoxy(38, 36);
printf("你未正确输入");
system("cls");
welcome();
}
}
void map() //绘制游戏范围边框
{
int i;
for (i = 0; i < 58; i += 2)
{
gotoxy(i, 0);
color(5);
printf("□");
gotoxy(i, 26);
printf("□");
}
for (i = 1; i < 26; i++)
{
gotoxy(0, i);
printf("□");
gotoxy(56, i);
printf("□");
}
}
void scorerecord()
{
File();
gotoxy(64, 4);
color(11);
printf("*最高纪录*:%d", Hscore);
gotoxy(64, 8);
color(4);
printf("得分:%d", score);
color(13);
gotoxy(73, 11);
printf("小 提 示");
gotoxy(60, 13);
color(6);
printf("-------------------");
gotoxy(60, 25);
printf("-------------------");
color(3);
gotoxy(64, 14);
printf("每个食物得分:%d分", fen);
gotoxy(64, 16);
printf("不能撞墙,不可以咬自己");
gotoxy(64, 20);
printf("用方向键控制蛇得移动");
gotoxy(64, 22);
printf("Space:暂停游戏");
gotoxy(64, 24);
printf("Esc:退出游戏");
}
void File()
{
FILE* fp;
int err;
err = fopen_s(&fp,"save.txt", "a+");
fscanf_s(fp, "%d", &Hscore);
fclose(fp);
}
void snake()
{
Snake* tt;
int i;
tt = (Snake*)malloc(sizeof(Snake)); //从蛇尾开始往蛇头设置蛇身的坐标
tt->x = 24;
tt->y = 5;
tt->text = NULL;
for (i = 1; i <= 4; i++) //设置蛇身,初始化长度为5
{
head = (Snake*)malloc(sizeof(Snake)); //利用循环,不断开辟一个空间,该空间成为蛇头
head->y = 5; //直到达到蛇的初始化位置
head->x= 24 + 2 * i;
head->text = tt;
tt = head;
}
while (tt != NULL) //输出蛇身
{
gotoxy(tt->x, tt->y);
color(14);
printf("■");
tt = tt->text;
}
}
void creatfood()
{
Snake* food1;
label:srand((unsigned)time(NULL)); //初始化随机食物
food1 = (Snake*)malloc(sizeof(Snake));
while ((food1->x % 2) != 0)
{
food1->x = rand() % 52 + 2; //设置随机食物的横坐标随机值
}
food1->y = rand() % 24 + 1;
pp = head; //把头指针给pp,然后遍历蛇身
while (pp->text != NULL)
{
if (pp->x == food1->x && pp->y == food1->y) //判断食物位置是否与蛇身重合
{ //如果重合就释放第一个食物指针,然后重新生成食物
free(food1);
goto label;
}
pp = pp->text;
}
gotoxy(food1->x, food1->y); //如果不重合,就输出食物
food = food1;
color(12);
printf("■");
}
int bitemyself()
{
Snake *she;
she = head->text;
while (she != NULL)
{
if (she->x == head->x && she->y == head->y)
return 1;
she = she->text;
}
return 0;
}
void ifwall() //判断蛇是否撞到墙,原理是看蛇头的坐标是否和边界坐标重合
{
if (head->x == 0 || head->x == 56 || head->y == 0 || head->y == 26)
{
endgame = 1;
end();
}
}
void sleepup() //蛇的加速函数
{
if (sleeptime >= 50)
{
sleeptime = sleeptime - 10;
fen = fen + 2;
}
}
void sleepdown() //蛇的减速函数
{
if (sleeptime <= 350)
{
sleeptime = sleeptime + 30;
fen = fen - 2;
if (sleeptime == 350)
{
fen = 1;
}
}
}
void move()
{
Snake* xiayige; //下一个食物出现位置
ifwall(); //判断蛇是否撞到墙
xiayige = (Snake*)malloc(sizeof(Snake)); //为食物开辟指针
if (zhuangtai == U) //先判断此时蛇的状态,如果状态朝上,xiayige开辟的空间为蛇前行的下一个位置,然后蛇就长了一节
{ //再判断食物是不是和已经长长的蛇的蛇头重合,如果重合,就输出蛇
xiayige->x = head->x;
xiayige->y = head->y - 1;
xiayige->text = head;
head = xiayige;
pp = head;
if (xiayige->x == food->x && xiayige->y == food->y)
{
while (pp != NULL)
{
gotoxy(pp->x, pp->y);
color(14);
printf("■");
pp = pp->text;
}
score = score + fen;
sleepup();
creatfood();
}
else //如果不重合,输出原来的蛇,就不给蛇加长了
{
while (pp->text->text != NULL)
{
gotoxy(pp->x, pp->y);
color(14);
printf("■");
pp = pp->text;
}
gotoxy(pp->text->x, pp->text->y);
color(3);
printf(" "); //输出空格消除蛇移动的痕迹
free(pp->text);
pp->text = NULL;
}
}
if (zhuangtai == D)
{
xiayige->x = head->x;
xiayige->y = head->y + 1;
xiayige->text = head;
head = xiayige;
pp = head;
if (xiayige->x == food->x && xiayige->y == food->y)
{
while (pp != NULL)
{
gotoxy(pp->x, pp->y);
color(14);
printf("■");
pp = pp->text;
}
score = score + fen;
sleepup();
creatfood();
}
else
{
while (pp->text->text != NULL)
{
gotoxy(pp->x, pp->y);
color(14);
printf("■");
pp = pp->text;
}
gotoxy(pp->text->x, pp->text->y);
color(3);
printf(" ");
free(pp->text);
pp->text = NULL;
}
}
if (zhuangtai == L)
{
xiayige->x = head->x-2;
xiayige->y = head->y;
xiayige->text = head;
head = xiayige;
pp = head;
if (xiayige->x == food->x && xiayige->y == food->y)
{
while (pp != NULL)
{
gotoxy(pp->x, pp->y);
color(14);
printf("■");
pp = pp->text;
}
score = score + fen;
sleepup();
creatfood();
}
else
{
while (pp->text->text != NULL)
{
gotoxy(pp->x, pp->y);
color(14);
printf("■");
pp = pp->text;
}
gotoxy(pp->text->x, pp->text->y);
color(3);
printf(" ");
free(pp->text);
pp->text = NULL;
}
}
if (zhuangtai == R)
{
xiayige->x = head->x+2;
xiayige->y = head->y;
xiayige->text = head;
head = xiayige;
pp = head;
if (xiayige->x == food->x && xiayige->y == food->y)
{
while (pp != NULL)
{
gotoxy(pp->x, pp->y);
color(14);
printf("■");
pp = pp->text;
}
score = score + fen;
sleepup();
creatfood();
}
else
{
while (pp->text->text != NULL)
{
gotoxy(pp->x, pp->y);
color(14);
printf("■");
pp = pp->text;
}
gotoxy(pp->text->x, pp->text->y);
color(3);
printf(" ");
free(pp->text);
pp->text = NULL;
}
}
if (bitemyself() == 1)
{
endgame = 2;
end();
}
}
void keycontrol()
{
zhuangtai = R;
while (1)
{
scorerecord();
if (GetAsyncKeyState(VK_UP) && zhuangtai != D) //方向键↑
zhuangtai = U;
else if (GetAsyncKeyState(VK_DOWN) && zhuangtai != U) //方向键↓
zhuangtai = D;
else if (GetAsyncKeyState(VK_LEFT) && zhuangtai != R) //方向键←
zhuangtai = L;
else if (GetAsyncKeyState(VK_RIGHT) && zhuangtai != L) //方向键→
zhuangtai = R;
if (GetAsyncKeyState(VK_SPACE)) //如果按下空格键
{
while (1)
{
Sleep(300); //不断延迟时间来达到暂停的目的,再次按下方向键就跳出延迟时间的循环
if (GetAsyncKeyState(VK_SPACE))
{
break;
}
}
}
else if (GetAsyncKeyState(VK_ESCAPE)) //如果按下ESC键就退出
{
endgame = 3;
break;
}
else if (GetAsyncKeyState(VK_F1))
sleepup();
else if (GetAsyncKeyState(VK_F2))
sleepdown();
Sleep(sleeptime);
move();
}
}
void shibai()
{
system("cls");
int i;
gotoxy(17, 5);
color(11);
printf("+----------------------------------------------------------------+");
for (i = 6; i <= 19; i++)
{
gotoxy(17, i);
printf("|");
gotoxy(82, i);
printf("|");
}
gotoxy(17, 20);
printf("+----------------------------------------------------------------+");
}
void end()
{
system("cls");
if (endgame == 1)
{
shibai();
gotoxy(35, 9);
color(12);
printf("你撞到墙了,大哥。游戏结束!");
}
else if (endgame == 2)
{
shibai();
gotoxy(35, 9);
color(12);
printf("咬到自己了,憨包。游戏结束!");
}
else if (endgame == 3)
{
shibai();
gotoxy(40, 9);
color(12);
printf("你已结束游戏。");
}
gotoxy(43, 12);
color(13);
printf("你得到了%d分", score);
if (score >= Hscore) //分数高于最高分
{
color(10);
gotoxy(33, 16);
printf("创纪录啦!牛逼克斯啦");
Filein(); //将最高分写入文件中
}
else
{
color(10);
gotoxy(33, 16);
printf("继续努力,你离最高分还差%d分", Hscore - score);
}
choose();
}
void Filein()
{
FILE* ff; //定义文件指针
int err; //由于fopen_s函数与fopen函数不同,fopen_s函数执行成功返回0,执行失败返回一个非零整数值
if ((err = fopen_s(&ff, "save.txt", "w+")) != 0) //所以定义一个整形变量err用来接收该函数的返回值
{
printf("文件打开失败");
exit(0);
}
fprintf(ff, "%d", score);
fclose(ff);
}
void choose()
{
int n;
gotoxy(25, 23);
color(12);
printf("我不服,我要扳骚-------------1");
gotoxy(59, 23);
printf("太菜了,不想玩了-------------2");
gotoxy(46, 25);
color(11);
scanf_s("%d", &n);
switch (n)
{
case 1:
system("cls");
score = 0;
sleeptime = 600;
fen = 10;
choie();
break;
case 2:
exit(0);
break;
default:
gotoxy(35, 27);
color(12);
printf("你输入的信息有错误,眼睛不好使!");
system("pause >nul"); //按任意键
end();
choose();
break;
}
}