大学课程中所编写的贪吃蛇游戏
/********************************************************************************
* @File name: Snake
* @Description:基于c语言和easyx库的贪吃蛇程序的实现
* @Author: Sky_Codes
* @Version: 0.51
* @Date: 2019-12-01
********************************************************************************/
#include
#include
#include //easyx图形库
#include //媒体库
#include
#include
#include
#pragma comment (lib,"Winmm.lib")
#define INIT_X 800//初始化界面宽度
#define INIT_Y 480//初始化界面高度
#define SNAKE_LEN 3 //初始化小蛇长度
/*声明结构体*/
typedef enum ch //枚举 按键的数值
{
up = 119, //向上 W
down = 115,//向下 S
left = 97, //向左 A
right = 100,//向右 D
esc = 27, //退出 ESC
addSpeed = 113,//加速 Q
subSpeed = 101,//减速 E
stop = 32 //暂停 space空格
}Ch;
struct coor //坐标
{
int x; int y;//x、y坐标数值
};
struct food //食物结构体
{
struct coor fcr;//食物的坐标
int flag;//判断食物是否被吃,被吃后置反
}Food;
struct snake //小蛇结构体
{
struct coor scr[100];//蛇身长度限制
int len;//小蛇实际长度
Ch ch;//小蛇当前的朝向
int score;//得分
int speed;//速度
}Snake;
/*声明函数*/
void playMusic();/*播放背景音乐*/
void initGame();//初始化游戏界面
void initWelcome();//初始化进入页面
void playWhile();//游戏中循环函数
void initSnake();//初始化小蛇
void snakeMove(); //小蛇的移动
void snakeDraw();//画出小蛇
void getKey();//得到键值
void randFood();//随机食物
void foodDraw();//画出食物
void eatFood();//吃到食物
int eatSelforWall();//吃到自己或者撞墙
void getFlagKey();//按键去除移动其他按键的功能实现
void gameEnd();//死亡后是否结束游戏或者再开始
void gameOver(); //游戏结束
void againInit();//死亡后再进行游戏,进行初始化
void display_msg();//展示信息
/*声明所需各个需求变量*/
char scroe_s[100] = {'0'};//分转换字符数组中间变量
char font[2][10] = { "宋体","黑体" };//字体选择
char goder[20] = "【作者】SKY";//欢迎界面信息
char vision[20] = "【版本】0.51";//欢迎界面信息
char gameName[20] = "C---贪吃蛇";//欢迎界面标题
char songBgm[2][30] = { "open BGM.mp3 alias ACE" ,"play ACE repeat" };//背景音乐
char speak[5][20] = { "【得分】","【速度】","【长度】" };//游戏界面的数据展示
char speak2[5][20] = { "【最高得分】","【最快速度】","【最佳长度】" };//游戏界面的数据展示
int flagKey = 0;//判断除去方向按键其他按键的选择标识符
int speed = 100;//小蛇速度
int maxScore = 0, maxSpeed = 100, maxLen = 3;//保留最佳成绩
/*******************************************************
*
* Function name :main
* Description : 程序主函数
* Return :0 正常退出
**********************************************************/
int main()
{
playMusic();//播放音乐
initWelcome();//欢迎界面
system("pause");//用户按任意键进入游戏
cleardevice();//清除界面
closegraph();//关闭此画布
initgraph(INIT_X, INIT_Y);//初始化游戏窗口大小900*600
initGame();//初始化画布
initSnake();//初始化小蛇
Food.flag = 1;//置食物标识符为1,去生成第一个随即食物*/
playWhile();//游戏进行期间
return 0;
}
/*******************************************************
*
* Function name :initWelcome
* Description : 初始化进入页面,向玩家展示操作规则
* Return :无
**********************************************************/
void initWelcome()
{
initgraph(INIT_X,INIT_Y);//建立画布
setfillcolor(RGB(255,200, 215));//调节画布颜色
solidrectangle(0, 0, INIT_X,INIT_Y/2);//提取画布上半部矩形区域
setcolor(RGB(120, 200, 150));
settextstyle(40, 20, font[0]);//设置字体属性
setbkmode(TRANSPARENT);//设置背景为透明
outtextxy(110, 50, gameName);//在具体位置输出相关文字
settextstyle(20, 10, font[1]);
outtextxy(110, 100, goder);
outtextxy(110, 130, vision);
setfillcolor(RGB(255,200, 215));//调节画布颜色
solidrectangle(0, INIT_Y/2, INIT_X, INIT_Y);//提取画布下半部矩形区域ju
RECT r = {0,INIT_Y/2,400,INIT_Y};//得到在下半部分矩形中的部分区域
settextcolor(BLACK);//设置字体颜色
settextstyle(15, 0, "仿宋");//设置字体大小、风格
drawtext(_T("【功能按键】\n W->上 S->下 \n A->左 D->右\n Q->加速 E->减速\n 空格->暂停 ESC->退出\n"), &r, DT_LEFT);//在r矩阵中展示的语句
RECT r2= { 0,INIT_Y/2+100,400,INIT_Y};
settextcolor(BLACK);
settextstyle(20, 0, "仿宋");//设置字体大小、风格
drawtext(_T("【提示】\n此游戏在英文输入法下进行操控\n按任意键进入游戏\n"), &r2, DT_LEFT);//展示的语句
}
/*******************************************************
*
* Function name :initGame
* Description : 初始化游戏界面,在界面中设置游戏进程中向玩家展示的语句
* Return :无
**********************************************************/
void initGame()
{
/*裁剪得到非游戏区域*/
setfillcolor(0xe6b8af);//设置填充颜色
solidrectangle(600, 0, 800, 480);//绘制矩形在裁剪区
//setbkcolor(RGB(200, 150, 120));
setcolor(RED);//设置颜色
settextstyle(30, 15, font[0]);//设置字体大小、风格
setbkmode(TRANSPARENT);//设置背景为透明
outtextxy(625, 50, gameName);//设置游戏名称
/*提示语句区域*/
RECT r = { 625, 100, 780, 200 };//创建一个矩形放置语句
settextstyle(15, 0, font[1]);//设置字体大小、风格
drawtext(_T("简单的贪吃蛇小游戏\n祝你好运\n"), &r, DT_CENTER);//展示的语句
sprintf(scroe_s, "%d", Snake.score);
outtextxy(600, 150, speak[0]);
outtextxy(680, 150, scroe_s);
sprintf(scroe_s, "%d", Snake.speed);
outtextxy(600, 180, speak[1]);
outtextxy(680, 180, scroe_s);
sprintf(scroe_s, "%d", Snake.len + 1);
outtextxy(600, 210, speak[2]);
outtextxy(680, 210, scroe_s);
RECT r2 = { 600, 240, 780, 480 };//创建一个矩形放置语句
settextstyle(15, 0, font[1]);//设置字体大小、风格
drawtext(_T("【功能按键】\n W->上 S->下 \n A->左 D->右\n Q->加速 E->减速\n 空格->暂停 ESC->退出\n"), &r2, DT_LEFT);//展示的语句
/*游戏区域的属性设置,背景颜色、区域大小*/
setfillcolor(0xf4cccc);
solidrectangle(0, 0, 600, 480);//绘制矩形
}
/*******************************************************
*
* Function name :againInit
* Description : 小蛇死亡后再进行游戏,进行相关属性的初始化
* Return :无
**********************************************************/
void againInit()
{
initGame();//初始化画布
initSnake();//初始化小蛇
Food.flag = 1;//置食物标识符为1,去生成第一个随即食物*/
playWhile();//进入游戏
}
/*******************************************************
*
* Function name :playWhile
* Description : 玩家游戏中循环函数,在玩家游戏时做出相应的动作响应玩家
* Return :无
**********************************************************/
void playWhile()
{
while (1)
{
while (!_kbhit())//判断是否有按键输入
{
snakeMove();//小蛇的移动
eatFood();//判断是否吃到食物
if (Food.flag == 1)//标识符为1
{
randFood(); //生成随机食物坐标
}
if (eatSelforWall())//函数返回值为1,游戏结束
{
gameEnd();//死亡后是否结束游戏或者再开始
}
foodDraw();//画出食物
Sleep(speed);//延时
//cleardevice();//以背景色清空画布
//initGame();
display_msg();//展示此时小蛇的属性信息
}
getKey();//玩家键值的输入
}
}
/*******************************************************
*
* Function name :display_msg
* Description : 玩家游戏过程中,对小蛇属性的及时的刷新展示
* Parameter :无
* Return :无
**********************************************************/
void display_msg()
{
/*写入一个新的矩形,覆盖之前的矩形,再写入小蛇的属性数据*/
setfillcolor(0x90b1e8);
solidrectangle(600,150,800,230);
settextcolor(BLACK);
sprintf(scroe_s, "%d", Snake.score);
outtextxy(600, 150, speak[0]);
outtextxy(680, 150, scroe_s);
sprintf(scroe_s, "%d", Snake.speed);
outtextxy(600, 180, speak[1]);
outtextxy(680, 180, scroe_s);
sprintf(scroe_s, "%d", Snake.len + 1);
outtextxy(600, 210, speak[2]);
outtextxy(680, 210, scroe_s);
}
/*******************************************************
*
* Function name :initSnake
* Description :对小蛇的各项属性进行初始化
* Parameter :无
* Return :无
**********************************************************/
void initSnake()
{
//设置小蛇的属性
setcolor(WHITE);
setfillcolor(WHITE);
fillroundrect(200, 100, 210, 110,8,6);
Snake.len = SNAKE_LEN;
Snake.scr[0].x = 200;
Snake.scr[0].y = 100;
Snake.ch = down;
Snake.score = 0;
Snake.speed = 100;
}
/*******************************************************
*
* Function name :snakeMove
* Description : 小蛇移动时,方向的确定和改变小蛇每个关节的坐标
* 并且将蛇尾消影
* Parameter :无
* Return :无
**********************************************************/
void snakeMove()
{
int i;
setfillcolor(0xf4cccc); //对蛇尾进行消影处理
//fillrectangle(Snake.scr[Snake.len].x,Snake.scr[Snake.len].y, Snake.scr[Snake.len].x+10, Snake.scr[Snake.len].y+10 );
solidrectangle(Snake.scr[Snake.len].x,Snake.scr[Snake.len].y, Snake.scr[Snake.len].x+10, Snake.scr[Snake.len].y+10 );
for (i = Snake.len; i > 0; i--) //改变小蛇的各个节位坐标,使之移动
{
Snake.scr[i].x = Snake.scr[i - 1].x;
Snake.scr[i].y = Snake.scr[i - 1].y;
}
switch (Snake.ch) //判断小蛇此时的方向,使之相应的坐标变化
{
case up: Snake.scr[0].y -= 10;
break;
case down:Snake.scr[0].y += 10;
break;
case left:Snake.scr[0].x -= 10;
break;
case right:Snake.scr[0].x += 10;
break;
}
snakeDraw();//画出改变后的小蛇
}
/*******************************************************
*
* Function name :snakeDraw
* Description : 画出位置改变后的小蛇,并随机改变小蛇每节的颜色
* Return :无
**********************************************************/
void snakeDraw()
{
srand((unsigned)time(NULL));
int i,color;
for (i = Snake.len; i >= 0; i--)
{
color = rand()%4; //随机选择设置小蛇每节颜色
switch(color)
{
case 0:setfillcolor(RGB(30, 144, 255)); break;
case 1:setfillcolor(RGB(245, 5, 90)); break;
case 2:setfillcolor(RGB(125, 62, 74)); break;
case 3:setfillcolor(RGB(20, 7, 9)); break;
}
//fillrectangle(Snake.scr[i].x, Snake.scr[i].y, Snake.scr[i].x + 10, Snake.scr[i].y + 10);
fillroundrect(Snake.scr[i].x, Snake.scr[i].y, Snake.scr[i].x + 10, Snake.scr[i].y + 10,8,6);
}
}
/*******************************************************
*
* Function name :getKey
* Description : 对于玩家输入的按键处理,进行相应的响应
* Parameter :无
* Return :无
**********************************************************/
void getKey()
{
int getkey;
getkey = _getch();//此处使用了c++改变后的_getch()语句,得到玩家输入的键值,无需敲打回车
switch (getkey)//判断玩家输入的键值,如果与小蛇此时的方向相反,不给予响应
{
case up: if (Snake.ch != down) Snake.ch = up;
break;
case down:if (Snake.ch != up) Snake.ch = down;
break;
case left:if (Snake.ch != right) Snake.ch = left;
break;
case right:if (Snake.ch != left) Snake.ch = right;
break;
case esc:flagKey = 1;
break;
case addSpeed:flagKey = 2;
break;
case subSpeed:flagKey = 3;
break;
case stop:flagKey = 4;
break;
}
getFlagKey();//除去方向按键其他功能性按键的实现
}
/*******************************************************
*
* Function name :randFood
* Description : 随机生成食物坐标
* Parameter :无
* Return :函数返回值的说明
**********************************************************/
void randFood()
{
srand((unsigned)time(NULL));//种子
//得到的随机数应为10的倍数
Food.fcr.x = rand() % (600 / 10) * 10;
Food.fcr.y = rand() % (480 / 10) * 10;
Food.flag = 1;//重新将食物标识符设为1,表示已生成一个食物
}
/*******************************************************
*
* Function name :foodDraw
* Description : 在画布中画出食物
* Parameter :无
* Return :函数返回值的说明
**********************************************************/
void foodDraw()
{
//cleardevice();
fillrectangle(Food.fcr.x, Food.fcr.y, Food.fcr.x + 10, Food.fcr.y + 10);//画出食物
Food.flag = 0;//食物标识符置反
}
/*******************************************************
*
* Function name :函数名称
* Description : 小蛇吃到食物进行蛇身的加长和得分的增加和食物的标识符变化
* Parameter :无
* Return :无
**********************************************************/
void eatFood()
{
if (Snake.scr[0].x == Food.fcr.x && Snake.scr[0].y == Food.fcr.y)//蛇头与食物相遇的判断
{
Snake.len++;//小蛇长度加1
Snake.score += 10;//增加得分
Food.flag = 1;//置食物标识符
}
}
/*******************************************************
*
* Function name :eatSelforWall
* Description : 判断是否吃到自己或者撞墙
* Return :返回1 撞墙或者蛇头与自身相遇 返回0 游戏继续
**********************************************************/
int eatSelforWall()
{
int i;//循环使用变量
//是否撞墙
if (Snake.scr[0].x == 0 || Snake.scr[0].y == 480 || Snake.scr[0].x == 600 || Snake.scr[0].y == 0)
return 1;
//是否吃到自己
for (i = 1; i < Snake.len; i++)
{
if (Snake.scr[0].x == Snake.scr[i].x && Snake.scr[0].y == Snake.scr[i].y)
return 1;
}
return 0;
}
/*******************************************************
*
* Function name :getFlagKey
* Description : 除去方向按键其他功能性按键的实现
* Return :无
**********************************************************/
void getFlagKey()
{
if (flagKey == 1) //退出 ESC
{
flagKey = 0; closegraph(); exit(0);
}
else if (flagKey == 2) //加速 Q
{
flagKey = 0; speed -= 10; Snake.speed += 10;
if (speed <= 50) { speed = 50; Snake.speed = 150; }
}
else if (flagKey == 3)//减速 E
{
flagKey = 0; speed += 10; Snake.speed -= 10;
if (speed >= 150) { speed = 150; Snake.speed = 50; }
}
else if (flagKey == 4)//space空格
{ flagKey = 0; system("pause"); }
}
/*******************************************************
*
* Function name :gameEnd
* Description : 死亡后是否结束游戏或者再开始
* Parameter :无
* Return :无
**********************************************************/
void gameEnd()
{
/*得到每次游戏后的各项指标的最大值*/
maxScore = maxScore > Snake.score ? maxScore : Snake.score;
maxLen = maxLen > Snake.score ? maxLen : Snake.len;
maxSpeed = maxSpeed > Snake.speed ? maxSpeed : Snake.speed;
/*输出提示信息*/
RECT r3 = { 100,100,400,300 };
setbkmode(TRANSPARENT);//设置背景为透明
settextcolor(WHITE);
settextstyle(50, 25, "黑体");
drawtext(_T("游 戏 结 束"), &r3, DT_CENTER);
RECT r4 = { 100,300,400,600 };
settextstyle(30, 15, "仿宋");
drawtext(_T("【双击】\nE【再来一局】\nQ【退出游戏】\n"),&r4,DT_LEFT);
system("pause");
int getKey;
getKey = _getch();//得到玩家键值,反馈相应信息
switch (getKey)
{
case 113: gameOver();//退出
break;
case 101: againInit();//再来一局
break;
}
}
/*******************************************************
*
* Function name :gameOver
* Description : 游戏结束函数
* Return :无
**********************************************************/
void gameOver()
{
//system("pause");
cleardevice();//清空并关闭画布
closegraph();
initgraph(500,200);//建立结束画布
int x=400, y=20, speed=0,r=50,flag=0;//设置跳动小球的参数
while (1)/*输出本次游戏的最佳成绩和小球弹跳动画*/
{
setfillcolor(RGB(47, 79, 79));
settextstyle(40, 20, font[0]);
outtextxy(120, 50, "游戏结束");
settextcolor(RGB(255, 255, 224));
settextstyle(20, 10, font[1]);
sprintf(scroe_s, "%d", maxScore);
outtextxy(80, 100, speak2[0]);
outtextxy(200, 100, scroe_s);
sprintf(scroe_s, "%d", maxSpeed);
outtextxy(80, 140, speak2[1]);
outtextxy(200, 140, scroe_s);
sprintf(scroe_s, "%d", maxLen+1);
outtextxy(80, 180, speak2[2]);
outtextxy(200, 180, scroe_s);
/*小圆运动动画*/
circle(x, y, 30);
Sleep(50);
if (y > 180) { flag = 1; speed = -speed; }
if (y < 20) { flag = 0; speed = -speed; }
printf("%d %d\n", speed,y);
y = y + speed++;
if (y < 12) y = 20;
cleardevice();
}
}
/*******************************************************
*
* Function name :playMusic
* Description : 循环播放背景音乐
* Return :无
**********************************************************/
void playMusic()
{
//调用函数,播放音乐
mciSendString(songBgm[0], NULL, 0, NULL);
mciSendString(songBgm[1], NULL, 0, NULL);
}