#include
#include
#include
#include
#pragma comment(lib,"winmm.lib")
//分析:蛇有坐标,有方向,有长度;食物有坐标,存在的标记(flag是否被吃了),经验值(grade分数),将蛇和食物的坐标定义结构体
//定义蛇和食物坐标的结构体
typedef struct point
{
int x, y;
}MYPOINT;
//定义蛇的结构体
struct snake
{
MYPOINT xy[100]; //用数组存储坐标,数组的长度给定100,如果定义成坐标的形式,那么蛇是由一个个矩形组成的,随着蛇的长度增长,那么去画矩形就比较有难度了
int position; //定义方向
int num; //定义长度
}snake;
//7.定义食物的结构体
struct food
{
MYPOINT fdxy; //定义食物的坐标
int flag; //定义标记
int grade; //定义经验值
}food;
//8.枚举方向,蛇走的方向,enum 专门用来定义枚举类型
enum position
{
up, down, left, right
};
//9.初始化蛇,一个矩形边长为10
void initsnake()
{
//蛇的第三节坐标(蛇尾)
snake.xy[2].x = 200;
snake.xy[2].y = 200;
//蛇的第二节
snake.xy[1].x = 200;
snake.xy[1].y = 200;
//蛇头坐标(蛇头)
snake.xy[0].x = 200;
snake.xy[0].y = 200;
//蛇的方向
snake.position = right;
//蛇的长度
snake.num = 5;
}
//10.画蛇
void drawsnake()
{
//采用循环的形式画蛇
for (int i = 0; i < snake.num; i++)
{
setlinecolor(WHITE);//设置矩形的边框颜色
setfillcolor(RGB(rand() % 250, rand() % 250, rand() % 250)); //设置蛇颜色
fillrectangle(snake.xy[i].x, snake.xy[i].y, snake.xy[i].x + 10, snake.xy[i].y + 10); //绘制两个点确定矩形
}
}
//13.让蛇动起来,移动的原理就是坐标的转换
void movesnake()
{
//蛇身的坐标
for (int i = snake.num - 1; i > 0; i--)
{
snake.xy[i].x = snake.xy[i - 1].x;
snake.xy[i].y = snake.xy[i - 1].y;
}
//蛇头坐标
switch (snake.position)
{
case up:
snake.xy[0].y -= 10;
break;
case down:
snake.xy[0].y += 10;
break;
case left:
snake.xy[0].x -= 10;
break;
case right:
snake.xy[0].x += 10;
break;
}
}
void keyDown()
{
char userkey = _getch();
switch (userkey)
{
case'W':
case'w':
case'72':
if (snake.position != down)
snake.position = up;
break;
case'S':
case's':
case'80':
if (snake.position != up)
snake.position = down;
break;
case'A':
case'a':
case'75':
if (snake.position != right)
snake.position = left;
break;
case'D':
case'd':
case'77':
if (snake.position != left)
snake.position = right;
break;
}
}
//17.食物
//初始化蛇,坐标是随机产生的
void initfood()
{
food.fdxy.x = rand() % 80 * 10;//坐标必须在800*600之内
food.fdxy.y = rand() % 60 * 10;
food.flag = 1;//1代表食物存在
//17.2食物不能出现在蛇的身上
for (int i = 0; i < snake.num; i++)
{
if (food.fdxy.x == snake.xy[i].x && food.fdxy.y == snake.xy[i].y)
{
food.fdxy.x = rand() % 80 * 10;//蛇的坐标再次随机定义
food.fdxy.y = rand() % 60 * 10;
}
}
}
//18.画食物
void drawfood()
{
setlinecolor(WHITE);//设置矩形边框颜色
setfillcolor(RGB(3, 32, 251));//设置食物颜色
fillrectangle(food.fdxy.x, food.fdxy.y, food.fdxy.x + 10, food.fdxy.y + 10);//绘制两个点确定矩形
}
//20.吃食物
void eatfood()
{
if (snake.xy[0].x == food.fdxy.x && snake.xy[0].y == food.fdxy.y)
{
snake.num++;
food.flag = 0;
food.grade += 10;
}
}
//打印分数
void showGrade()
{
char grade[20] = " ";
sprintf_s(grade, "grade:%d", food.grade);//打印分数函数
settextcolor(RED);//设置字体颜色
settextstyle(25, 0, "宋体");
outtextxy(650, 50, grade);//指定分数函数输出的位置
}
//24.游戏结束
int snakeDie()
{
//24.1撞墙,蛇头坐标超出窗口外
if (snake.xy[0].x > 800 || snake.xy[0].x < 0 || snake.xy[0].y> 600 || snake.xy[0].y < 0)
{
mciSendString("close 2.mp3", 0, 0, 0);//关闭音乐
MessageBox(NULL, "撞墙啦!游戏结束!", "gameover", MB_OK);
return 1;//程序异常退出
}
//24.2自杀,蛇头坐标和蛇身的任意一节坐标重合
for (int i = 1; i < snake.num; i++)
{
if (snake.xy[0].x == snake.xy[i].x && snake.xy[0].y == snake.xy[i].y)
{
MessageBox(NULL, "自杀啦!游戏结束!", "gameover", MB_OK);
return 1;//程序异常退出
}
}
return 0;
}
int main()
{
srand((unsigned int)time(NULL)); //.把随机拿进来,不然就是伪随机,每次颜色都是一样的
//创建图形窗口
initgraph(800, 600); //初始化图像窗口
setbkcolor(RGB(250, 201, 130)); //改变窗口颜色
cleardevice();//清屏,刷新背景颜色
initsnake();
drawsnake();
mciSendString("open 2.mp3", 0, 0, 0);//打开音乐
mciSendString("play 2.mp3 repeat", 0, 0, 0);//循环播放
//14.蛇的移动需要在循环里面去调用
while (1)
{
cleardevice();//每次循环需要清屏处理
movesnake();//调用蛇移动
drawsnake();//画蛇
//19.调用食物
if (food.flag == 0)
{
initfood();
}
drawfood();
eatfood();//21.调用吃食物
showGrade();
if (snakeDie())
{
break;
}
//只有按键按下的时候才可以调用它,_kbhit()用于检测当前是否有键盘输入
if (_kbhit())
{
keyDown();
}
Sleep(100);//延迟
}
//fillrectangle(300, 300, 350, 350);
_getch(); //防止闪屏
closegraph();
return 0;
}



