文章目录
前言一、游戏说明二、演示效果三、游戏代码四、游戏代码详解4.1初始化4.2绘制界面4.3蛇的死亡4.4按键控制蛇的方向4.5蛇的移动4.6吃食物4.7游戏暂停 五、主函数总结前言
简单了解学习了C语言,用C语言写一个简单的贪吃蛇,基础功能基本完善,还需要其他功能,可以继续添加。
博主抛砖引玉,还望各位大佬多多指点,感谢各位。
一、游戏说明
环境: VC ,EasyX
游戏界面当中没有打印相关的说明,
按键上下左右,WSAD控制蛇的移动
按键空格按下后,可以暂停游戏,再次按下后,恢复游戏
该程序设计的贪吃蛇游戏设定可以穿墙,只有蛇身大于最大长度,或者蛇头吃到自己的身体才死亡。
再蛇死亡后,游戏画面暂停,按下任意键后退出程序。
二、演示效果
snake
三、游戏代码
#include<stdio.h>#include<graphics.h>#include <conio.h>#include <stdlib.h>#define SNAKE_MAXNUM 250 //蛇的最大长度#define width 640#define height 480struct snake//蛇的结构体{int size;//蛇的节数int dir;//方向int speed;//速度POINT coor[SNAKE_MAXNUM]; //坐标}snake;struct Food//食物{int x;int y;int r;bool flag;//标志 1为存在,0为被吃DWORD color;}food;enum DIR{UP,DOWN,LEFT,RIGHT,};void GameInit();void GameDraw();void snakeMove();void keyControl();void EatFood();void Stop();bool SnakeDie();int main(){GameInit();while (SnakeDie()){snakeMove();GameDraw();Stop();keyControl();EatFood();Sleep(100);}return 0;}//数据初始化void GameInit(){initgraph(width, height);// 创建绘图窗口,大小为 640x480 像素//再加一个参数 SHOWCONSOLE 并且显示控制台srand(GetTickCount());//设置随机数种子GetTickCount()获取开机到现在的毫秒数//初始化蛇的信息snake.size = 5;snake.speed = 10;snake.dir = RIGHT;for (int i = 0; i <= snake.size; i++){snake.coor[i].x = 40 - 10 * i;snake.coor[i].y = 10;}//食物初始化food.x = rand() % width;food.y = rand() % height;food.color = RGB(rand() % 256, rand() % 256, rand() % 256);food.r = rand() % 5 + 10;food.flag = true;}void GameDraw(){// 双缓冲绘图BeginBatchDraw();setbkcolor(RGB(100, 150, 100));//背景色cleardevice();for (int i = 0; i < snake.size; i++){solidcircle(snake.coor[i].x, snake.coor[i].y, 5); //蛇}//绘制食物if (food.flag){solidcircle(food.x, food.y, food.r);//画圆形食物}if (!SnakeDie())//蛇死按下任意键退出{// 按任意键退出_getch();closegraph();}EndBatchDraw();}void snakeMove(){for (int i = snake.size - 1; i > 0; i--) {snake.coor[i] = snake.coor[i - 1];}//移动方向该改变坐标switch (snake.dir){case RIGHT://右snake.coor[0].x += snake.speed;break;case LEFT://左snake.coor[0].x -= snake.speed;break;case UP://上snake.coor[0].y -= snake.speed;break;case DOWN://下snake.coor[0].y += snake.speed;break;default:break;}//穿墙判断if (snake.coor[0].y > height){snake.coor[0].y = 0;}else if (snake.coor[0].y < 0){snake.coor[0].y = height;}if (snake.coor[0].x > width){snake.coor[0].x = 0;}else if (snake.coor[0].x < 0){snake.coor[0].x = width;}}void keyControl(){//判断有没有按键按下,有按键按下返回真if (_kbhit()){//72 80 75 77 上下左右键值switch (_getch()){case 72:case 'w':case 'W':if (snake.dir != DOWN) {snake.dir = UP;}break;case 80:case 's':case 'S':if (snake.dir != UP) {snake.dir = DOWN;}break;case 75:case 'a':case 'A':if (snake.dir != RIGHT) {snake.dir = LEFT;}break;case 77:case 'd':case 'D':if (snake.dir != LEFT) {snake.dir = RIGHT;}break;default:break;}}}void EatFood(){if (snake.coor[0].x < food.x + food.r && snake.coor[0].x > food.x - food.r &&snake.coor[0].y < food.y + food.r && snake.coor[0].y > food.y - food.r &&food.flag == 1)//如果不判断flag 蛇会加2节 因为碰撞来个两次食物边缘{food.flag = false;snake.size++;}if (!food.flag)//食物被吃后再次刷新 初始化食物{food.x = rand() % width;food.y = rand() % height;food.color = RGB(rand() % 256, rand() % 256, rand() % 256);food.r = rand() % 10 + 5;food.flag = true;}}void Stop()//空格按下游戏暂停和继续{if (_kbhit()){if (_getch() == ' ')while (_getch() != ' ');}}bool SnakeDie()//当蛇吃到自己的身体后,返回为假{for (int i = 1; i < snake.size-1; i++){if (snake.coor[0].x == snake.coor[i].x && snake.coor[0].y == snake.coor[i].y ||snake.size >= SNAKE_MAXNUM){return false;}}return true;}
四、游戏代码详解
4.1初始化
#define SNAKE_MAXNUM 250 //蛇的最大长度#define width 640#define height 480
struct snake//蛇的结构体{int size;//蛇的节数int dir;//方向int speed;//速度POINT coor[SNAKE_MAXNUM]; //坐标}snake;struct Food//食物{int x;int y;int r;bool flag;//标志 1为存在,0为被吃DWORD color;}food;enum DIR//蛇移动的方向{UP,DOWN,LEFT,RIGHT,};
蛇和食物的结构体
蛇的属性有:蛇的节数也就是长度,蛇在移动时候的方向,这里方向使用枚举,有上下左右四个方向,蛇的速度,初始化为10,蛇的坐标
食物的初始化:x y表示坐标,其中这里左上角为(0,0)点。 食物的半径r 以及食物标志flag ,如果食物被吃掉flag为0,如果食物还存在则flag为1. 食物的颜色。
void GameInit(){initgraph(width, height);// 创建绘图窗口,大小为 640x480 像素//再加一个参数 SHOWCONSOLE 并且显示控制台srand(GetTickCount());//设置随机数种子GetTickCount()获取开机到现在的毫秒数//初始化蛇的信息snake.size = 5;snake.speed = 10;snake.dir = RIGHT;for (int i = 0; i <= snake.size; i++){snake.coor[i].x = 40 - 10 * i;snake.coor[i].y = 10;}//食物初始化food.x = rand() % width;food.y = rand() % height;food.color = RGB(rand() % 256, rand() % 256, rand() % 256);food.r = rand() % 5 + 10;food.flag = true;}
游戏的初始化
创建一个绘图窗口 大小为 width height 前面使用宏定义。可以直接对宏定义进行修改,改变地图大小
设置随机数种子,为了以后的食物的位置在铺垫
初始化蛇的信息
并且使蛇头初始化的位置在(40,10)的位置
初始化食物
4.2绘制界面
void GameDraw(){// 双缓冲绘图BeginBatchDraw();setbkcolor(RGB(100, 150, 100));//背景色cleardevice();for (int i = 0; i < snake.size; i++){solidcircle(snake.coor[i].x, snake.coor[i].y, 5); //蛇}//绘制食物if (food.flag){solidcircle(food.x, food.y, food.r);//画圆形食物}if (!SnakeDie())//蛇死按下任意键退出{// 按任意键退出_getch();closegraph();}EndBatchDraw();}
在绘制界面时采用双缓冲绘图,可以避免界面频闪。
首先对整个窗口的背景色进行调整
通过使用循环绘制出蛇头和蛇身
绘制食物,食物为半径随机的圆形来表示
进行判断蛇时候死亡,如果死后 需要等待按下任意键,来关闭窗口界面
4.3蛇的死亡
bool SnakeDie()//当蛇吃到自己的身体后,返回为假{for (int i = 1; i < snake.size-1; i++){if (snake.coor[0].x == snake.coor[i].x && snake.coor[0].y == snake.coor[i].y ||snake.size >= SNAKE_MAXNUM){return false;}}return true;}
因为游戏设定贪吃蛇可以穿墙所以死亡条件只有吃到自己的身体
在这里采用进行循环判断蛇头坐标是否与蛇身重合,如果重合则表示蛇头吃到自己的身体,
死亡返回 false 否则返回true
4.4按键控制蛇的方向
void keyControl(){//判断有没有按键按下,有按键按下返回真if (_kbhit()){//72 80 75 77 上下左右键值switch (_getch()){case 72:case 'w':case 'W':if (snake.dir != DOWN) {snake.dir = UP;}break;case 80:case 's':case 'S':if (snake.dir != UP) {snake.dir = DOWN;}break;case 75:case 'a':case 'A':if (snake.dir != RIGHT) {snake.dir = LEFT;}break;case 77:case 'd':case 'D':if (snake.dir != LEFT) {snake.dir = RIGHT;}break;default:break;}}}
利用_kbhit()函数进行判断是否有按键按下,如果有,则根据按下的按键进行对蛇的方向进行调整
72 80 75 77 上下左右键值
如果不进行判断是否有按键按下,则游戏中需要每按下一次方向键才会进行移动蛇
进行方向的改变时,需要进行判断如果蛇本身的方向是上,则按下 下 不能让其进行向下,本身方向是左,按下右不能向右,以此类推
4.5蛇的移动
void snakeMove(){for (int i = snake.size - 1; i > 0; i--) {snake.coor[i] = snake.coor[i - 1];}//移动方向该改变坐标switch (snake.dir){case RIGHT://右snake.coor[0].x += 10;break;case LEFT://左snake.coor[0].x -= 10;break;case UP://上snake.coor[0].y -= 10;break;case DOWN://下snake.coor[0].y += 10;break;default:break;}//穿墙判断if (snake.coor[0].y > height){snake.coor[0].y = 0;}else if (snake.coor[0].y < 0){snake.coor[0].y = height;}if (snake.coor[0].x > width){snake.coor[0].x = 0;}else if (snake.coor[0].x < 0){snake.coor[0].x = width;}}
蛇的移动采用蛇的每一节移动到前一节的坐标,根据方向判断蛇头的坐标如如何变化,
蛇头向左移动时,y轴坐标不变,x轴坐标减少
以此类推
因为游戏模式只有一个穿墙模式,所以把穿墙判断写道了move中,如果写多个模式可以单独写一个函数,当蛇头越界时,需要让蛇头改变位置到对应的穿墙后的坐标。
4.6吃食物
void EatFood(){if (snake.coor[0].x < food.x + food.r && snake.coor[0].x > food.x - food.r &&snake.coor[0].y < food.y + food.r && snake.coor[0].y > food.y - food.r &&food.flag == 1)//如果不判断flag 蛇会加2节 因为碰撞来个两次食物边缘{food.flag = false;snake.size++;}if (!food.flag)//食物被吃后再次刷新 初始化食物{food.x = rand() % width;food.y = rand() % height;food.color = RGB(rand() % 256, rand() % 256, rand() % 256);food.r = rand() % 10 + 5;food.flag = true;}}
当蛇头触碰到食物后,则表示蛇吃到了食物,则蛇的长度加一节
因为蛇头中心的坐标触碰一次食物会右两次触碰结果,所以应该对此进行判断第一次触碰到食物后,对食物的flag赋值为假,然后被吃后进行重新对食物进行随机产生。
并且产生后flag重新赋值为真。
4.7游戏暂停
void Stop()//空格按下游戏暂停和继续{if (_kbhit()){if (_getch() == ' ')while (_getch() != ' ');}}
如果右按键按下,判断是否为空格 如果是空格则执行空循环,直到再次按下空格,循环退出,游戏继续。
五、主函数
int main(){GameInit();while (SnakeDie()){snakeMove();GameDraw();Stop();keyControl();EatFood();Sleep(100);}return 0;}
总结
第一次写小工程,估计有许多BUG,但是以后会完善的,本篇主要展示思路。
第一步,永远是最难的,加油!
如果觉得《基础版贪吃蛇(C语言版本)》对你有帮助,请点赞、收藏,并留下你的观点哦!