#include <stdio.h>
#include <time.h>
#include <windows.h>
#include <stdlib.h>
#include <conio.h>
#pragma warning(disable:4996)//在某些编译环境中,以下用到的一些函数可能会报不安全,比如:getch,kbhit 所以这里要加上这个定义可以
/*某一些函数的先后执行顺序做了调整*/
#define INFO_X 100 //提示信息区横坐标
#define WIDE 50 //游戏界面宽度
#define HIGH 36 //游戏界面高度
#define LEVELUP 5 //升级所需的食物个数
/* 定义全局变量 */
unsigned char key;
int i, j, k, end[2]; //i,j,k为循环变量,end数组用来做蛇尾坐标的中间变量
/* 蛇身结构 */
struct Snakes
{
int X[100]; //蛇身的横坐标
int Y[100]; //蛇身的纵坐标
int length; //蛇的长度
int speed; //蛇移动速度
int count; //蛇吃到食物个数
};
/* 食物结构 */
struct Food
{
int X; //食物横坐标
int Y; //食物纵坐标
};
struct Snakes s, * snake = &s; //定义蛇的结构体指针并指向蛇的结构体
struct Food f, * food = &f; //定义食物结构体指针并指向食物结构体
/* 设置控制台标题和大小 */
void SetTitle()
{
//设置控制台窗口大小
system("mode con cols=150 lines=40");
//设置控制台标题
SetConsoleTitle("贪吃蛇");
}
/* 设置光标位置 */
void SetPos(int x, int y)
{
HANDLE winhandle;
COORD pos = { x,y };
winhandle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(winhandle, pos);
}
/* 设置控制台颜色 */
void Setcolor(int forcolor, int bakcolor)
{
/*
0=黑色, 8=灰色,
1=蓝色, 9=淡蓝色,
2=绿色, A=淡绿色,
3=湖蓝色, B=淡浅绿色,
4=红色, C=淡红色,
5=紫色, D=淡紫色,
6=黄色, E=淡黄色,
7=白色, F=亮白色
*/
HANDLE winhandle;
winhandle = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(winhandle, forcolor + bakcolor * 0x10);
}
/* 清楚单行显示 */
void Cleanlin(int x, int y)
{
SetPos(x, y);
for (i = 0; i < 50; i++)
{
printf(" ");
}
}
/* 设置游戏界面 */
void Table()
{
for (i = 0; i < HIGH; i++)
{
if (i == 0 || i == HIGH - 1)
{
for (k = 0; k < WIDE * 2 - 1; k += 2)
{
SetPos(k, i);
printf("■");
}
continue;
}
else
{
for (j = 0; j < WIDE * 2 - 1; j += 2)
{
if (j == 0 || j == WIDE * 2 - 2)
{
SetPos(j, i);
printf("■");
}
}
}
}
}
/* 显示提示和菜单 */
void ShowMenu()
{
SetPos(INFO_X + 17, 1);
Setcolor(9, 0);
printf("欢迎来到贪吃蛇!");
SetPos(INFO_X + 17, 5);
printf("Esc 退出游戏");
SetPos(INFO_X + 17, 7);
printf("空格 暂停游戏");
SetPos(INFO_X + 17, 9);
printf("↑↓←→ 控制蛇头方向");
SetPos(INFO_X + 17, 11);
printf("长按方向键加速");
SetPos(INFO_X + 17, 15);
printf("游戏得分:%d", snake->count * 100);
SetPos(INFO_X + 17, 17);
printf("当前级别:%d", snake->count / LEVELUP + 1);
SetPos(INFO_X + 17, 19);
printf("当前速度:%d", snake->speed);
SetPos(INFO_X + 17, 21);
printf("吃到食物:%d", snake->count);
SetPos(INFO_X + 17, 23);
printf("食物坐标:%-2d,%-2d", food->X, food->Y);
}
/* 初始化蛇身 */
void init_snake()
{
snake->X[0] = WIDE; //初始化蛇的横坐标
snake->Y[0] = HIGH / 2; //初始化蛇的竖坐标
end[0] = snake->X; //记住蛇尾横坐标
end[1] = snake->Y; //记住蛇尾纵坐标
snake->speed = 300; //初始化蛇的速度为300ms
snake->length = 3; //初始化蛇的长度为3节
snake->count = 0; //初始化蛇吃的个数为0
for (i = 1; i < snake->length; i++)
{
/* 依次得到蛇身、蛇头的坐标 */
snake->X[i] = snake->X[i - 1] + 2;
snake->Y[i] = snake->Y[i - 1];
}
}
/* 移动蛇身 */
void move_snake()
{
SetPos(snake->X[0], snake->Y[0]);
printf(" "); /* 清除蛇尾*/
for (i = 1; i < snake->length; i++)
{/* 后一节的坐标依次取代前一节的坐标 */
snake->X[i - 1] = snake->X[i];
snake->Y[i - 1] = snake->Y[i];
}
}
/* 显示蛇身 */
void print_snake()
{
for (i = 0; i < snake->length; i++)
{
SetPos(snake->X[i], snake->Y[i]);
if (i == 0)
{
printf("○"); //打印蛇尾
}
else if (i == snake->length - 1)
{
printf("¤"); //打印蛇头
}
else
{
printf("⊙"); //打印蛇身
}
}
}
/* 产生食物 */
void get_food()
{
srand((unsigned)time(NULL));
while (1)
{
food->X = ((rand() % (WIDE - 3)) + 1) * 2;
food->Y = (rand() % (HIGH - 2)) + 1;
for (i = 0; i < snake->length; i++)
{
if (food->X == snake->X[i] && food->Y == snake->Y[i])
{
break;
}
}
if (i == snake->length)
{
SetPos(food->X, food->Y);
Setcolor(10, 0);
printf("⊙");
Setcolor(9, 0);
break;
}
}
}
/* 吃食物 */
void eat_food()
{
if (snake->X[snake->length - 1] == food->X && snake->Y[snake->length - 1] == food->Y)
{/*如果蛇头坐标和食物坐标相同,吃掉食物,身长加1。*/
snake->length++;
for (i = snake->length - 1; i > 0; i--)
{/* 蛇后节坐标依次赋值给蛇前一节的坐标,依次得到蛇身及蛇头的坐标 */
snake->X[i] = snake->X[i - 1];
snake->Y[i] = snake->Y[i - 1];
}
snake->X[0] = end[0];
snake->Y[0] = end[1];
get_food();
snake->count++;
if (snake->count % LEVELUP == 0)
{/* 当蛇吃LEVELUP个食物时,速度加快20毫秒并且升一级 */
snake->speed -= 20;
}
}
}
/* 穿墙 */
void through_wall()
{ /* 当蛇碰到移动方向的边界时,蛇身穿过边界从相对的另一边出现。*/
if (key == 72 && snake->Y[snake->length - 1] == 0)//上键
{
snake->Y[snake->length - 1] = HIGH - 2;
}
if (key == 77 && snake->X[snake->length - 1] == WIDE * 2 - 2)//右键
{
snake->X[snake->length - 1] = 2;
}
if (key == 80 && snake->Y[snake->length - 1] == HIGH - 1)//下键
{
snake->Y[snake->length - 1] = 1;
}
if (key == 75 && snake->X[snake->length - 1] == 0)//左键
{
snake->X[snake->length - 1] = (WIDE - 2) * 2;
}
}
void GameOver()
{
system("cls");
SetPos(WIDE, HIGH / 2);
printf("游戏结束!");
ShowMenu();
SetPos(0, HIGH);
exit(0);
getch();
}
/* 判断蛇的死亡 */
void die()
{
for (i = 0; i < snake->length - 1; i++)
{ /* 当蛇头碰到蛇身,蛇死亡。 */
if (snake->X[snake->length - 1] == snake->X[i] && snake->Y[snake->length - 1] == snake->Y[i])
{
GameOver();
}
}
}
/* 得到用户输入 */
void GetKey()
{
switch (key)
{
case 27://Esc键--结束游戏
{
GameOver();
break;
}
case 32://空格键--暂停游戏
{
SetPos(INFO_X + 13, HIGH - 5);
Setcolor(5, 0);
Sleep(500);
printf("游戏暂停,按方向键继续!");
Setcolor(9, 0);
SetPos(0, HIGH);
break;
}
case 72://上键
{
move_snake();
snake->Y[snake->length - 1] -= 1;
break;
}
case 77://右键
{
move_snake();
snake->X[snake->length - 1] += 2;
break;
}
case 80://下键
{
move_snake();
snake->Y[snake->length - 1] += 1;
break;
}
case 75://左键
{
move_snake();
snake->X[snake->length - 1] -= 2;
break;
}
}
}
/* 开始游戏 */
void GameStar()
{
key = 77; //初始化蛇向右移动
SetTitle(); //设置控制台标题和大小
Setcolor(4, 0);
Table(); //初始化游戏界面
init_snake(); //初始化蛇身
get_food(); //初始化第一个食物
while (1)
{
Cleanlin(INFO_X, HIGH - 5);
ShowMenu();
end[0] = snake->X[0];
end[1] = snake->Y[0];
j = 0;
if (kbhit())
{/* 判断是否按下键盘,如果按下,ch接收键盘输入 */
key = getch();
if (kbhit())
{/* 如果长按键盘,则加速 */
Sleep(20);
j = 1;
}
}
GetKey();
through_wall();
eat_food();
print_snake();
die();
if (j == 0)
{
Sleep(snake->speed); //延迟时间
}
else
{
Sleep(10);
}
}
}
/* 游戏结束 */
int main()
{
GameStar();
return 0;
}