您的位置:首页 > 其它

Easyx库-贪吃蛇小游戏

2016-03-28 13:26 387 查看
#include <graphics.h>
#include <string.h>
#include <stdio.h>             //sprintf将整数转换为字符串
#include <time.h>              //srand产生随机数
#define SQU_LONG 15            //正方形的长
#define SQU_NUMBER 30          //正方形个数
#pragma comment(lib,"Winmm.lib")               //导入音乐头文件

IMAGE img,right,stop,play,fail,change;         //定义背景,右边,游戏暂停,正在游戏,游戏失败,分数改变图片
int NUM=3;                                     //节点个数
char score[5];                                 //存储分数的字符串
int foodx,foody;                               //食物的坐标,用于批绘制

void food();                            //产生食物
void snakeMove();                       //蛇移动
int Direction(int savec);               //控制方向
void eat();                             //吃食物
void over();                            //蛇死亡

struct snake
{
int x;                      //蛇头x坐标
int y;                      //蛇头y坐标
int dire;                   //蛇头方向
struct snake *next;         //结构体指针
};
struct snake *head=(snake *)malloc(sizeof(snake));           //定义头指针
struct snake *p;                                             //用于遍历结构体
struct snake saveLast,saveBody;                              //saveLast用于保存前一个节点,saveBody用于保存后一个节点

void main()//主方法
{
initgraph(SQU_LONG*SQU_NUMBER+200,SQU_LONG*SQU_NUMBER);		    //创建画布
loadimage(&img,"image/bk_picture.jpg");                         //读取背景图片
putimage(0,0,&img);                                             //在坐标(0,0)处放置背景图片
loadimage(&right,"image/right.jpg");
putimage(495,0,&right);
settextcolor(WHITE);											//文字颜色为白色
setbkmode(TRANSPARENT);                                         //文字背景为透明
settextstyle(20,0,"楷体");                                      //文字字号为20,正常宽度,字体为楷体
outtextxy(530,40,"游戏规则:");                                 //在坐标(530,70)处输出“游戏规则”四个字,只能输出字符串格式
outtextxy(502,70,"方向键控制方向");
outtextxy(502,90,"  Space键暂停");
outtextxy(502,110,"  Shift键加速");
loadimage(&play,"image/play.jpg");
putimage(495,290,&play);
mciSendString("open music/bk_audio.mp3 alias bk_audio",NULL,0,NULL);            //读取背景音乐文件并命名为bk_audio
mciSendString("play bk_audio repeat",NULL,0,NULL);                              //repeat为循环播放

int x,y;                                        //蛇头坐标
srand((unsigned)time(NULL));                    //产生随机数的语句,与rand()连用
do
{
x=rand()%SQU_LONG*SQU_NUMBER;               //先算求余,后算乘法,随机产生蛇头的坐标
y=rand()%SQU_LONG*SQU_NUMBER;
}while(x>SQU_LONG*(SQU_NUMBER-3)||y>SQU_LONG*(SQU_NUMBER-3)||x<3*SQU_LONG||y<3*SQU_LONG);             //不能出现在四周靠边的位置
struct snake *a=(snake *)malloc(sizeof(snake));             //用于存储蛇头
struct snake *b=(snake *)malloc(sizeof(snake));             //一开始出现的第一节身子
struct snake *c=(snake *)malloc(sizeof(snake));             //一开始出现的第二节身子
p=head;                           //p指向head
p->next=a;
a->x=x;
a->y=y;
a->dire=rand()%4+1;               //a为蛇头,随机产生方向
a->next=b;
b->next=c;
c->next=NULL;	                  //一开始只有一个蛇头两个身子,最后一个身子无指向
p=p->next;                        //p指向蛇头
setfillcolor(RED);                //设置填充颜色红色,表示蛇头
bar(p->x,p->y,p->x+SQU_LONG-1,p->y+SQU_LONG-1);              //在(p->x,p->y)处画一个长度为SQU_LONG的填充红色的正方形
saveLast.x=p->x;                  //将移动前蛇头信息保存为上一个节点的信息
saveLast.y=p->y;
saveLast.dire=p->dire;
saveLast.next=p->next;
if(p->dire==1)
p->x-=SQU_LONG;         //向左,p->x-1
else if(p->dire==2)
p->y-=SQU_LONG;         //向上,p->y-1
else if(p->dire==3)
p->x+=SQU_LONG;         //向右,p->x+1
else if(p->dire==4)
p->y+=SQU_LONG;         //向下,p->y+1
setfillcolor(RED);          //移动后重新画蛇头
bar(p->x,p->y,p->x+SQU_LONG-1,p->y+SQU_LONG-1);              //在移动后坐标处画一个长度为SQU_LONG的填充红色的正方形
p=p->next;                  //p指向第一个身子
while(p)                           //p不为空就进入循环,一开始设置链表有三个节点,一共可进入两次
{
saveBody.x=p->x;               //将移动后的信息保存为现在节点的信息
saveBody.y=p->y;
saveBody.dire=p->dire;
p->x=saveLast.x;               //重新将保存的移动前的信息读取出,赋给当前p指向的身子
p->y=saveLast.y;
p->dire=saveLast.dire;
saveLast.x=saveBody.x;         //保存的移动前的失去作用,重新将移动后的再作为上一个节点,保证蛇每个身子记录前一个身子的信息
saveLast.y=saveBody.y;
saveLast.dire=saveBody.dire;
setfillcolor(YELLOW);          //设置填充颜色黄色,表示蛇身子
bar(p->x,p->y,p->x+SQU_LONG-1,p->y+SQU_LONG-1);		        //在读取到信息的坐标处画一个长度为SQU_LONG的填充黄色的正方形
p=p->next;                     //p指向下一个身子
}
food();                      //调用生成食物方法
snakeMove();	             //调用蛇移动方法
}

void food()//生成食物
{
int x,y;                             //食物坐标
do
{
x=rand()%SQU_LONG*SQU_NUMBER+SQU_LONG;
y=rand()%SQU_LONG*SQU_NUMBER+SQU_LONG;
}while(getpixel(x,y)==RED||getpixel(x,y)==YELLOW||x>SQU_LONG*(SQU_NUMBER-1)||y>SQU_LONG*(SQU_NUMBER-1));        //不能出现在蛇头和蛇身上还有边框右边和下边
foodx=x;                             //将坐标保存为全局变量,用于其他方法批绘制
foody=y;
}

void snakeMove()//蛇移动
{
int i,savec;                //savec用于在选择方向是临时保存
while(1)
{
p=head->next;                              //p指向蛇头
saveLast.x=p->x;                           //依然是将移动前蛇头信息保存为上一节点信息
saveLast.y=p->y;
saveLast.dire=p->dire;
if(p->dire==1)
p->x-=SQU_LONG;                        //向左,p->x-1
else if(p->dire==2)
p->y-=SQU_LONG;                        //向上,p->y-1
else if(p->dire==3)
p->x+=SQU_LONG;                        //向右,p->x+1
else if(p->dire==4)
p->y+=SQU_LONG;                        //向下,p->y+1
p=p->next;                                 //p指向第一个身子
while(p)
{
saveBody.x=p->x;                       //依然是将移动后信息保存为现在节点的信息
saveBody.y=p->y;
saveBody.dire=p->dire;
p->x=saveLast.x;
p->y=saveLast.y;
p->dire=saveLast.dire;
saveLast.x=saveBody.x;
saveLast.y=saveBody.y;
saveLast.dire=saveBody.dire;
p=p->next;                             //p指向第二个身子
}
p=head->next;                                         //p重新指向蛇头
if(getpixel(p->x,p->y)==YELLOW||p->x<0||p->y<0||p->x>(SQU_LONG*(SQU_NUMBER-1)+45)||p->y>SQU_LONG*(SQU_NUMBER-1))       //如果获取到蛇头坐标的颜色为黄色(蛇头覆盖在身子上)活着蛇头碰到边缘
over();	                                          //调用失败方法
else if(getpixel(p->x,p->y)==GREEN)                   //如果蛇头坐标的颜色为绿色(蛇头覆盖在食物上,代表吃掉食物)
{
mciSendString("open music/eat_food.mp3 alias eat_food",NULL,0,NULL);           //调用吃掉食物的音乐
mciSendString("play eat_food from 0",NULL,0,NULL);                             //from 0为播放一次
eat();                                            //调用吃食物方法
food();                                           //调用生成食物方法
}
BeginBatchDraw();                                                 //开始批绘制
putimage(0,0,&img);                                               //每一次绘制都需要刷新,所以每次都需要调用背景图片
p=head->next;
setfillcolor(RED);                                    //移动后重新画蛇头
bar(p->x,p->y,p->x+SQU_LONG-1,p->y+SQU_LONG-1);
p=p->next;
while(p)
{
setfillcolor(YELLOW);                             //移动后重新画身子
bar(p->x,p->y,p->x+SQU_LONG-1,p->y+SQU_LONG-1);
p=p->next;
}
setfillcolor(GREEN);                                              //设置填充颜色为绿色,表示食物
bar(foodx,foody,foodx+SQU_LONG-1,foody+SQU_LONG-1);               //绿色代表食物
outtextxy(540,200,"得分:");
sprintf(score,"%d",(NUM-3)*10);                                   //将整数(NUM-3)*10转换为字符串保存在score中
loadimage(&change,"image/score.jpg");
putimage(495,220,&change);
outtextxy(546,220,score);
FlushBatchDraw();                                                 //每更新一次绘制一次
p=head->next;
for(i=0;i<5;i++)
{
Sleep(NUM<20?(200-4*NUM):100);	                              //蛇移动停顿的时间,随着吃的食物个数的增多停顿时间减少,减少到0.1秒后保持不变
savec=p->dire;                                                //将蛇头原来的方向保存到savec中
p->dire=Direction(savec);                                     //调用按键方法并传递savec参数
if(p->dire==5)                                                //如果选择了加速按键
{
p->dire=savec;                                            //方向仍然是原方向
break;                                                    //跳出循环,不停顿
}
}
EndBatchDraw();                                                   //关闭批量绘图
}
}

int Direction(int savec)//按键
{
p=head->next;                                              //p指向蛇头
if(p->dire!=3&&GetAsyncKeyState(VK_LEFT)&0x8000)           //如果原来方向不向右并且按下左键
p->dire=1;
else if(p->dire!=4&&GetAsyncKeyState(VK_UP)&0x8000)        //如果原来方向不向下并且按下上键
p->dire=2;
else if(p->dire!=1&&GetAsyncKeyState(VK_RIGHT)&0x8000)     //如果原来方向不向左并且按下右键
p->dire=3;
else if(p->dire!=2&&GetAsyncKeyState(VK_DOWN)&0x8000)      //如果原来方向不向上并且按下下键
p->dire=4;
else if(GetAsyncKeyState(VK_SHIFT)&0x8000)                 //按shift键
p->dire=5;
else if(GetAsyncKeyState(VK_SPACE)&0x8000)                 //按空格键
{
loadimage(&stop,"image/stop.jpg");
putimage(495,290,&stop);                               //更新游戏暂停图片
FlushBatchDraw();                                      //批绘制
mciSendString("stop bk_audio",NULL,0,NULL);            //暂停,音乐停止
system("pause");                                       //暂停,按任意键继续
loadimage(&play,"image/play.jpg");
putimage(495,290,&play);                               //更新正在游戏图片
FlushBatchDraw();                                      //批绘制
mciSendString("play bk_audio",NULL,0,NULL);            //音乐重新从上一次结束的地方播放
p->dire=savec;                   //暂停结束继续向同一个方向走
}
else
p->dire=savec;                   // 若是没有选择依然是原先的方向
return p->dire;
}

void over()//结束
{
loadimage(&fail,"image/fail.jpg");
putimage(495,290,&fail);                              //更新游戏失败图片
FlushBatchDraw();                                     //批绘制
mciSendString("stop bk_audio",NULL,0,NULL);	          //结束,音乐停止
system("pause");
exit(0);                                              //退出到控制台
}

void eat()//吃食物
{
p=head;
while(p->next!=NULL)                                  //若p不是尾节点,则继续进入循环遍历
p=p->next;
struct snake *a=(snake *)malloc(sizeof(snake));       //重新声明一个节点,用于添加身子
a->x=saveLast.x;                                      //将最后保存的节点信息赋给新节点
a->y=saveLast.y;
a->dire=saveLast.dire;
a->next=NULL;
p->next=a;                                            //连接到链表中
p=p->next;
NUM+=1;                                               //节点个数加1
}


源代码文件http://pan.baidu.com/s/1ge9s7WB
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: