放寒假写一个贪吃蛇玩玩,写了还是有几个小时,还有许多未完善的地方,学了文件操作可以把最高分贮存下来。大家多多指点,给点建议或需要更改的地方。
不喜勿喷。
全部代码:
#include <stdio.h>
#include <easyx.h>
#include <stdlib.h>
#include <conio.h>
#define SNAKE_NUM 500
#define R 5
int main();
struct Data
{
int x;
int y;
};
struct Snake
{
int size;
int dir;
int speed;
Data coor[SNAKE_NUM];//坐标
}snake;
struct Food
{
int x;
int y;
int op = 0;
int score;
}food;
enum
{
UP,
DOWN,
LEFT,
RIGHT
};
void GameInit()
{
initgraph(640, 480, 0);
srand(GetTickCount());
snake.size = 20;
snake.speed = 10;
snake.dir = RIGHT;
for (int i = 0, j = snake.size - 1; i < snake.size; i++, j--)
{
snake.coor[i].x = 10 * j + 4 * R;
snake.coor[i].y = 10;
}
food.x = rand() % 630+10;
food.y = rand() % 470+10;
}
void GameDraw()
{
BeginBatchDraw();
setbkcolor(RGB(20, 50, 105));
cleardevice();
setfillcolor(YELLOW);
solidcircle(snake.coor[0].x, snake.coor[0].y, R);
int i = 1;
while (snake.coor[i].x)
{
setfillcolor(WHITE);
solidcircle(snake.coor[i].x, snake.coor[i].y, R);
i++;
}
setfillcolor(BLACK);
if(food.op) solidcircle(food.x, food.y, R);
EndBatchDraw();
}
void Snakemove()
{
for (int i = snake.size-1; i >=1; i--)
{
snake.coor[i] = snake.coor[i - 1];
}
switch (snake.dir)
{
case UP:
if(snake.coor[0].y>0)
snake.coor[0].y-=snake.speed;
else snake.coor[0].y = 480;
break;
case DOWN:
if (snake.coor[0].y < 480 )
snake.coor[0].y += snake.speed;
else snake.coor[0].y = 0;
break;
case LEFT:
if (snake.coor[0].x > 0)
snake.coor[0].x-=snake.speed;
else snake.coor[0].x = 640;
break;
case RIGHT:
if (snake.coor[0].x < 640)
snake.coor[0].x += snake.speed;
else snake.coor[0].x = 0;
break;
}
}
void EatFood()
{
if (snake.coor[0].x - food.x > -10&& snake.coor[0].x - food.x < 10)
{
if (snake.coor[0].y - food.y > -10 && snake.coor[0].y - food.y < 10)
{
food.op = 0;
snake.size++;
food.score=(snake.size) * 10;
}
}
}
void KeyControl()
{
ExMessage msg;
while(peekmessage(&msg,EX_KEY))
{
if (msg.message == WM_KEYDOWN)
{
switch (msg.vkcode)
{
case 'w':
case 'W':
case 72:
if (snake.dir != DOWN)
snake.dir = UP;
break;
case 's':
case 'S':
case 80:
if (snake.dir != UP)
snake.dir = DOWN;
break;
case 'a':
case 'A':
case 75:
if (snake.dir != RIGHT)
snake.dir = LEFT;
break;
case 'd':
case 'D':
case 77:
if (snake.dir != LEFT)
snake.dir = RIGHT;
break;
}
}
if (msg.message == WM_KEYUP)
{
switch (msg.vkcode)
{
case 'w':
case 'W':
case 72:
if (snake.dir != DOWN)
snake.dir = UP;
break;
case 's':
case 'S':
case 80:
if (snake.dir != UP)
snake.dir = DOWN;
break;
case 'a':
case 'A':
case 75:
if (snake.dir != RIGHT)
snake.dir = LEFT;
break;
case 'd':
case 'D':
case 77:
if (snake.dir != LEFT)
snake.dir = RIGHT;
break;
}
}
}
}
int HeadHit()
{
int i = 1;
while (i < snake.size)
{
if (snake.coor[0].x == snake.coor[i].x && snake.coor[0].y == snake.coor[i].y)
return 0;
i++;
}
return 1;
}
void ProFood()
{
food.x = rand() % 630+10;
food.y = rand() % 470+10;
for (int i = 0; i < snake.size; i++)
{
if (food.x == snake.coor[i].x && food.y == snake.coor[i].y)
{
food.x = rand() % 630+10;
food.y = rand() % 470+10;
i = 0;
}
}
food.op = 1;
}
void Score()
{
char s[5];
sprintf_s(s, "%d", food.score);
outtextxy(640 / 2 - 70, 10, "分数为:");
outtextxy(640 / 2, 10, s);
}
void EndDraw()
{
BeginBatchDraw();
int i = 0;
/*while (snake.coor[i].x)
{
setfillcolor(RED);
solidcircle(snake.coor[i].x, snake.coor[i].y, R);
i++;
}*/
setfillcolor(RED);
solidcircle(snake.coor[0].x, snake.coor[0].y, R);
setfillcolor(WHITE);
solidcircle(snake.coor[1].x, snake.coor[1].y, R);
outtextxy(640 / 2 - 50, 480 / 2, "再来一把输入R/r");
outtextxy(640 / 2 - 50, 480 / 2 + 50, "输入任意键退出");
EndBatchDraw();
}
int ClearDevice()
{
ExMessage msg;
while (peekmessage(&msg, EX_KEY))
{
if (msg.message == WM_KEYDOWN)
{
switch (msg.vkcode)
{
case 'R':
case 'r':
main();
break;
default:
return 0;
break;
}
}
if (msg.message == WM_KEYUP)
{
switch (msg.vkcode)
{
case 'R':
case 'r':
ClearDevice();
main();
break;
default:
return 0;
break;
}
}
}
return 1;
}
void Final()
{
cleardevice();
settextcolor(RED);
settextstyle(100, 0, _T("Consolas"));
int i = 0;
for(i=0;i<200;i++)
{
outtextxy(640 / 2 - i, 480 / 2 - i, "GAME OVER");
Sleep(30);
}
int j;
for(j=0;j<180;j++)
{
outtextxy(640 / 2 - i-j, 480 / 2 -i+j, "GAME OVER");
Sleep(30);
}
for (int h = 0; h < 190; h++)
{
outtextxy(640 / 2 - i - j+h, 480 / 2 - i + j, "GAME OVER");
Sleep(30);
}
system("pause");
}
int main()
{
GameInit(); //初始化游戏
GameDraw(); //游戏绘制
while (HeadHit())
{
GameDraw();
Snakemove(); //蛇的移动
KeyControl(); //键位控制
if (!food.op) ProFood();//生成食物
EatFood(); //判断是否吃了食物
Score(); //当前分数
Sleep(50);
}
EndDraw(); //头和身体碰撞后
while (ClearDevice()); //读取输入的键位
Final(); //游戏结束画面
}
分析代码:
一.初始化游戏
1.初始化游戏数据
#define SNAKE_NUM 500 //蛇最大的长度
#define R 5 //半径
struct Data //记录蛇的坐标的结构体
{
int x;
int y;
};
struct Snake //记录蛇的信息
{
int size;
int dir; //方向
int speed;
Data coor[SNAKE_NUM];//蛇坐标数组
}snake;
struct Food //关于生成食物的结构体
{
int x;
int y;
int op = 0; //判断地图上是否已有食物
int score; //记录分数
}food;
enum //方向
{
UP,
DOWN,
LEFT,
RIGHT
};
2.地图初始化
void GameInit()
{
initgraph(640, 480, 0); //窗口大小
srand(GetTickCount()); //随机数种子
snake.size = 3;
snake.speed = 10;
snake.dir = RIGHT;
for (int i = 0, j = snake.size - 1; i < snake.size; i++, j--)
{
snake.coor[i].x = 10 * j + 4 * R;
snake.coor[i].y = 10;
}
food.x = rand() % 630+10;
food.y = rand() % 470+10;
}
二.地图的绘制
void GameDraw()
{
BeginBatchDraw(); //绘图缓冲
setbkcolor(RGB(20, 50, 105));
cleardevice();
setfillcolor(YELLOW);
solidcircle(snake.coor[0].x, snake.coor[0].y, R); //绘制蛇头
int i = 1;
while (snake.coor[i].x)
{
setfillcolor(WHITE);
solidcircle(snake.coor[i].x, snake.coor[i].y, R);//绘制蛇身
i++;
}
setfillcolor(BLACK);
if(food.op) solidcircle(food.x, food.y, R); //判断当前是否有食物
EndBatchDraw(); //绘图缓冲
}
当前界面
三.键盘控制
1.获取键盘信息
这样可以在easyx的窗口流畅地获取键盘输入的键位,而不是黑色的命令窗口
void KeyControl()
{
ExMessage msg;
while(peekmessage(&msg,EX_KEY)) //获取键盘信息
{
if (msg.message == WM_KEYDOWN) //按下某个键
{
switch (msg.vkcode) //按下的键位
{
case 'w':
case 'W':
case 72:
if (snake.dir != DOWN)
snake.dir = UP;
break;
case 's':
case 'S':
case 80:
if (snake.dir != UP)
snake.dir = DOWN;
break;
case 'a':
case 'A':
case 75:
if (snake.dir != RIGHT)
snake.dir = LEFT;
break;
case 'd':
case 'D':
case 77:
if (snake.dir != LEFT)
snake.dir = RIGHT;
break;
}
}
if (msg.message == WM_KEYUP) //松开某个键
{
switch (msg.vkcode) //按下的键位
{
case 'w':
case 'W':
case 72:
if (snake.dir != DOWN)
snake.dir = UP;
break;
case 's':
case 'S':
case 80:
if (snake.dir != UP)
snake.dir = DOWN;
break;
case 'a':
case 'A':
case 75:
if (snake.dir != RIGHT)
snake.dir = LEFT;
break;
case 'd':
case 'D':
case 77:
if (snake.dir != LEFT)
snake.dir = RIGHT;
break;
}
}
}
}
2.根据键盘的操作移动蛇
void Snakemove()
{
for (int i = snake.size-1; i >=1; i--) //让最后一个等于前一个蛇身的坐标(不包含蛇头)
{
snake.coor[i] = snake.coor[i - 1];
}
switch (snake.dir) //按键引起蛇头坐标的改变
{
case UP: //穿过墙体后到达另外一边
if(snake.coor[0].y>0)
snake.coor[0].y-=snake.speed;
else snake.coor[0].y = 480;
break;
case DOWN:
if (snake.coor[0].y < 480 )
snake.coor[0].y += snake.speed;
else snake.coor[0].y = 0;
break;
case LEFT:
if (snake.coor[0].x > 0)
snake.coor[0].x-=snake.speed;
else snake.coor[0].x = 640;
break;
case RIGHT:
if (snake.coor[0].x < 640)
snake.coor[0].x += snake.speed;
else snake.coor[0].x = 0;
break;
}
}
四.食物
1.生成食物
void ProFood()
{
food.x = rand() % 630+10;
food.y = rand() % 470+10;
for (int i = 0; i < snake.size; i++)
{
if (food.x == snake.coor[i].x && food.y == snake.coor[i].y)
{ //判断食物是否在蛇上
food.x = rand() % 630+10;
food.y = rand() % 470+10;
i = 0;
}
}
food.op = 1; //1代表已有食物
}
2.蛇吃食物
void EatFood() //由于都是⚪所以圆心距为两个半径就为吃到食物
{
if (snake.coor[0].x - food.x > -10&& snake.coor[0].x - food.x < 10)
{
if (snake.coor[0].y - food.y > -10 && snake.coor[0].y - food.y < 10)
{
food.op = 0; //食物已被吃
snake.size++;//蛇长加一
food.score=(snake.size) * 10;//分数加10
}
}
}
五.游戏结束
1.蛇头碰到蛇尾
int HeadHit()
{
int i = 1;
while (i < snake.size)
{
if (snake.coor[0].x == snake.coor[i].x && snake.coor[0].y == snake.coor[i].y)
return 0;
i++;
}
return 1;
}
2.更换画面(游戏说明)
void EndDraw()
{
BeginBatchDraw();
int i = 0;
/*while (snake.coor[i].x)
{
setfillcolor(RED);
solidcircle(snake.coor[i].x, snake.coor[i].y, R);
i++;
}*/
setfillcolor(RED);
solidcircle(snake.coor[0].x, snake.coor[0].y, R);
setfillcolor(WHITE);
solidcircle(snake.coor[1].x, snake.coor[1].y, R);
outtextxy(640 / 2 - 50, 480 / 2, "再来一把输入R/r");
outtextxy(640 / 2 - 50, 480 / 2 + 50, "输入任意键退出");
EndBatchDraw();
}
3.是否再来一局(输入R/r)
int ClearDevice()
{
ExMessage msg;
while (peekmessage(&msg, EX_KEY))
{
if (msg.message == WM_KEYDOWN)
{
switch (msg.vkcode)
{
case 'R':
case 'r':
main(); //又回到main函数继续
break;
default:
return 0;
break;
}
}
if (msg.message == WM_KEYUP)
{
switch (msg.vkcode)
{
case 'R':
case 'r':
ClearDevice();
main();
break;
default:
return 0;
break;
}
}
}
return 1;
}
*4.绘制GAME OVER(娱乐)
void Final()
{
cleardevice();
settextcolor(RED);
settextstyle(100, 0, _T("Consolas"));
int i = 0;
for(i=0;i<200;i++)
{
outtextxy(640 / 2 - i, 480 / 2 - i, "GAME OVER");
Sleep(30);
}
int j;
for(j=0;j<180;j++)
{
outtextxy(640 / 2 - i-j, 480 / 2 -i+j, "GAME OVER");
Sleep(30);
}
for (int h = 0; h < 190; h++)
{
outtextxy(640 / 2 - i - j+h, 480 / 2 - i + j, "GAME OVER");
Sleep(30);
}
system("pause");
}
六.main函数
int main()
{
GameInit(); //初始化游戏
GameDraw(); //游戏绘制
while (HeadHit())
{
GameDraw();
Snakemove(); //蛇的移动
KeyControl(); //键位控制
if (!food.op) ProFood();//生成食物
EatFood(); //判断是否吃了食物
Score(); //当前分数
Sleep(50); //减慢绘图速度
}
EndDraw(); //结束画面
while (ClearDevice()); //判断按下的键位
Final(); //最后的画面
}
谢谢浏览,给个赞吧