(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹)
今天我们来尝试一下通过easyx窗口创建贪吃蛇小游戏
首先就是引入几个必要的头文件,相信大家都已经不陌生了,因为在之前的小游戏中都有涉及
#include<stdio.h> #include<stdlib.h> #include<graphics.h> //便于引入easyx窗口及其函数 #include<conio.h> //按键控制 #include<time.h> //构建随机函数
接下来就是对各个变量进行编写,我们这里的窗口高度定义为640,宽度为480
首先就是最为关键的坐标属性
struct point //坐标属性 { int x; int y; };
然后就是蛇和食物的属性
struct Snake //蛇的属性 { int num; //蛇的节数 point xy[100]; //蛇最长的节数 char postion; //方向 }snake; struct Food //食物属性 { point foodxy; //食物坐标 int flag; //食物是否存在 }food;
因为后期在移动小蛇时,我们要对方向进行编写,所以我们在这里不妨先枚举一下各个方向,便于后期编写
enum moveposition{right=77,left=75,down=80,up=72};
此处也可以不枚举,只需要将后面代码中的的方向改为相应的数字即可
接下来我们就要用不同的函数来构建不同的变量,我将不同的变量总结了一下,便于大家观察
void intsnake();//初始化蛇 void drawsnake();//画蛇 void movesnake();//移动蛇 void keysnake();//按键控制 void intfood();//初始化食物 void drawfood();//画食物 void eatfood();//吃食物 int snakedie();//蛇死亡
首先就是初始化蛇了,这里我们将初始化的蛇确定为三节,并且每一节的间距为10,并初始化蛇运动的方向为右
void intsnake() { snake.xy[2].x = 0; snake.xy[2].y = 0; snake.xy[1].x = 10; snake.xy[1].y = 0; snake.xy[0].x = 20; snake.xy[0].y = 0; snake.num = 3; snake.postion = right; }
然后就是对蛇进行绘画,我们这里用矩形来表示蛇的身体,对于蛇就颜色,大家可以选择自己喜欢的,我这里用随机函数进行绘制,效果奇特 ,哈哈哈哈哈嗝~
void drawsnake() { for (int i = 0; i < snake.num; i++) { setlinecolor(BLACK);//边框颜色 setfillcolor(RGB(rand()%255, rand() % 255, rand() % 255));//填充颜色(随机色) //画矩形 fillrectangle(snake.xy[i].x, snake.xy[i].y, snake.xy[i].x + 10, snake.xy[i].y + 10); } }
然后就是要考虑蛇移动的问题 ,我们可以这样想,所谓的蛇移动,就是在蛇头移动后,蛇身体的每一个坐标都等于它前面的坐标,这里我们将蛇头记为snake.xy[0],那么第二节的坐标就是蛇头移动前的坐标,第三节的坐标就变成了蛇移动前第二节的坐标。因此这里我们将蛇头与蛇身体分开表示
void movesnake() { //除了第一节(蛇头),后面每一节都是前一节的坐标 for (int i = snake.num - 1; i > 0; i--) { snake.xy[i].x = snake.xy[i - 1].x; snake.xy[i].y = snake.xy[i - 1].y; } //第一节的处理 switch (snake.postion) { case right: snake.xy[0].x += 10; break; case left: snake.xy[0].x -= 10; break; case down: snake.xy[0].y += 10; break; case up: snake.xy[0].y -= 10; break; default: break; } }
在确定完蛇的移动顺序后,就是对蛇进行按键处理了,确保蛇可以被键盘控制,如果对键盘操作有不明白的同学可以查阅(http://t.csdn.cn/KkFwU)
void keysnake() { char userkey = 0; userkey = _getch();//控制台可以直接读取我按的键 switch (userkey) { case 'd': case right: snake.postion = right; break; case left: case 'a': snake.postion = left; break; case down: case 's': snake.postion = down; break; case up: case 'w': snake.postion = up; break; default: break; } }
蛇我们已经完成,接下来就是对 食物进行编写,这里我们用随机函数rand对食物出现的位置进行定义,确保食物每次出现的位置不同,之所以将640分成64*10,是确保食物尽可能出现在窗口中间,不然数字太小,蛇可能吃不到。这里我们多加一个如果食物出现在蛇身上,是为了防止在一开始的时候食物便出现在蛇身上导致我们没有看见食物。(虽然这样的几率很小很小很小,但我还是想皮一下 ,嘿嘿嘿)
void intfood() { //拆开写,防止蛇吃不到食物 food.foodxy.x = rand() % 64 * 10; food.foodxy.y = rand() % 48 * 10; food.flag = 1;//防止反复出现食物 //如果食物出现在蛇身上 for(int i = 0; i > snake.num; i++) { if(food.foodxy.x==snake.xy[i].x && food.foodxy.y == snake.xy[i].y) { food.foodxy.x = rand() % 64 * 10; food.foodxy.y = rand() % 48 * 10; } } }
接下来就是画食物了,和蛇一样,我们也用矩形绘制食物
void drawfood() { setlinecolor(BLACK); setfillcolor(GREEN); fillrectangle(food.foodxy.x, food.foodxy.y, food.foodxy.x + 10, food.foodxy.y + 10); }
食物画完了,接下来就该让小蛇吃食物啦
void eatfood() { if (snake.xy[0].x == food.foodxy.x&&snake.xy[0].y==food.foodxy.y) { snake.num++;//蛇长度每次加一 food.flag = 0;//重新显示食物 } }
接下来就是蛇的死亡啦,小蛇死亡分为两种,撞墙或者撞自己,因为这里用到了MessageBox,所以我们在开头应该声明一个主窗口
HWND hwnd = NULL;//表示主窗口 int snakedie() { if (snake.xy[0].x > 640 || snake.xy[0].y > 480 || snake.xy[0].x < 0 || snake.xy[0].y < 0) { MessageBox(hwnd, "游戏结束","撞墙",MB_OK);//弹出一个窗口 return 1; } for (int i = 1; i < snake.num; i++)//撞自己 { if (snake.xy[0].x == snake.xy[i].x && snake.xy[0].y == snake.xy[i].y) { MessageBox(hwnd, "游戏结束", "撞自己", MB_OK);//弹出一个窗口 return 1; } } return 0; }
接下来就是振奋人心的主函数组合啦,我们这里定义flag为0时表示无食物,此时就对食物进行定义并且绘制,在食物出现后,因为 intfood()中flag为1,所以之后食物就不会再次出现,直到在eatfood()中小蛇吃掉食物,并将flag改为0,则食物才会在while()循环的驱动下再次定义并绘制
这里我们还用到了双缓冲绘图,是为了防止小蛇在移动时一闪一闪,这个在我之前的easyx基础中有涉及
int main() { srand((unsigned int)time(NULL));//生成随机数种子 hwnd = initgraph(640, 480);//窗口大小,init意思是初始化 setbkcolor(WHITE);//窗口颜色 intsnake(); while (1)//循环执行命令 { cleardevice();//刷新一下,防止窗口颜色不变 //双缓冲绘图,放在绘图代码之前和之后,防止贪吃蛇界面一闪一闪 BeginBatchDraw();//开始绘图 drawsnake(); movesnake(); drawfood(); EndBatchDraw();// 结束绘图 if (food.flag == 0) { intfood(); } eatfood(); if (snakedie()) { break; } while (_kbhit())//判断是否有按键,防止出现屏幕不动的情况 { keysnake(); } Sleep(50);//放慢速度 } getchar();//防止闪屏 closegraph();//关闭窗口 return 0; }
总体代码就是这样,如果大家发现bug或者有更好的方法 ,欢迎大家一起来讨论呀
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<time.h> #include<stdlib.h> #include<graphics.h> #include<conio.h> struct point //坐标属性 { int x; int y; }; struct Snake //蛇的属性 { int num; //蛇的节数 point xy[100]; //蛇最长的节数 char postion; //方向 }snake; struct Food //食物属性 { point foodxy; //食物坐标 int flag; //食物是否存在 }food; HWND hwnd = NULL;//表示主窗口 enum moveposition{right=77,left=75,down=80,up=72}; //void intsnake();//初始化蛇 //void drawsnake();//画蛇 //void movesnake();//移动蛇 //void keysnake();//按键控制 //void intfood();//初始化食物 //void drawfood();//画食物 //void eatfood();//吃食物 //int snakedie();//蛇死亡 void intsnake() { snake.xy[2].x = 0; snake.xy[2].y = 0; snake.xy[1].x = 10; snake.xy[1].y = 0; snake.xy[0].x = 20; snake.xy[0].y = 0; snake.num = 3; snake.postion = right; } void drawsnake() { for (int i = 0; i < snake.num; i++) { setlinecolor(BLACK);//边框颜色 setfillcolor(RGB(rand()%255, rand() % 255, rand() % 255));//填充颜色(随机色) //画矩形 fillrectangle(snake.xy[i].x, snake.xy[i].y, snake.xy[i].x + 10, snake.xy[i].y + 10); } } void movesnake() { //除了第一节(蛇头),后面每一节都是前一节的坐标 for (int i = snake.num - 1; i > 0; i--) { snake.xy[i].x = snake.xy[i - 1].x; snake.xy[i].y = snake.xy[i - 1].y; } //第一节的处理 switch (snake.postion) { case right: snake.xy[0].x += 10; break; case left: snake.xy[0].x -= 10; break; case down: snake.xy[0].y += 10; break; case up: snake.xy[0].y -= 10; break; default: break; } } void keysnake() { char userkey = 0; userkey = _getch();//控制台可以直接读取我按的键 switch (userkey) { case 'd': case right: snake.postion = right; break; case left: case 'a': snake.postion = left; break; case down: case 's': snake.postion = down; break; case up: case 'w': snake.postion = up; break; default: break; } } void intfood() { //拆开写,防止蛇吃不到食物 food.foodxy.x = rand() % 64 * 10; food.foodxy.y = rand() % 48 * 10; food.flag = 1; //如果食物出现在蛇身上 for(int i = 0; i > snake.num; i++) { if(food.foodxy.x==snake.xy[i].x && food.foodxy.y == snake.xy[i].y) { food.foodxy.x = rand() % 64 * 10; food.foodxy.y = rand() % 48 * 10; } } } void drawfood() { setlinecolor(BLACK); setfillcolor(GREEN); fillrectangle(food.foodxy.x, food.foodxy.y, food.foodxy.x + 10, food.foodxy.y + 10); } void eatfood() { if (snake.xy[0].x == food.foodxy.x&&snake.xy[0].y==food.foodxy.y) { snake.num++;//蛇长度每次加一 food.flag = 0;//重新显示食物 } } int snakedie() { if (snake.xy[0].x > 640 || snake.xy[0].y > 480 || snake.xy[0].x < 0 || snake.xy[0].y < 0) { MessageBox(hwnd, "游戏结束","撞墙",MB_OK);//弹出一个窗口 return 1; } for (int i = 1; i < snake.num; i++)//撞自己 { if (snake.xy[0].x == snake.xy[i].x && snake.xy[0].y == snake.xy[i].y) { MessageBox(hwnd, "游戏结束", "撞自己", MB_OK);//弹出一个窗口 return 1; } } return 0; } int main() { srand((unsigned int)time(NULL));//生成随机数种子 hwnd = initgraph(640, 480);//窗口大小,init意思是初始化 setbkcolor(WHITE);//窗口颜色 intsnake(); while (1) { cleardevice();//刷新一下,防止窗口颜色不变 //双缓冲绘图,放在绘图代码之前和之后,防止贪吃蛇界面一闪一闪 BeginBatchDraw();//开始绘图 drawsnake(); movesnake(); drawfood(); EndBatchDraw();// 结束绘图 if (food.flag == 0) { intfood(); } eatfood(); if (snakedie()) { break; } while (_kbhit()) { keysnake(); } Sleep(50);//放慢速度 } getchar();//防止闪屏 closegraph();//关闭窗口 return 0; }
大家一起加油