编程总是对着一个黑窗口,可以说是非常乏味了,于是喵喵就翻出来了以前用easyx图形库做图形界面的贪吃蛇游戏。
不过大家只是当做提高编程的乐趣来学习吧,想进一步做的话可以学习QT,还有其他的框架。
这是一个easyx图形库的学习教程,建议大家学完再看本文:
https://www.easyx.cn/skills/List.aspx?id=7
首先看一下效果图:
实现的功能:
基本的吃食物长大,撞墙死亡,特殊食物,游戏暂停,重开游戏,记分数的功能。
游戏最高分的记录。
游戏关卡的选择。
加了游戏的音效,具体的音效,可以在下面下载:
链接:https://pan.baidu.com/s/1NFn19J7gcXmG45jAuYe4Ig 密码:x5kz
一些说明:
这个程序用的基本是C,当时对C++类的理解实在太差,现在也懒的改了。
这个程序是万恶的VC写的,当时还没发现codeblocks啥的。
关于程序的功能实现,并不太难,有详细的注释,可以随意复制粘贴。
下面看贪吃蛇的代码:
#include "node.h"
class Food
{
public:
Food();
virtual ~Food();
int food;//0为无食物,1为有食物
node foodxy;
int c;//累计出现食物个数
}; Food::Food()
{
c=;
} Food::~Food()
{ } class node
{
public:
int x,y;
node();
virtual ~node(); };
#include "node.h"
class snake
{
public:
snake();
virtual ~snake();
node jie[];//蛇每个节点坐标
int n;//蛇当前节点数
char dry;//蛇当前前进方向
};
class wall
{
public:
node dry[];//障碍物的坐标
int n;//障碍物的个数
wall();
virtual ~wall(); };
#include<graphics.h>
#include<conio.h>
#include<time.h>
#include "snake.h"
#include "Food.h"
#include<stdio.h>
#include<fstream.h>
#include "mmsystem.h"//导入声音头文件
#pragma comment(lib,"winmm.lib")//导入声音头文件库
#include "wall.h"
int wallnum,speed; void zero();
void first();//操作页面初始化
int second( Food &, snake&);//数据初始化
void foodstyle(Food&,wall);//食物状态
void gameover(snake,int);//游戏结束
void judge( Food&,snake&,int,wall);//判断游戏是否结束
void judge2(Food &,snake&);//判断蛇是否吃到食物
void snakemove(Food&,snake&,wall);
void snakeshow(Food &,snake &,wall);
void change(Food &,snake &,int);//改变方向
void score(snake );//记录分数
void wallstyle(wall&);//障碍物的状态 int main()
{
initgraph(,);
int o;
Food F;
snake Snake;
wall Wall;
first();
zero();
o= second(F,Snake);
wallstyle(Wall);
PlaySound("kaichang.wav",NULL,SND_FILENAME|SND_ASYNC);//载入声音特效
while()
{
while(!kbhit())//没有键盘输入时
{ if(!F.food )
{
foodstyle(F,Wall);
}
judge(F,Snake,o,Wall);
judge2(F,Snake);
snakemove(F,Snake,Wall);
Sleep(speed);//控制速度
score(Snake);
}
change(F,Snake,o); }
return ;
} void zero()
{
char p[];
outtextxy(,,_T("关卡:"));
for(int i=;i<;i++)
{
RECT r= {+*i,,+*i,};//使数字显示在矩形区域*
sprintf(p, "%d", i+);
drawtext(p, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
settextstyle(, , _T("黑体"));
outtextxy(,,_T("请输入 1 or 2 or 3 确定关卡"));
char c=getch();//控制选择关卡
switch (c)
{
case '':
wallnum=;
speed=;
i=;
break;
case '':
wallnum=;
speed=;
i=;
break;
case '':
wallnum=;
speed=;
i=;
break;
default:
settextcolor(BLACK);//擦除
outtextxy(,,_T("请输入 1 or 2 or 3 确定关卡"));
settextcolor(RED);
outtextxy(,,_T("请正确输入"));
Sleep();//确保显示时间
main();
}
setfillcolor(GREEN);
RECT v= {+*(i-),,+*(i-),};
sprintf(p, "%d", i);
drawtext(p, &v, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
settextcolor(BLACK);
outtextxy(,,_T("请输入 1 or 2 or 3 确定关卡"));
settextcolor(RED);//确保以后的字体颜色
}
void first()
{
srand((unsigned)time(NULL));//播种子
setlinestyle(PS_DASH);//实线
settextcolor(RED);
setlinecolor(BLUE);
line(,,,);//分界线
line(,,,);
outtextxy(,,_T("分数:"));//操作说明
outtextxy(,,_T("最高分:"));
outtextxy(,,_T("操作方式:"));
outtextxy(,,_T(" W/w:上移 S/s:下移"));
outtextxy(,,_T(" A/a:左移 D/d:右移"));
outtextxy(,,_T(" 空格:暂停/开始"));
outtextxy(,,_T(" Esc:退出"));
outtextxy(,,_T(" 作者:丁喵喵"));
setlinecolor(BLUE);//示例图形
setfillcolor(GREEN);
fillcircle(,,);
fillcircle(,,);
setfillcolor(RED);
fillrectangle(,,,);
fillrectangle(,,,);
setfillcolor(BLACK);
fillcircle(,,);
outtextxy(,,_T("温馨提示:"));
outtextxy(,,_T("一.障碍物,撞击死亡"));
outtextxy(,,_T("四.被破坏障碍物,非无敌状态撞击仍会死亡"));
outtextxy(,,_T("二.特殊食物,吃掉冲撞障碍物不死亡"));
outtextxy(,,_T("三.蛇吃完特殊食物后的无敌状态"));
outtextxy(,,_T("五.只有蛇头时冲撞障碍物不死亡"));
} int second(Food & F,snake & Snake)
{
F.food=;//食物有无、蛇结束、位置、前进方向初始化
Snake.n=;
Snake.jie[].x=;
Snake.jie[].y=;
setfillcolor(RED);
fillcircle( Snake.jie[].x,Snake.jie[].y,);
Snake.dry='d';
ifstream inFile("scoremax.txt",ios::in);//读入文件
int o;
inFile>>o;
char p[];
sprintf(p, "%d", o);
settextstyle(, , _T("黑体"));
outtextxy(,,p);//最高分
sprintf(p, "%d", (Snake.n-)*);
outtextxy(,,p);//分数
return o;
} void foodstyle(Food & F,wall Wall)
{
if(!F.food)
{
F.foodxy.x=(rand()%)*+;//食物出现地点
F.foodxy.y=(rand()%)*+;
//确保食物不出现在障碍物及蛇初始位置
while((F.foodxy.x==&&F.foodxy.y==)||(F.foodxy.x==&&F.foodxy.y==))
{
F.foodxy.x=(rand()%)*+;
F.foodxy.y=(rand()%)*+;
}
for(int i=;i<Wall.n;i++)
{
if(F.foodxy.x==Wall.dry[i].x&&F.foodxy.y==Wall.dry[i].y)
{
foodstyle(F,Wall);
}
}
setlinestyle(PS_SOLID);
if((F.c+)%==&&(F.c+)!=)//判断是否为特殊食物
{
setfillcolor(GREEN);
}
else
{
setfillcolor(YELLOW);
}
fillcircle(F.foodxy.x,F.foodxy.y,);
F.food=;//食物状态为有
F.c++;//累计出现食物个数
}
}
void judge(Food & F,snake & Snake,int o,wall Wall)
{
if(Snake.jie[].x<=||Snake.jie[].x>=||Snake.jie[].y<=||Snake.jie[].y>=)
{//判断是否撞墙
PlaySound("zhuangqiang.wav",NULL,SND_FILENAME|SND_ASYNC);
Sleep();
gameover(Snake,o);
}
for(int i=;i<=Snake.n;i++)
{//判断是否咬到自己
if(Snake.jie[].x==Snake.jie[i].x&&Snake.jie[].y==Snake.jie[i].y)
{
PlaySound("yao.wav",NULL,SND_FILENAME|SND_ASYNC);
Sleep();
gameover(Snake,o);
}
}
for(i=;i<Wall.n;i++)
{//判断是否撞到障碍物
if(Snake.jie[].x<Wall.dry[i].x+&&Snake.jie[].y<Wall.dry[i].y+&&
Snake.jie[].x>Wall.dry[i].x-&&Snake.jie[].y>Wall.dry[i].y-)
{
if((F.c-)%!=&&F.c!=)//非无敌状态
{
PlaySound("zhuangqiang.wav",NULL,SND_FILENAME|SND_ASYNC);
Sleep();
gameover(Snake,o);
}
}
} } void judge2(Food & F,snake & Snake)
{
if(Snake.jie[].x==F.foodxy.x&&Snake.jie[].y==F.foodxy.y)//判断是否吃到食物
{
PlaySound("shiwu.wav",NULL,SND_FILENAME|SND_ASYNC);
setfillcolor(BLACK);//擦除
fillcircle(F.foodxy.x,F.foodxy.y,);
Snake.n++;//蛇结数增加
setfillcolor(BLUE);
fillcircle( F.foodxy.x,F.foodxy.y,);
F.food=;//食物被吃掉
}
}
void gameover(snake Snake,int o)
{
if(o<=(Snake.n-)*)//判断是否需要更改最高分
{
PlaySound("zhangsheng.wav",NULL,SND_FILENAME|SND_ASYNC);
ofstream outFile("scoremax.txt",ios::out);//写入文件
outFile<<(Snake.n-)*;
outFile.close();
}
else
{
PlaySound("Game_over.wav",NULL,SND_FILENAME|SND_ASYNC);
}
settextcolor(RED);
settextstyle(, , _T("黑体"));
outtextxy(,,_T("GAME OVER"));
settextstyle(, , _T("黑体"));
outtextxy(,,_T("是否重新开始"));
outtextxy(,,_T("YES(Y/y)"));
outtextxy(,,_T("NO(N/n)"));
char c=getch();//判断是否重新开始
if(c=='n'||c=='N')
{
closegraph();//关闭画布
}
else if(c=='y'||c=='Y')
{
main();
}
else//避免输入移动指令破坏画面
{
gameover(Snake,o);
} } void snakemove(Food & F,snake & Snake,wall Wall)
{
int i;
for (i=Snake.n ; i>; i--)//蛇身每一节移到前一节位置
{
Snake.jie[i].x = Snake.jie[i-].x;
Snake.jie[i].y = Snake.jie[i-].y;
}
switch (Snake.dry)//判断之前的移动方向 蛇头并按该方向移到
{
case 'W':
case 'w':
Snake.jie[].y-=;
break;
case 's':
case 'S':
Snake.jie[].y +=;
break;
case 'A':
case 'a':
Snake.jie[].x -=;
break;
case 'D':
case 'd':
Snake.jie[].x +=;
break;
};
snakeshow(F,Snake,Wall);//将结果显示
} void change(Food & F,snake & Snake,int o)
{
char key,p[];
IMAGE tmp;
int i;
key = getch();
switch (key)
{
case 'w':
case 'W':
if (Snake.dry !='s'&&Snake.dry !='S')//确保不反向移动
{
Snake.dry ='w';
}
break;
case 's':
case 'S':
if (Snake.dry !='w'&&Snake.dry !='W')
{
Snake.dry = 's';
}
break;
case 'a':
case 'A':
if (Snake.dry !='D'&&Snake.dry !='d')
{
Snake.dry = 'a';
}
break;
case 'd':
case 'D':
if (Snake.dry !='a'&&Snake.dry !='A')
{
Snake.dry = 'd';
}
break;
case' '://暂停 getimage(&tmp,,,,);//将该区域图像保存
settextstyle(, , _T("黑体"));
outtextxy(, , _T("任意键继续"));
PlaySound("stop.wav",NULL,SND_FILENAME|SND_ASYNC);
getch();
putimage(,,&tmp);//将保存图像返回,确保不破坏背景
for(i=;i>=;i--)//倒计时
{
settextstyle(, , _T("黑体"));
sprintf(p, "%d", i);
outtextxy(, , p);
Sleep();
putimage(,,&tmp);
}
PlaySound("start.wav",NULL,SND_FILENAME|SND_ASYNC);
break;
case :
gameover(Snake,o);//退出
break;
}
} void snakeshow(Food & F,snake & Snake,wall Wall)
{
int i;
for (i=Snake.n-; i>; i--)//蛇身
{
setfillcolor(BLUE);
fillcircle( Snake.jie[i].x,Snake.jie[i].y,);
}
if((F.c-)%==&&F.c!=)//特殊食物
{
setfillcolor(GREEN);
}
else
{
setfillcolor(RED);
}
fillcircle( Snake.jie[].x,Snake.jie[].y,);
setlinecolor(BLACK);
setfillcolor(BLACK);//擦除之前最后一节蛇身
fillcircle( Snake.jie[Snake.n].x,Snake.jie[Snake.n].y,);
if(Snake.n>)
{
setfillcolor(BLUE);
}
else
{
setfillcolor(RED);
}
fillcircle( Snake.jie[Snake.n-].x,Snake.jie[Snake.n-].y,);
} void score(snake Snake)
{
char p[];
sprintf(p, "%d", (Snake.n-)*);
settextcolor(BLACK);
outtextxy(,,p);
sprintf(p, "%d", (Snake.n-)*);
settextcolor(RED);
settextstyle(, , _T("黑体"));
outtextxy(,,p); } void wallstyle(wall & Wall)
{
Wall.n =wallnum;
for(int i=;i<Wall.n;i++)
{
Wall.dry[i].x=(rand()%)*+;//障碍物出现地点
Wall.dry[i].y=(rand()%)*+;
while((Wall.dry[i].x==&&Wall.dry[i].y==)||(Wall.dry[i].x==&&Wall.dry[i].y==)
||(Wall.dry[i].x==&&Wall.dry[i].y==))
{
Wall.dry[i].x=(rand()%)*+;//障碍物出现地点
Wall.dry[i].y=(rand()%)*+;
}
setfillcolor(RED);
fillrectangle(Wall.dry[i].x-,Wall.dry[i].y-,Wall.dry[i].x+,Wall.dry[i].y+);
for(int j=;j<i;j++)//确保障碍物不重叠
{
if(Wall.dry[i].x==Wall.dry[j].x&&Wall.dry[i].y==Wall.dry[j].y)
{
i--;
}
}
}
}