编程总是对着一个黑窗口,可以说是非常乏味了,于是喵喵就翻出来了以前用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=0; } Food::~Food() { } class node { public: int x,y; node(); virtual ~node(); }; #include "node.h" class snake { public: snake(); virtual ~snake(); node jie[200];//蛇每个节点坐标 int n;//蛇当前节点数 char dry;//蛇当前前进方向 }; class wall { public: node dry[30];//障碍物的坐标 int n;//障碍物的个数 wall(); virtual ~wall(); };
1 #include2 #include 3 #include 4 #include "snake.h" 5 #include "Food.h" 6 #include 7 #include 8 #include "mmsystem.h"//导入声音头文件 9 #pragma comment(lib,"winmm.lib")//导入声音头文件库 10 #include "wall.h" 11 int wallnum,speed; 12 13 void zero(); 14 void first();//操作页面初始化 15 int second( Food &, snake&);//数据初始化 16 void foodstyle(Food&,wall);//食物状态 17 void gameover(snake,int);//游戏结束 18 void judge( Food&,snake&,int,wall);//判断游戏是否结束 19 void judge2(Food &,snake&);//判断蛇是否吃到食物 20 void snakemove(Food&,snake&,wall); 21 void snakeshow(Food &,snake &,wall); 22 void change(Food &,snake &,int);//改变方向 23 void score(snake );//记录分数 24 void wallstyle(wall&);//障碍物的状态 25 26 27 int main() 28 { 29 initgraph(640,560); 30 int o; 31 Food F; 32 snake Snake; 33 wall Wall; 34 first(); 35 zero(); 36 o= second(F,Snake); 37 wallstyle(Wall); 38 PlaySound("kaichang.wav",NULL,SND_FILENAME|SND_ASYNC);//载入声音特效 39 while(1) 40 { 41 while(!kbhit())//没有键盘输入时 42 { 43 44 if(!F.food ) 45 { 46 foodstyle(F,Wall); 47 } 48 judge(F,Snake,o,Wall); 49 judge2(F,Snake); 50 snakemove(F,Snake,Wall); 51 Sleep(speed);//控制速度 52 score(Snake); 53 } 54 change(F,Snake,o); 55 56 } 57 return 0; 58 } 59 60 void zero() 61 { 62 char p[1]; 63 outtextxy(490,30,_T("关卡:")); 64 for(int i=0;i<3;i++) 65 { 66 RECT r= {520+40*i,35,560+40*i,45};//使数字显示在矩形区域中央 67 sprintf(p, "%d", i+1); 68 drawtext(p, &r, DT_CENTER | DT_VCENTER | DT_SINGLELINE); 69 } 70 settextstyle(40, 15, _T("黑体")); 71 outtextxy(50,200,_T("请输入 1 or 2 or 3 确定关卡")); 72 char c=getch();//控制选择关卡 73 switch (c) 74 { 75 case '1': 76 wallnum=10; 77 speed=300; 78 i=1; 79 break; 80 case '2': 81 wallnum=15; 82 speed=200; 83 i=2; 84 break; 85 case '3': 86 wallnum=15; 87 speed=100; 88 i=3; 89 break; 90 default: 91 settextcolor(BLACK);//擦除 92 outtextxy(50,200,_T("请输入 1 or 2 or 3 确定关卡")); 93 settextcolor(RED); 94 outtextxy(200,200,_T("请正确输入")); 95 Sleep(1000);//确保显示时间 96 main(); 97 } 98 setfillcolor(GREEN); 99 RECT v= {530+40*(i-1),20,550+40*(i-1),60}; 100 sprintf(p, "%d", i); 101 drawtext(p, &v, DT_CENTER | DT_VCENTER | DT_SINGLELINE); 102 settextcolor(BLACK); 103 outtextxy(50,200,_T("请输入 1 or 2 or 3 确定关卡")); 104 settextcolor(RED);//确保以后的字体颜色 105 } 106 void first() 107 { 108 srand((unsigned)time(NULL));//播种子 109 setlinestyle(PS_DASH);//实线 110 settextcolor(RED); 111 setlinecolor(BLUE); 112 line(480,0,480,480);//分界线 113 line(0,480,640,480); 114 outtextxy(490,90,_T("分数:"));//操作说明 115 outtextxy(490,150,_T("最高分:")); 116 outtextxy(490,210,_T("操作方式:")); 117 outtextxy(490,260,_T(" W/w:上移 S/s:下移")); 118 outtextxy(490,310,_T(" A/a:左移 D/d:右移")); 119 outtextxy(490,360,_T(" 空格:暂停/开始")); 120 outtextxy(490,410,_T(" Esc:退出")); 121 outtextxy(490,450,_T(" 作者:丁喵喵")); 122 setlinecolor(BLUE);//示例图形 123 setfillcolor(GREEN); 124 fillcircle(310,495,10); 125 fillcircle(30,535,5); 126 setfillcolor(RED); 127 fillrectangle(20,505,40,525); 128 fillrectangle(300,510,320,530); 129 setfillcolor(BLACK); 130 fillcircle(310,520,10); 131 outtextxy(20,490,_T("温馨提示:")); 132 outtextxy(50,510,_T("一.障碍物,撞击死亡")); 133 outtextxy(320,510,_T("四.被破坏障碍物,非无敌状态撞击仍会死亡")); 134 outtextxy(50,530,_T("二.特殊食物,吃掉冲撞障碍物不死亡")); 135 outtextxy(320,490,_T("三.蛇吃完特殊食物后的无敌状态")); 136 outtextxy(320,530,_T("五.只有蛇头时冲撞障碍物不死亡")); 137 } 138 139 int second(Food & F,snake & Snake) 140 { 141 F.food=0;//食物有无、蛇结束、位置、前进方向初始化 142 Snake.n=1; 143 Snake.jie[0].x=40; 144 Snake.jie[0].y=40; 145 setfillcolor(RED); 146 fillcircle( Snake.jie[0].x,Snake.jie[0].y,10); 147 Snake.dry='d'; 148 ifstream inFile("scoremax.txt",ios::in);//读入文件 149 int o; 150 inFile>>o; 151 char p[1]; 152 sprintf(p, "%d", o); 153 settextstyle(10, 10, _T("黑体")); 154 outtextxy(550,150,p);//最高分 155 sprintf(p, "%d", (Snake.n-1)*10); 156 outtextxy(550,90,p);//分数 157 return o; 158 } 159 160 void foodstyle(Food & F,wall Wall) 161 { 162 if(!F.food) 163 { 164 F.foodxy.x=(rand()%22)*20+20;//食物出现地点 165 F.foodxy.y=(rand()%22)*20+20; 166 //确保食物不出现在障碍物及蛇初始位置 167 while((F.foodxy.x==40&&F.foodxy.y==40)||(F.foodxy.x==60&&F.foodxy.y==40)) 168 { 169 F.foodxy.x=(rand()%22)*20+20; 170 F.foodxy.y=(rand()%22)*20+20; 171 } 172 for(int i=0;i ) 173 { 174 if(F.foodxy.x==Wall.dry[i].x&&F.foodxy.y==Wall.dry[i].y) 175 { 176 foodstyle(F,Wall); 177 } 178 } 179 setlinestyle(PS_SOLID); 180 if((F.c+1)%5==0&&(F.c+1)!=0)//判断是否为特殊食物 181 { 182 setfillcolor(GREEN); 183 } 184 else 185 { 186 setfillcolor(YELLOW); 187 } 188 fillcircle(F.foodxy.x,F.foodxy.y,5); 189 F.food=1;//食物状态为有 190 F.c++;//累计出现食物个数 191 } 192 } 193 void judge(Food & F,snake & Snake,int o,wall Wall) 194 { 195 if(Snake.jie[0].x<=0||Snake.jie[0].x>=480||Snake.jie[0].y<=0||Snake.jie[0].y>=480) 196 {//判断是否撞墙 197 PlaySound("zhuangqiang.wav",NULL,SND_FILENAME|SND_ASYNC); 198 Sleep(3000); 199 gameover(Snake,o); 200 } 201 for(int i=1;i<=Snake.n;i++) 202 {//判断是否咬到自己 203 if(Snake.jie[0].x==Snake.jie[i].x&&Snake.jie[0].y==Snake.jie[i].y) 204 { 205 PlaySound("yao.wav",NULL,SND_FILENAME|SND_ASYNC); 206 Sleep(3000); 207 gameover(Snake,o); 208 } 209 } 210 for(i=0;i ) 211 {//判断是否撞到障碍物 212 if(Snake.jie[0].x 20&&Snake.jie[0].y 20&& 213 Snake.jie[0].x>Wall.dry[i].x-20&&Snake.jie[0].y>Wall.dry[i].y-20) 214 { 215 if((F.c-1)%5!=0&&F.c!=1)//非无敌状态 216 { 217 PlaySound("zhuangqiang.wav",NULL,SND_FILENAME|SND_ASYNC); 218 Sleep(3000); 219 gameover(Snake,o); 220 } 221 } 222 } 223 224 } 225 226 void judge2(Food & F,snake & Snake) 227 { 228 if(Snake.jie[0].x==F.foodxy.x&&Snake.jie[0].y==F.foodxy.y)//判断是否吃到食物 229 { 230 PlaySound("shiwu.wav",NULL,SND_FILENAME|SND_ASYNC); 231 setfillcolor(BLACK);//擦除 232 fillcircle(F.foodxy.x,F.foodxy.y,5); 233 Snake.n++;//蛇结数增加 234 setfillcolor(BLUE); 235 fillcircle( F.foodxy.x,F.foodxy.y,10); 236 F.food=0;//食物被吃掉 237 } 238 } 239 void gameover(snake Snake,int o) 240 { 241 if(o<=(Snake.n-1)*10)//判断是否需要更改最高分 242 { 243 PlaySound("zhangsheng.wav",NULL,SND_FILENAME|SND_ASYNC); 244 ofstream outFile("scoremax.txt",ios::out);//写入文件 245 outFile<<(Snake.n-1)*10; 246 outFile.close(); 247 } 248 else 249 { 250 PlaySound("Game_over.wav",NULL,SND_FILENAME|SND_ASYNC); 251 } 252 settextcolor(RED); 253 settextstyle(180, 40, _T("黑体")); 254 outtextxy(100,100,_T("GAME OVER")); 255 settextstyle(40, 15, _T("黑体")); 256 outtextxy(200,300,_T("是否重新开始")); 257 outtextxy(150,350,_T("YES(Y/y)")); 258 outtextxy(350,350,_T("NO(N/n)")); 259 char c=getch();//判断是否重新开始 260 if(c=='n'||c=='N') 261 { 262 closegraph();//关闭画布 263 } 264 else if(c=='y'||c=='Y') 265 { 266 main(); 267 } 268 else//避免输入移动指令破坏画面 269 { 270 gameover(Snake,o); 271 } 272 273 } 274 275 void snakemove(Food & F,snake & Snake,wall Wall) 276 { 277 int i; 278 for (i=Snake.n ; i>0; i--)//蛇身每一节移到前一节位置 279 { 280 Snake.jie[i].x = Snake.jie[i-1].x; 281 Snake.jie[i].y = Snake.jie[i-1].y; 282 } 283 switch (Snake.dry)//判断之前的移动方向 蛇头并按该方向移到 284 { 285 case 'W': 286 case 'w': 287 Snake.jie[0].y-=20; 288 break; 289 case 's': 290 case 'S': 291 Snake.jie[0].y +=20; 292 break; 293 case 'A': 294 case 'a': 295 Snake.jie[0].x -=20; 296 break; 297 case 'D': 298 case 'd': 299 Snake.jie[0].x +=20; 300 break; 301 }; 302 snakeshow(F,Snake,Wall);//将结果显示 303 } 304 305 void change(Food & F,snake & Snake,int o) 306 { 307 char key,p[1]; 308 IMAGE tmp; 309 int i; 310 key = getch(); 311 switch (key) 312 { 313 case 'w': 314 case 'W': 315 if (Snake.dry !='s'&&Snake.dry !='S')//确保不反向移动 316 { 317 Snake.dry ='w'; 318 } 319 break; 320 case 's': 321 case 'S': 322 if (Snake.dry !='w'&&Snake.dry !='W') 323 { 324 Snake.dry = 's'; 325 } 326 break; 327 case 'a': 328 case 'A': 329 if (Snake.dry !='D'&&Snake.dry !='d') 330 { 331 Snake.dry = 'a'; 332 } 333 break; 334 case 'd': 335 case 'D': 336 if (Snake.dry !='a'&&Snake.dry !='A') 337 { 338 Snake.dry = 'd'; 339 } 340 break; 341 case' '://暂停 342 343 getimage(&tmp,150,200,150,40);//将该区域图像保存 344 settextstyle(40, 15, _T("黑体")); 345 outtextxy(150, 200, _T("任意键继续")); 346 PlaySound("stop.wav",NULL,SND_FILENAME|SND_ASYNC); 347 getch(); 348 putimage(150,200,&tmp);//将保存图像返回,确保不破坏背景 349 for(i=3;i>=1;i--)//倒计时 350 { 351 settextstyle(40, 15, _T("黑体")); 352 sprintf(p, "%d", i); 353 outtextxy(200, 200, p); 354 Sleep(1000); 355 putimage(150,200,&tmp); 356 } 357 PlaySound("start.wav",NULL,SND_FILENAME|SND_ASYNC); 358 break; 359 case 27: 360 gameover(Snake,o);//退出 361 break; 362 } 363 } 364 365 void snakeshow(Food & F,snake & Snake,wall Wall) 366 { 367 int i; 368 for (i=Snake.n-1; i>0; i--)//蛇身 369 { 370 setfillcolor(BLUE); 371 fillcircle( Snake.jie[i].x,Snake.jie[i].y,10); 372 } 373 if((F.c-1)%5==0&&F.c!=1)//特殊食物 374 { 375 setfillcolor(GREEN); 376 } 377 else 378 { 379 setfillcolor(RED); 380 } 381 fillcircle( Snake.jie[0].x,Snake.jie[0].y,10); 382 setlinecolor(BLACK); 383 setfillcolor(BLACK);//擦除之前最后一节蛇身 384 fillcircle( Snake.jie[Snake.n].x,Snake.jie[Snake.n].y,10); 385 if(Snake.n>1) 386 { 387 setfillcolor(BLUE); 388 } 389 else 390 { 391 setfillcolor(RED); 392 } 393 fillcircle( Snake.jie[Snake.n-1].x,Snake.jie[Snake.n-1].y,10); 394 } 395 396 397 void score(snake Snake) 398 { 399 char p[1]; 400 sprintf(p, "%d", (Snake.n-2)*10); 401 settextcolor(BLACK); 402 outtextxy(550,90,p); 403 sprintf(p, "%d", (Snake.n-1)*10); 404 settextcolor(RED); 405 settextstyle(10, 10, _T("黑体")); 406 outtextxy(550,90,p); 407 408 } 409 410 void wallstyle(wall & Wall) 411 { 412 Wall.n =wallnum; 413 for(int i=0;i ) 414 { 415 Wall.dry[i].x=(rand()%22)*20+20;//障碍物出现地点 416 Wall.dry[i].y=(rand()%22)*20+20; 417 while((Wall.dry[i].x==40&&Wall.dry[i].y==40)||(Wall.dry[i].x==60&&Wall.dry[i].y==40) 418 ||(Wall.dry[i].x==80&&Wall.dry[i].y==40)) 419 { 420 Wall.dry[i].x=(rand()%22)*20+20;//障碍物出现地点 421 Wall.dry[i].y=(rand()%22)*20+20; 422 } 423 setfillcolor(RED); 424 fillrectangle(Wall.dry[i].x-10,Wall.dry[i].y-10,Wall.dry[i].x+10,Wall.dry[i].y+10); 425 for(int j=0;j//确保障碍物不重叠 426 { 427 if(Wall.dry[i].x==Wall.dry[j].x&&Wall.dry[i].y==Wall.dry[j].y) 428 { 429 i--; 430 } 431 } 432 } 433 }