贪吃蛇?
没错,就是贪吃蛇,这个你不会不知道吧。那你肯定会疑问了,还能用代码写贪吃蛇?当然啦,今天我就教大家写一个属于自己的贪吃蛇!
你所需要准备的是:一定的链表知识,电脑集成编译环境CodeBlocks(最好使用该软件,否则可能会不成功),点个赞,关注一波~~后续有好东西,我会继续分享的!
设计思路
首先,要先将背景打印出来,这里需要的函数下面会介绍。然后随机生成蛇头,根据蛇头生成蛇身,并将整个蛇打印出来,然后生成食物(确保不和蛇重合),这样,第一步就完成了。接下来,到了最主要的步骤了,蛇身移动及吃食。这里我采用的是先清除蛇身,再打印到移动后的位置,吃食同理。而蛇的方向控制需要键盘控制。
调用函数
void Menu(); //初始化菜单
void Gotoxy(int x, int y); //光标定位
void GotoChange(int x, int y); //将■改为空格
void GotoPrint(int x, int y); //转至(x,y)打印■
void CreatWall(); //生成围墙
void CreatSnake(); //初始化生成蛇
void PrintBody(); //打印蛇身
void Initialization(); //初始化界面
void CreatFood(); //生成随机食物
int Control(); //控制蛇
int Judge(); //评判结束
void MovingBody(); //移动蛇身
void ChangeBody(int x, int y); //改变蛇身
void Eating(); //蛇“进食”
void End(); //结束页面
其中比较难理解且重要的函数可见:
gotoxy()函数——>传送门
Control()里的_kbhit()——>传送门
Control()里的_getch()——>传送门
未列出的变色函数SetConsoleTextAttribute——>传送门
代码实现:
#include
#include
#include
#include
#include
#define up 'w'
#define down 's'
#define left 'a'
#define right 'd'
#define stop 'p'
typedef struct snake
{
int x, y;
struct snake *next;
}SNAKE;
void Menu(); //初始化菜单
void Gotoxy(int x, int y); //光标定位
void GotoChange(int x, int y); //将■改为空格
void GotoPrint(int x, int y); //转至(x,y)打印■
void CreatWall(); //生成围墙
void CreatSnake(); //初始化生成蛇
void PrintBody(); //打印蛇身
void Initialization(); //初始化界面
void CreatFood(); //生成随机食物
int Control(); //控制蛇
int Judge(); //评判结束
void MovingBody(); //移动蛇身
void ChangeBody(int x, int y); //改变蛇身
void Eating(); //蛇“进食”
void End(); //结束页面
char name[66];
int speed = 50, score = 0, co;
SNAKE *head, *tail;
int food_x, food_y;
char input = 1;
int main()
{
Menu();
CreatWall();
CreatSnake();
Initialization();
CreatFood();
if(Control() == 0)
return 0;
return 0;
}
void Menu()
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY
| FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
Gotoxy(40, 16);
printf("欢迎打开贪吃蛇游戏~~~\n");
Gotoxy(40, 17);
printf("请输入您的用户名:");
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
scanf("%s", name);
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY
| FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
Gotoxy(40, 19);
printf("请您选择游戏难度:\n\
\t\t\t\t\t1:小白模式\n\
\t\t\t\t\t2:普通模式(推荐)\n\
\t\t\t\t\t3:困难模式\n\
\t\t\t\t\t4:极限模式\n\
\t\t\t\t\t5:变态模式\n\
\t\t\t\t\t6:冒险模式\n\t\t\t\t\t");
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
scanf("%d", &co);
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
if(co > 0 && co < 6)
speed *= (6-co);
else
speed = 300;
system("cls");
Gotoxy(42, 14);
printf("正在加载中~~~\n");
Gotoxy(20, 16);
printf("提示:\n");
Gotoxy(24, 18);
printf("请在英文输入法中操作,反向移动等同于吃到自己,wasd控制p暂停\n");
Gotoxy(36, 20);
printf("\t全屏游戏效果更佳哟~~~");
Sleep(3000);
system("cls");
}
void Gotoxy(int x, int y)
{
COORD pos = {x, y};
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 获取标准输出设备句柄
SetConsoleCursorPosition(hOut, pos); //两个参数分别是指定哪个窗体,具体位置
}
void GotoPrint(int x, int y)
{
Gotoxy(x, y);
printf("■");
}
void GotoChange(int x, int y)
{
Gotoxy(x, y);
printf(" ");
}
void CreatWall()
{
int i, j;
for (i = 0; i < 36; i++)
{
for(j = 0; j < 72; j += 2)
{
if(i == 0 || i == 35 || j == 0 || j == 70)
printf("■");
else
printf(" ");
}
printf("\n");
}
}
void CreatSnake()
{
srand((unsigned)time(NULL));
head = (SNAKE*)malloc(sizeof(SNAKE));
head->x = rand()%30+3;
if(head->x % 2 != 0)
{
head->x++;
}
head->y = rand()%30+3;
tail = (SNAKE*)malloc(sizeof(SNAKE));
SNAKE *p = (SNAKE*)malloc(sizeof(SNAKE));
SNAKE *q = (SNAKE*)malloc(sizeof(SNAKE));
p->x = head->x;
p->y = head->y+1;
q->x = head->x;
q->y = head->y+2;
head->next = p;
p->next = q;
q->next = tail;
tail->next = NULL;
}
void PrintBody()
{
SNAKE *t = head;
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
GotoPrint(t->x, t->y);
t = t->next;
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_GREEN);
while(t->next != NULL)
{
GotoPrint(t->x, t->y);
t = t->next;
}
Gotoxy(0, 36);
}
void Initialization()
{
PrintBody();
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
Gotoxy(128, 2);
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
printf("p:(开始/暂停)");
Gotoxy(120, 3);
printf("如果蛇在移动过程中,撞到墙壁或身体");
Gotoxy(120, 4);
printf("交叉(蛇头撞到自己的身体)游戏结束");
Gotoxy(100, 12);
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
printf("%s", name);
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
printf(",加油加油喀~~~");
Gotoxy(100, 18);
printf("您目前的分数为:");
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
Gotoxy(116, 18);
printf("%d", score);
Gotoxy(100, 24);
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
printf("小游戏作者:");
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
printf("ChrisPhantom");
}
void CreatFood()
{
lable:
food_y = rand()%(34) + 1;
food_x = rand()%(67) + 2;
if (food_x % 2 != 0)
{
food_x = food_x + 1;
}
SNAKE *t = head;
while(1) //遍历排除蛇身重复
{
if(t->next == NULL)
break;
if(food_x == t->x && food_y == t->y)
{
goto lable;
}
t = t->next;
}
Gotoxy(food_x, food_y);
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
printf("⊙");
}
int Control()
{
while (1)
{
if (Judge() == 0)
return 0;
if (_kbhit())
{
input = _getch();
}
MovingBody();
Eating();
}
return 1;
}
int Judge()
{
if (head->x == 0 || head->x == 70 || head->y == 0 || head->y == 35) //撞到墙壁
{
End();
return 0;
}
SNAKE *p = head->next;
while (1)
{
if (p->next == NULL)
break;
if (head->x == p->x && head->y == p->y) //身体交叉
{
End();
return 0;
}
p = p->next;
}
return 1;
}
void MovingBody() //通过先清空后打印实现动画效果
{
int x = head->x, y = head->y;
SNAKE *p = head;
while (1)
{
if (p->next == NULL)
break;
GotoChange(p->x, p->y);
p = p->next;
}
switch (input)
{
case up:
head->y -= 1;
ChangeBody(x, y);
break;
case down:
head->y += 1;
ChangeBody(x, y);
break;
case left:
head->x -= 2;
ChangeBody(x, y);
break;
case right:
head->x += 2;
ChangeBody(x, y);
break;
case stop:
break;
}
PrintBody();
Sleep(speed);
}
void ChangeBody(int x, int y)
{
SNAKE *p = head->next;
int mid1, mid2, tmid1, tmid2;
mid1 = p->x;
mid2 = p->y;
while (1)
{
if (p->next->next == NULL)
break;
tmid1 = p->next->x;
tmid2 = p->next->y;
p->next->x = mid1;
p->next->y = mid2;
mid1 = tmid1;
mid2 = tmid2;
p = p->next;
}
p = head->next;
//if (p->next!= NULL)
{
p->x = x;
p->y = y;
}
}
void Eating()
{
if (head->x == food_x && head->y == food_y)
{
printf("\a");
CreatFood();
SNAKE *t = (SNAKE*)malloc(sizeof(SNAKE));
SNAKE *p;
p = head;
while (1)
{
if (p->next->next == NULL)
break;
p = p->next;
}
p->next = t;
t->next = tail;
score += 10;
if(co == 6 && speed > 40)
{
speed -= 20;
}
Gotoxy(116, 18);
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
printf("%d", score);
}
}
void End()
{
system("cls");
Gotoxy(56, 14);
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
printf("%s,", name);
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
printf("您的得分为:");
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
printf("%d", score);
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
Gotoxy(56, 16);
if(score <= 30)
printf("不要气馁,继续加油啊 ~_~");
else if(score <= 70)
printf("你已经很不错啦,是不是还可以更厉害呢 @_@");
else if(score <=120)
printf("你真是超级厉害啊,已经超过大多数人啦 ^_^");
else
printf("难道你...你就是传说中的dalao !_!");
Gotoxy(48, 19);
printf("小游戏作者:");
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);
printf("ChrisPhantom(没错就是我ChrisPhantom本人了,手动滑稽)");
Gotoxy(48, 20);
SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_BLUE);
printf("如果喜欢的话,就给我点个赞吧~~~");
Gotoxy(48, 22);
system("pause");
}
参考资料
https://blog.csdn.net/qq_40935723/article/details/86553391
https://blog.csdn.net/qq_40953281/article/details/79315254
https://mbd.baidu.com/newspage/data/error
由于其中部分代码的注释未详尽的解释,不明白的可以私信咨询。喜欢的话麻烦点个赞分享一下啦。
如果觉得本码足够规整而又不清楚规范,可查看另一帖子《C语言代码规范》–>传送门
感谢师傅来访,技术不精,请勿吐槽,如有问题请留言。