admin管理员组文章数量:1794759
C语言实现贪吃蛇(简易)
文章目录
目录
文章目录
前言
一、游戏功能和效果
1.游戏功能
2.游戏效果
二. 游戏初步实现
1.确定地图大小
2.创建蛇对象,食物对象
3.初始化蛇
4.生成随机食物
5.画蛇
6.画食物
7. 游戏内移动控制
1.当按上下左右时移动方向改变 。
2.开始游戏时的默认方向
8.判断蛇撞墙,撞身体,撞食物3种情况
1.蛇撞墙:判断蛇头坐标是否和行和列相等,如果相等游戏结束!
2.蛇撞身体:判断蛇头坐标是否和蛇身坐标相等,如果相等游戏结束!
3.蛇撞食物:撞到食物后当前长度增加,再重新生成食物,移动速度变快,分数增加!
4.和蛇移动结合
9.画墙和初步实现
1.画墙
2.初步实现
三.游戏的改进与完善
1.解决频闪
2.去掉蛇尾
3.去除光标
四、完整游戏代码
1.game.h文件
2.test.c文件
总结
前言
本文使用C语言做出简易的贪吃蛇程序,此程序比较简单,适合新手入门或小白。
在这里主要实现一个简易蛇的移动和方向的控制。以及当蛇撞到墙壁,身体,食物这几种情况的判断。
一、游戏功能和效果 1.游戏功能1.wasd,控制蛇移动的方向。
2.每吃到一个食物移动速度变快。
3.游戏结束显示游戏分数(吃到食物+10分)
2.游戏效果 二. 游戏初步实现根据上图可以看到游戏界面大致可以分为3个:1.蛇的图形 2.产生的食物 3.周围的墙壁。(这里‘#’代表食物,‘*’代表蛇身,‘@’代表蛇头)
再细分的话:1.创建蛇的结构体,初始化,改变光标位置,画蛇。2.创建食物结构体,在地图中随机放食物。3.让蛇动起来,用4个键控制蛇的方向,撞到食物身体增长,碰到墙壁结束。4.画墙。
1.确定地图大小实现程序要有一个适当的范围,行和列可以使用两层for循环来确定:例如20行80列
确定后在头文件定义row和col为20,80就可以了。
2.创建蛇对象,食物对象 //蛇身对象 struct BODY { int X; int Y; }; //蛇对象 struct SNAKE { struct BODY body[ROW*COL];//蛇身最大长度 int size;//当前长度 }snake; //食物对象 struct FOOD { int X; int Y; }food; 3.初始化蛇这里根据效果图,蛇要居中,那么x,y坐标是行和列的1半。
蛇头是正中间,坐标是第一个:snake.body[0]。
蛇身就是从1开始的下标,第1个下标减1:snake.body[1].X = COL / 2 - 1;是第一节蛇身,第2个下标减2是第二节蛇身,那么使用for循环控制蛇身的长度。
void Initsnake() { //初始化蛇头 snake.size = 4; snake.body[0].X = COL / 2; snake.body[0].Y = ROW / 2; //初始化蛇身 int i = 0; for (i = 1; i <= snake.size; i++) { snake.body[i].X = COL / 2 - i; snake.body[i].Y = ROW / 2; } } 4.生成随机食物将生成的随机数%上行和列,控制在范围内,赋值到food的X,Y坐标上。
void Initfood()//生成食物 { food.X = rand() % COL; food.Y = rand() % ROW; } 5.画蛇在画蛇时我们要在地图的中间进行画蛇,那么怎么才能在中间呢?
一般在我们打字时,后面都有一个光标,光标在哪字就打在哪。所以在这里需要设置光标的位置,使他在中间就可以了。这里要用到光标修改函数:我们把相应的坐标给这个函数,就会定位到相应的位置。
void InitUI() {//画蛇 COORD coord = { 0 }; int i = 0; for (i = 0; i < snake.size; i++)//改变光标位置 { coord.X = snake.body[i].X; coord.Y = snake.body[i].Y; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); if (i == 0) { putchar('@'); } else { putchar('*'); } }在这里我们直接使用就可以,当i==0时,就画蛇头,其他情况就是蛇尾,画‘*’号。
6.画食物和画蛇相同
//画食物 coord.X = food.X; coord.Y = food.Y; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); putchar('#');
7. 游戏内移动控制 1.当按上下左右时移动方向改变 。这里可以看图:这里蛇头的坐标是(6,4),当按下上键坐标为(6,3),按下键为(6,5)当按左键右键时,坐标为(5,4),(7,4)。
那么改变方向只需要将X与Y坐标进行+1,-1就可以实现,这里我们定义两个全局变量kx,ky。
2.开始游戏时的默认方向当我们打开游戏,如果不按方向键,蛇也会默认向一个方向移动,这里我们要使用非阻塞方式检测是否有输入:kbhit()函数和无回显的取一个字符:getch()函数。
具体写法如下:默认向右移动,当有键盘输入时改变方向。
8.判断蛇撞墙,撞身体,撞食物3种情况这里可以使用while()来将这3种情况和蛇移动放在一起,进行实现。
1.蛇撞墙:判断蛇头坐标是否和行和列相等,如果相等游戏结束!while (snake.body[0].X >= 0 && snake.body[0].X < COL&& snake.body[0].Y >= 0 && snake.body[0].Y < ROW) {
2.蛇撞身体:判断蛇头坐标是否和蛇身坐标相等,如果相等游戏结束!//蛇头撞身体 int i = 0; for (i = 1; i < snake.size; i++) { if (snake.body[0].X == snake.body[i].X&&snake.body[0].Y == snake.body[i].Y) { return; } }
3.蛇撞食物:撞到食物后当前长度增加,再重新生成食物,移动速度变快,分数增加!//蛇头撞食物 if (snake.body[0].X == food.X&&snake.body[0].Y == food.Y) { snake.size++;//身体增长 Initfood();//食物消失 result += 10;//加分 if (speed != 60) { speed -= 30;//速度增加,到最大速度时停止 } }
4.和蛇移动结合void Playgame()//游戏控制 { char key = 'd'; //蛇撞墙 while (snake.body[0].X >= 0 && snake.body[0].X < COL&& snake.body[0].Y >= 0 && snake.body[0].Y < ROW) { //接收按键输入 if (_kbhit()) { key = _getch(); } switch (key) { case 'w':kx = 0; ky = -1; break; case 's':kx = 0; ky = +1; break; case 'd':kx = +1; ky = 0; break; case 'a':kx = -1; ky = 0; break; default: break; } //蛇头撞身体 int i = 0; for (i = 1; i < snake.size; i++) { if (snake.body[0].X == snake.body[i].X&&snake.body[0].Y == snake.body[i].Y) { return; } } //蛇头撞食物 if (snake.body[0].X == food.X&&snake.body[0].Y == food.Y) { snake.size++;//身体增长 Initfood();//食物消失 result += 10;//加分 if (speed != 60) { speed -= 30;//速度增加,到最大速度时停止 } }
9.画墙和初步实现 1.画墙 void Initwall()//画墙 { int i = 0; int j = 0; for (i = 0; i <= ROW; i++) { for (j = 0; j <= COL; j++) { if (i == 0) { printf("-"); } else if (i == ROW) { printf("-"); } else if (j == 0) { printf("|"); } else if (j == COL) { printf("|"); } else { printf(" "); } } printf("\\n"); } } 2.初步实现将墙画好后,蛇还不能移动,我们先看图:
蛇原来的坐标是(6,5)(6,4)6,3)(6,2),当向前走1格后是(6,6)(6,5)(6,4)(6,3)。
原来蛇头的坐标(6,5)给第一节蛇身,第一节蛇身给第2节,以此类推。也就是蛇头的坐标根据方向进行+1或-1,蛇身由上一节的进行赋值。
写好后再用清屏函数system("cls")进行更新,就可以初步实现!
但是运行后发现不断清屏会出现频闪,游戏效果非常不好!
三.游戏的改进与完善 1.解决频闪
初步完成后,蛇确实可以跑起来,但游戏体验太差!下面解决频闪问题!
这里第一想到的便是将清屏函数去掉换成延时函数:Sleep(),这样不需要一直更新,但又会出现新的问题:后面蛇尾会一直在,不会消失!那么就需要将最后一节蛇尾去掉。
2.去掉蛇尾首先我们将蛇尾的坐标存起来:
//存储蛇尾的坐标 lastX = snake.body[snake.size - 1].X; lastY = snake.body[snake.size - 1].Y;
然后我们在画蛇的函数中InitUI() ,将蛇尾坐标变成空格:
//去除蛇尾 coord.X = lastX; coord.Y = lastY; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); putchar(' ');
到这里我们就完美的解决掉问题了! 最后将光标去除就好了!!
3.去除光标这里直接使用此函数就可以!
四、完整游戏代码 1.game.h文件 #ifndef __GAME_H__ #define __GAME_H__ //定义行和列 #define ROW 20 #define COL 80 //头文件 #include<stdio.h> #include<stdlib.h> #include<time.h> #include<conio.h> #include<string.h> #include<windows.h> void Initsnake();//初始化蛇 void Initfood();//初始化食物 void InitUI();//画蛇 void Initwall();//画墙 void Playgame();//游戏:控制 int speed = 300;//初始速度 int result = 0;//游戏分数 lastX = 0;//存放蛇尾坐标 lastY = 0; int kx = 0;//方向控制 int ky = 0; //蛇身结构体 struct BODY { int X; int Y; }; //创建蛇结构体 struct SNAKE { struct BODY body[ROW*COL];//蛇身最大长度 int size;//长度 }snake; //创建食物结构体 struct FOOD { int X; int Y; }food; #endif 2.test.c文件 #define _CRT_SECURE_NO_WARNINGS 1 #include"game.h" void Initsnake() { //初始化蛇头 snake.size = 4; snake.body[0].X = COL / 2; snake.body[0].Y = ROW / 2; //初始化蛇身 int i = 0; for (i = 1; i <= snake.size; i++) { snake.body[i].X = COL / 2 - i; snake.body[i].Y = ROW / 2; } } void Initfood()//生成食物 { food.X = rand() % COL; food.Y = rand() % ROW; } void InitUI() {//画蛇 COORD coord = { 0 }; int i = 0; for (i = 0; i < snake.size; i++)//改变光标位置 { coord.X = snake.body[i].X; coord.Y = snake.body[i].Y; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); if (i == 0) { putchar('@'); } else { putchar('*'); } } //去除蛇尾 coord.X = lastX; coord.Y = lastY; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); putchar(' '); //画食物 coord.X = food.X; coord.Y = food.Y; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); putchar('#'); //结束时,改变位置 coord.X = 0; coord.Y = ROW + 2; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); } void Initwall()//画墙 { int i = 0; int j = 0; for (i = 0; i <= ROW; i++) { for (j = 0; j <= COL; j++) { if (i == 0) { printf("-"); } else if (i == ROW) { printf("-"); } else if (j == 0) { printf("|"); } else if (j == COL) { printf("|"); } else { printf(" "); } } printf("\\n"); } } void Playgame()//游戏控制 { char key = 'd'; //蛇撞墙 while (snake.body[0].X >= 0 && snake.body[0].X < COL&& snake.body[0].Y >= 0 && snake.body[0].Y < ROW) { InitUI();//更新蛇 //接收按键输入 if (_kbhit()) { key = _getch(); } switch (key) { case 'w':kx = 0; ky = -1; break; case 's':kx = 0; ky = +1; break; case 'd':kx = +1; ky = 0; break; case 'a':kx = -1; ky = 0; break; default: break; } //蛇头撞身体 int i = 0; for (i = 1; i < snake.size; i++) { if (snake.body[0].X == snake.body[i].X&&snake.body[0].Y == snake.body[i].Y) { return; } } //蛇头撞食物 if (snake.body[0].X == food.X&&snake.body[0].Y == food.Y) { snake.size++;//身体增长 Initfood();//食物消失 result += 10;//加分 if (speed != 60) { speed -= 30;//速度增加,到最大速度时停止 } } //存储蛇尾的坐标 lastX = snake.body[snake.size - 1].X; lastY = snake.body[snake.size - 1].Y; //蛇移动,前一节身体给后一节身体赋值 for (i = snake.size - 1; i > 0; i--) { snake.body[i].X = snake.body[i - 1].X; snake.body[i].Y = snake.body[i - 1].Y; } snake.body[0].X += kx; snake.body[0].Y += ky; Sleep(speed); } return; } void game()//游戏函数 { //去除光标 CONSOLE_CURSOR_INFO cci; cci.dwSize = sizeof(cci); cci.bVisible = FALSE; SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci); //初始化蛇 Initsnake(); //初始化食物 Initfood(); //画墙 Initwall(); //画蛇 InitUI(); //游戏控制 Playgame(); //成绩 printf("Game over!游戏结束!\\n"); printf("游戏分数:%d\\n", result); } int main() { srand((unsigned int)time(NULL)); game();//游戏函数 return 0; }
总结
以上就是今天贪吃蛇的内容,主要就是蛇移动的实现比较难。这里就是比较简单实现方法,230行左右就可以实现,还是比较容易理解的!可以根居其他的加一些功能来进行完善!
版权声明:本文标题:C语言实现贪吃蛇(简易) 内容由林淑君副主任自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.xiehuijuan.com/baike/1686897829a115800.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论