前面的话:
首次写这个,如有不足,欢迎指正。
代码中的注释解释的很详细!所以说阅读起来应该问题不大,有帮助就最好啦!( ̄︶ ̄)↗
/11/2更新:
贪吃蛇C++_: 大一作业,使用EasyX图形库制作的贪吃蛇游戏 ()
我在Gitee上传了自己的代码,大家喜欢可以支持一下啊!
EasyX库官网/
需要先下好哦!
图像音频资源在这里找的爱给网(现在也不好了,下载资源需要什么币,虽然可以免费获得但是很麻烦,有好的资源网站麻烦推荐一波)☺
作为c语言的练手项目算是非常经典的了,在完成的过程中也回忆了一波童年,所有代码可以运行。图片,音乐使用自己的就可以了。
有人要过游戏图片音频资源,我就在这里放出来了。
图片音频资源/download/m0_63288666/86506592?spm=1001..3001.5503PS:很抱歉没有看消息的习惯(主要是关注的人略微多些,每次都99+,随后就不再去管了)
那个朋友被晾了3,4个月,说声抱歉哈。
运行实例
头文件 MYHEAD.h
包裹了依赖的库和全局定义的变量,全局的函数。
1.首先完成基本功能的搭建。
2.实现变色功能。
3.计分版功能。
4.插入音乐。
大概按这个顺序做的,但是实话实说也不是很严格。
#pragma once#include<stdio.h>#include<graphics.h>#include<conio.h>#include<time.h>#include<mmsystem.h>#pragma comment(lib,"winmm.lib")//引用Windows Multimedia #pragma warning(disable:4996)/*开发日志:1.首先完成基本功能的搭建。2.实现变色功能。3.计分版功能。4.插入音乐。*/#define WIDTH 1200//UNIT*600#define HIGH 660//UNIT*33#define UNIT 20//这是每个蛇身矩形的单位长度IMAGE img_bk;//设置背景图片IMAGE img_frame, img_pause, img_manual, img_bkimg_rank;//边框图片,暂停图片,说明图片,排行榜背景enum game//枚举设置空地,蛇身,蛇头,墙,食物所处的状态{SPACE, BODY, HEAD, WALL, FOOD//0,1,2,3,4};struct SNAKE//蛇身的结构体{int x;int y;};struct SNAKE snake[1024];//[0][0]储存蛇头的位置int snakelong;//蛇身的长度struct _FOOD//食物{int color;int x;int y;}food;struct record//这是记录排行榜的数组{int score = 0;//分数int hour;int min;int sec;int year;int mon;int day;}rec[10];/*————————————————定义全局变量————————*/int h_num;//纵横的边框个数,只在绘制边框时有用int w_num;int canvas[HIGH][WIDTH - 120];//设置画布,用来存储当前的状态int state;//状态,用来标识选项:选择的是 1 OR 2 OR 3 OR 4的选项状态int snakeDir;//方向,用来标识蛇的移动方向int snakecolor;//蛇的颜色int score;//得分int sleeptime;//调节速度用int mode;//模式选择//普通,无敌/*———————————————————————————————————*//*———————————————定义函数—————————————*/void startup();//初始化函数void chose();//选择函数int setColor(int a);//设置填充颜色void menu();//菜单函数void pauseMenu();//暂停游戏菜单void show();//展示函数void updateWithoutuser();//与用户输入无关的更新void updateWithuser();//与用户输入有关的更新void gameover();//游戏结束void regame();//重开游戏void addFood();//随机设置食物void speed_mode_menu();//速度,模式选择菜单。四种速度,三种模式int writerank();int showrank();void autofind();//自动寻路/*——————————————————————————————————————*/
源文件 TCS.cpp
#include"MYHEAD.h" 使用双引号是在当前目录下先找,之后再到其它目录下找,我想这对于速度也许有一点的提升吧。实际的话尖括号也行。
#include"MYHEAD.h"int main(){startup();//初始化函数LABLE: menu();//菜单函数chose();//选择函数if (state == 1)//开始游戏{speed_mode_menu();//速度,模式选择菜单。四种速度,2种模式while (1)//游戏循环主题{show();//展示函数updateWithoutuser();//与用户输入无关的更新updateWithuser();//与用户输入有关的更新}}else if (state == 2)//游戏说明{cleardevice();putimage(0, 0, &img_manual);//输出说明图片settextstyle(80, 0, L"楷体");outtextxy(5 * UNIT, 2 * UNIT, L"游戏说明");settextstyle(30, 0, L"隶书");outtextxy(5 * UNIT, 7 * UNIT, L"1.游戏有4种速度,2种模式。");outtextxy(5 * UNIT, 9 * UNIT, L"2.速度决定难度和分数,模式分有“普通”和“无敌”,无敌模式下");outtextxy(5 * UNIT, 11 * UNIT, L"不会死亡,且可以穿墙。");outtextxy(5 * UNIT, 13 * UNIT, L"3.由“W”“S”“A”“D”分别控制上、下、左、右的方向。");outtextxy(5 * UNIT, 15 * UNIT, L"4.空格键暂停游戏。");outtextxy(5 * UNIT, 17 * UNIT, L"5.Esc键游戏退出,返回主页面。");outtextxy(5 * UNIT, 19* UNIT, L"6.当蛇首撞墙或咬到蛇身时游戏结束,自动存档并返回主页面。");outtextxy(5 * UNIT, 21 * UNIT, L"7.小蛇每吃到一个食物,分数就会增加。初始分数为零。");outtextxy(5 * UNIT, 23 * UNIT, L"8.游戏目标是尽可能多的得分,打破记录!");outtextxy(5 * UNIT, 25 * UNIT, L"按任意键返回……");system("pause");goto LABLE;}else if (state == 3)//排行榜{showrank();//排行榜显示system("pause");goto LABLE;}else if(state == 4)//游戏结束{gameover();exit(1);}return 0;}void startup()//初始化函数{srand(GetTickCount());//随机数种子mciSendString(L"open .\\background_music.mp3 alias bkmusic",NULL,0,NULL);mciSendString(L"play bkmusic repeat", NULL, 0, NULL);initgraph(WIDTH, HIGH);//创建画布HWND hwnd = GetHWnd();//获取窗口句柄SetWindowText(hwnd, L"我的贪吃蛇 v1.0");//设置窗口标题文字loadimage(&img_bk, L".\\img_bk (2).png", WIDTH, HIGH);//加载背景图片loadimage(&img_frame, L".\\walls.gif");//加载边框图片loadimage(&img_pause, L".\\img_pause.JPG",WIDTH,HIGH);//加载暂停图片loadimage(&img_manual, L".\\manual.png", WIDTH, HIGH);//加载说明图片loadimage(&img_bkimg_rank, L".\\bkimg.JPG", WIDTH, HIGH);h_num = HIGH / 60;//高WALL图片有几个w_num = (WIDTH-120) / 60;//宽WALL图片有几个//====================================分割线=====================================//memset(canvas, SPACE, sizeof(canvas));//全部初始化为空地for (int i = 0; i < 60; i++)//初始化墙壁所在的位置,四周 60 像素的边框{for (int j = 0; j < WIDTH-120; j++){canvas[i][j] = canvas[HIGH - i - 1][j] = WALL;}}for (int i = 0; i < HIGH; i++)//初始化墙壁所在的位置,四周 60 像素的边框{for (int j = 0; j < 60; j++){canvas[i][j] = canvas[i][WIDTH-120 - j - 1] = WALL;}}canvas[60 + UNIT*5][60 + UNIT*5] = HEAD;//初始化头canvas[60 + UNIT * 5][60 + UNIT * 4] = canvas[60 + UNIT * 5][60 + UNIT * 3] = BODY;//初始化身体addFood();//随机设置食物state = 1;//菜单选择状态snakelong = 3;//蛇长3snake[0].x = 60 + UNIT * 5; snake[0].y = 60 + UNIT * 5;snake[1].x = 60 + UNIT * 4; snake[1].y = 60 + UNIT * 5;snake[2].x = 60 + UNIT * 3; snake[2].y = 60 + UNIT * 5;snakeDir = 0x44;//D方向,虚拟键码,是默认的移动方向snakecolor = 1;//蛇初始颜色 1 —— 蓝色score = 0;sleeptime = 100;mode = 0;}void chose()//选择函数{while (1){switch (_getch()){case '1':menu();outtextxy(WIDTH / 2 - 150, HIGH / 2 - 60, L"->");state = 1;break;case '2':menu();outtextxy(WIDTH / 2 - 150, HIGH / 2 - 15, L"->");state = 2;break;case '3':menu();outtextxy(WIDTH / 2 - 150, HIGH / 2 + 30, L"->");state = 3;break;case '4':menu();outtextxy(WIDTH / 2 - 150, HIGH / 2 + 75, L"->");state = 4;break;case VK_RETURN:return;}}}void menu()//菜单函数{putimage(0, 0, &img_bk);//显示背景setbkmode(TRANSPARENT);//设置背景格式为透明settextcolor(BLACK);//字体颜色是黑色//输出settextstyle(80, 0, _T("隶书"));outtextxy(WIDTH / 2 - 300, HIGH / 6, _T("贪吃蛇小游戏"));settextstyle(30, 0, _T("隶书"),0,0,0,0,0,0);outtextxy(WIDTH / 2 -120, HIGH / 2 - 60, _T("1:开始游戏"));outtextxy(WIDTH / 2 - 120, HIGH / 2 -15, _T("2:游戏说明"));outtextxy(WIDTH / 2 - 120, HIGH / 2 + 30, _T("3:排行榜"));outtextxy(WIDTH / 2 - 120, HIGH / 2 + 75, _T("4:退出游戏"));outtextxy(WIDTH / 2 - 300, HIGH / 2 + 125, L"数字键 1,2,3,4 选择,Enter键进入 “->”标识当前选中的位置");}void pauseMenu()//暂停游戏菜单{system("pause");}void show()//展示函数{BeginBatchDraw();setbkcolor(RGB(130,130,130));//设置当前背景色为 黑cleardevice();//用该背景色清空屏幕settextstyle(35, 0, L"华文彩云",0,0,FW_LIGHT,0,0,0);setcolor(YELLOW);TCHAR sco[5],snlong[6];_stprintf_s(sco, _T("%d"), score);// _stprintf_s 函数_stprintf_s(snlong, _T("%d"), snakelong);outtextxy(WIDTH - 100, 2 * UNIT, L"得分:");outtextxy(WIDTH - 100, 4 * UNIT, sco);outtextxy(WIDTH - 100, 6 * UNIT, L"蛇长:");outtextxy(WIDTH - 100, 8 * UNIT, snlong);int i = 0,j = 0;for (i = 0,j = 0; i < h_num || j < w_num; i++,j++)//输出边框{putimage(0, i * 60, &img_frame);putimage(WIDTH -120- 60, i * 60, &img_frame);putimage(j * 60, 0, &img_frame);putimage(j * 60, HIGH - 60, &img_frame);}setColor(rand()%7);//炫彩蛇头fillrectangle(snake[0].x, snake[0].y, snake[0].x + UNIT, snake[0].y + UNIT);for (i = 1; i < snakelong; i++)//输出蛇的矩形{setColor(snakecolor);fillrectangle(snake[i].x, snake[i].y, snake[i].x + UNIT, snake[i].y + UNIT);}setColor(food.color);fillrectangle(food.x, food.y, food.x + UNIT, food.y + UNIT);FlushBatchDraw();}void updateWithoutuser()//与用户输入无关的更新{SNAKE temp{};//用来暂存蛇头的下一个位置//autofind();switch (snakeDir){case 0x57://wtemp.x = snake[0].x;temp.y = snake[0].y -UNIT;break;case 0x41://atemp.x = snake[0].x - UNIT;temp.y = snake[0].y;break;case 0x53://stemp.x = snake[0].x;temp.y = snake[0].y + UNIT;break;case 0x44://dtemp.x = snake[0].x + UNIT;temp.y = snake[0].y;break;}switch (canvas[temp.y][temp.x]){case SPACE://是空地,可以继续前进canvas[snake[snakelong - 1].y][snake[snakelong - 1].x] = SPACE;//蛇尾消除for (int i = snakelong - 1; i > 0; i--)//蛇整体做个移动{snake[i] = snake[i-1];}canvas[snake[0].y][snake[0].x] = BODY;//地图上老蛇头的位置赋成蛇身snake[0] = temp;//重新赋值蛇头的坐标canvas[snake[0].y][snake[0].x] = HEAD;//地图标识蛇头位置break;case FOOD://食物,增长身体,重新生成mciSendString(L"close eatmusic", NULL, 0, NULL);mciSendString(L"open .\\eat.mp3 alias eatmusic", NULL, 0, NULL);mciSendString(L"play eatmusic", NULL, 0, NULL);fillrectangle(food.x, food.y, food.x + UNIT, food.y + UNIT);for (int i = snakelong; i > 0; i--)//蛇整体做个移动{snake[i] = snake[i - 1];}canvas[snake[0].y][snake[0].x] = BODY;//地图上老蛇头的位置赋成蛇身snake[0] = temp;//重新赋值蛇头的坐标canvas[snake[0].y][snake[0].x] = HEAD;//地图标识蛇头位置snakelong++;//长度 + 1snakecolor = setColor(food.color);//颜色更该为原来食物的颜色addFood();//重新随机一个食物的颜色if (sleeptime == 200)score++;//得分加1else if (sleeptime == 100)score += 2;else if (sleeptime == 60)score += 3;else if (sleeptime == 40)score += 5;break;case BODY://身体,普通模式下死亡if (mode)//是模式2:无敌break;writerank();Sleep(800);regame();break;case WALL://墙,普通模式下死亡if (mode)//是模式2:无敌穿墙{canvas[snake[snakelong - 1].y][snake[snakelong - 1].x] = SPACE;//蛇尾消除for (int i = snakelong - 1; i > 0; i--)//蛇整体做个移动{snake[i] = snake[i - 1];}canvas[snake[0].y][snake[0].x] = BODY;//地图上老蛇头的位置赋成蛇身switch (snakeDir){case 0x57://wtemp.y = HIGH -20 - snake[0].y;break;case 0x41://atemp.x = WIDTH - 140 - snake[0].x;break;case 0x53://stemp.y = HIGH - 20 - snake[0].y;break;case 0x44://dtemp.x = WIDTH - 140 - snake[0].x;break;}snake[0] = temp;//重新赋值蛇头的坐标canvas[snake[0].y][snake[0].x] = HEAD;//地图标识蛇头位置break;}writerank();Sleep(800);regame();break;}Sleep(sleeptime);}void updateWithuser()//与用户输入有关的更新{if (GetAsyncKeyState(0x41) && snakeDir != 0x44)//asnakeDir = 0x41;if (GetAsyncKeyState(0x44) && snakeDir != 0x41)//dsnakeDir = 0x44;if (GetAsyncKeyState(0x57) && snakeDir != 0x53)//wsnakeDir = 0x57;if (GetAsyncKeyState(0x53) && snakeDir != 0x57)//ssnakeDir = 0x53;if (GetAsyncKeyState(VK_SPACE))//空格建暂停pauseMenu();if (GetAsyncKeyState(VK_ESCAPE))//esc键退出游戏返回主菜单regame();}void gameover()//游戏结束{EndBatchDraw();closegraph();}void addFood()//随机设置食物{int x = 0, y = 0;do{x = (rand() % (int)((WIDTH-120 - 120) / UNIT)) * UNIT + 60;y = (rand() % (int)((HIGH - 120) / UNIT)) * UNIT + 60;} while (canvas[y][x] != SPACE);//随机的位置只能是空地canvas[y][x] = FOOD;//位置是食物food.x = x;food.y = y;food.color = rand() % 3;}int setColor(int a)//设置颜色{switch (a){case 0:setfillcolor(RGB(255, 0, 0));//红色break;case 1:setfillcolor(RGB(0, 0, 255));//蓝色break;case 2:setfillcolor(RGB(0, 255, 0));//绿色break;case 3:setfillcolor(RGB(255, 165, 0));//橙色break;case 4:setfillcolor(RGB(255, 255, 0));//黄色break;case 5:setfillcolor(RGB(0, 255, 255));//青色break;case 6:setfillcolor(RGB(160, 32, 240));//紫色break;}return a;}void speed_mode_menu()//速度,模式选择菜单。四种速度,三种模式{T1:cleardevice();wchar_t wspeed[5];InputBox(wspeed, 5, L"+请输入速度值+(输入数字1,2,3,4)\n\n1-超简单速度(一个食物得一分)\n2-普通速度(一个食物得两分)\n3-困难速度(一个食物三分)\n4-地狱速度(一个食物五分)\n\n★默认为普通速度★",L"这是一个选择速度等级的框框q(≧▽≦q)",L"输入吧( ̄︶ ̄)↗");int speed = _wtoi(wspeed);if (speed == 1)//超简单速度sleeptime = 200;else if (speed == 2)//普通模式sleeptime = 100;else if (speed == 3)//困难模式sleeptime = 60;else if (speed == 4)//地狱模式sleeptime = 40;elsegoto T1;T2:wchar_t tmode[2];InputBox(tmode, 2, L"+请输入1,2选择模式+\n\n1-普通模式\n2-无敌模式\n\n\n★默认为普通模式★", L"这是一个选择游戏模式的框框q(≧▽≦q)", L"输入吧( ̄︶ ̄)↗");int _mode = _wtoi(tmode);mode = _mode -1;//设置模式if (mode != 0 && mode != 1)goto T2;}int writerank()//输入存储排名{while (_kbhit())//清空键盘缓冲区{_getch();}time_t timep;struct tm* ti;time(&timep);ti = localtime(&timep);record* temp = (record*)malloc(sizeof(record)*100);//申请一个空间int i = 0, n = 0;FILE* fp = NULL;errno_t err = fopen_s(&fp, ".\\rank.txt", "ab");//保存成绩用追加读写 if (err){printf("cannot open the file\n");system("pause");return -1;//如果文件出现错误返回-1 }temp->score = score;//分数temp->year = ti->tm_year+1900;//年temp->mon = ti->tm_mon+1; //月temp->day = ti->tm_mday; //日temp->hour = ti->tm_hour;//时temp->min = ti->tm_min; //分temp->sec = ti->tm_sec; //秒fwrite(temp, sizeof(record), 1, fp);fclose(fp);free(temp);return 0;}int showrank()//展示排名{record _temp;int j = 0, i = 0, k = 0;FILE* fp = NULL;errno_t err = fopen_s(&fp, ".\\rank.txt", "rb");if (err){printf("cannot open the file\n");system("pause");return -1;}if (fp == NULL)//这个貌似没有什么用处{printf_s("暂无数据!");//return 0;}rewind(fp);while (!feof(fp)){fread(&rec[i], sizeof(record), 1, fp);i++;}for (int j = 0; j < i; j++)//排序用{for (int k = 0; k < i; k++){if (rec[k].score < rec[j].score){_temp = rec[k];rec[k] = rec[j];rec[j] = _temp;}}}if (i >= 10)i = 10;cleardevice();putimage(0, 0, &img_bkimg_rank);settextcolor(BLACK);settextstyle(4 * UNIT, 0, L"华文新魏");outtextxy(WIDTH / 2 - 7*UNIT, 0, _T("排行榜"));settextstyle(3 * UNIT, 0, L"华文楷体");outtextxy(7 * UNIT, 4 * UNIT, L"得 分");outtextxy(20 * UNIT, 4*UNIT, L"年 月 日 时 分 秒");settextstyle( UNIT, 0, L"方正姚体");for (int j = 0; j < i ; j++){TCHAR s1[6];_stprintf_s(s1,_T("%d"), rec[j].score);//分数outtextxy(10 * UNIT, j * (UNIT * 2) + 9 * UNIT, s1);TCHAR s2[6];_stprintf_s(s2, _T("%d"), rec[j].year);//年outtextxy(20 * UNIT, j * (UNIT * 2) + 9 * UNIT, s2);TCHAR s3[6];_stprintf_s(s3, _T("%d"), rec[j].mon);//月outtextxy(25 * UNIT, j * (UNIT * 2) + 9 * UNIT, s3);TCHAR s4[6];_stprintf_s(s4, _T("%d"), rec[j].day);//日outtextxy(30 * UNIT, j * (UNIT * 2) + 9 * UNIT, s4);TCHAR s5[6];_stprintf_s(s5, _T("%d"), rec[j].hour);//时outtextxy(40 * UNIT, j * (UNIT * 2) + 9 * UNIT, s5);TCHAR s6[6];_stprintf_s(s6, _T("%d"), rec[j].min);//分outtextxy(45 * UNIT, j * (UNIT * 2) + 9 * UNIT, s6);TCHAR s7[6];_stprintf_s(s7, _T("%d"), rec[j].sec);//秒outtextxy(50 * UNIT, j * (UNIT * 2) + 9 * UNIT, s7);}outtextxy(5 * UNIT, 30 * UNIT, L"按任意键返回……");fclose(fp);return 0;}void regame(){clearrectangle(0,0,WIDTH,HIGH);gameover();main();}void autofind(){snakeDir;int chax = snake[0].x - food.x;//蛇头与食物的坐标差int chay = snake[0].y - food.y;if (chax > 0 && snakeDir != 0x44){snakeDir = 0x41;}if (chax < 0 && snakeDir != 0x41){snakeDir = 0x44;}if (chay > 0 && snakeDir != 0x53){snakeDir = 0x57;}if (chay < 0 && snakeDir != 0x57){snakeDir = 0x53;}if (chay == 0 && chax > 0 && snakeDir == 0x44){snakeDir = 0x53;}if (chay == 0 && chax < 0 && snakeDir == 0x41){snakeDir = 0x53;}if (chax == 0 && chay > 0 && snakeDir == 0x53){snakeDir = 0x41;}if (chay == 0 && chax < 0 && snakeDir == 0x57){snakeDir = 0x41;}}
先简单这样子吧,以后再慢慢发详细的东西。
如果觉得《【EasyX图形库】c语言贪吃蛇-音乐-图片-界面比较美观》对你有帮助,请点赞、收藏,并留下你的观点哦!