当前位置:网站首页>C语言小游戏------贪吃蛇----小白专用
C语言小游戏------贪吃蛇----小白专用
2022-07-29 12:21:00 【嗯嗯好的呢!】
C语言贪吃蛇小游戏
视频正在随缘策划中。。。。
废话在后面直接上程序
该程序在VS2019上可完美运行。
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#include<time.h>
#include<conio.h>
constexpr auto maphigh = 28, mapwide = 84;
struct virus
{
int x;
int y;
}virus;
unsigned short snakesize = 50, speed = 300, len = 4;
struct snake
{
int x[50];
int y[50];
int len;//蛇的长度
int speed;//蛇的速度
}snake;
int key = 'w';//初始化方向
void gotoxy(int x, int y);
void drawmap();
void keydown();
void creatvirus();
int snakestatus();
void startgame();
int menuselect();
void goodbye();
void introduce();
void edition();
int setup();
void respect();
int setup1();
int modifydiffculty();
void diffculty();
int customize();
void customize1();
int main()
{
for (;;)
{
system("cls");//清屏
switch (menuselect())
{
case 1://开始游戏
startgame();
break;
case 2://介绍
introduce();
break;
case 3://版本
edition();
break;
case 4://设置
setup1();
break;
case 5:
goodbye();
return 0;
default:
break;
}
}
}
void drawmap()//1.画地图
{
//⊙:病毒 █:蛇身(占用两个字符)
srand((unsigned int)time(NULL));//随机病毒出现的位置
int i, k;
for (i = 0; i <= maphigh; i++)
{
gotoxy(0, i);
printf("█");//打印左边框
gotoxy(mapwide, i);
printf("█");//打印右边框
}
for (i = 0; i <= mapwide; i += 2)//+=2因为 █占两个字节
{
gotoxy(i, 0);
printf("█");//打印下边框
gotoxy(i, maphigh);
printf("█");//打印上边框
}
//画蛇
snake.len = len;
snake.speed = speed;
//初始化蛇的位置
snake.x[0] = mapwide / 2;
snake.y[0] = maphigh / 2;//[0]为蛇头的位置
//画蛇头
gotoxy(snake.x[0], snake.y[0]);
printf("█");
//画蛇身
for (k = 1; k < snake.len; k++)
{
snake.x[k] = snake.x[k - 1] + 2;
snake.y[k] = snake.y[k - 1];
gotoxy(snake.x[k], snake.y[k]);
printf("█");
}
while (1)
{
virus.x = rand() % (mapwide - 4) + 2;//+2,+1这个与█所占的字符有关,长占两个字符宽1个
virus.y = rand() % (maphigh - 2) + 1;//画个图,显而易见
if (virus.x % 2 == 0)
break;
}
gotoxy(virus.x, virus.y);
printf("⊙");
gotoxy(mapwide + 4, maphigh);
printf("⊙:%d", snakesize - snake.len);
}
void creatvirus()//2.产生病毒
{
if (snake.x[0] == virus.x && snake.y[0] == virus.y)
{
//printf("a");//声音
snake.len++;
srand((unsigned)time(NULL));
while (1)
{
int flag = 1;
virus.x = rand() % (mapwide - 4) + 2;//+2,+1这个与█所占的字符有关,长占两个字符宽1个
virus.y = rand() % (maphigh - 2) + 1;//画个图,显而易见
//产生的病毒不能在蛇的身上
for (int k = 0; k < snake.len; k++)
{
if (snake.x[k] == virus.x && snake.y[k] == virus.y)
{
flag = 0;//virus不合适的标志
break;
}
}
if (flag == 1 && virus.x % 2 == 0)//病毒位置合法且x坐标为偶数
{//x左右是以两个字节为单位运动的,若virus的x坐标为奇数,就不存在snake.x[k] == virus.x
break;
}
}
}
gotoxy(virus.x, virus.y);
printf("⊙");
gotoxy(mapwide + 8, 0);//将光标移走
printf("W");
gotoxy(mapwide + 6, 1);
printf("A S D 进行控制");
gotoxy(mapwide + 4, maphigh);
printf("⊙:%d", snakesize - snake.len);
}
void keydown()//3.按键
{
int i, temp;
if (_kbhit()) //kbhit函数检查当前是否有键盘输入,若有则返回一个非0值,否则返回0
{
fflush(stdin);// 清空输入缓冲区,通常是为了确保不影响后面的数据读取
temp = _getch();//getch:从控制台读取一个字符,但不显示在屏幕上
if ((temp == 'a' || temp == 'A') && (key != 'D' && key != 'd'))//解决了按反方向键蛇自杀的问题
{
key = temp;
}
if ((temp == 'w' || temp == 'W') && (key != 's' && key != 'S'))
{
key = temp;
}
if ((temp == 's' || temp == 'S') && (key != 'W' && key != 'w'))
{
key = temp;
}
if ((temp == 'D' || temp == 'd') && (key != 'a' && key != 'A'))
{
key = temp;
}
}
//擦除最后一节
gotoxy(snake.x[snake.len - 1], snake.y[snake.len - 1]);
printf(" ");
for (i = snake.len - 1; i > 0; i--)
{
snake.x[i] = snake.x[i - 1];//以前1的位置现在变成了2,0变成了1
snake.y[i] = snake.y[i - 1];
}
switch (key)//最后一节已经擦出,前移后0,1位置重合,左上角坐标为0,0
{
case'w':
case'W':
snake.y[0]--;
break;
case's':
case'S':
snake.y[0]++;
break;
case'a':
case'A':
snake.x[0] -= 2;
break;
case'd':
case'D':
snake.x[0] += 2;
break;
}
gotoxy(snake.x[0], snake.y[0]);
printf("█");
gotoxy(mapwide + 2, 0);//将光标移走
}
int snakestatus()//4.蛇的状态
{
if ((snake.x[0] == 0 || snake.x[0] == mapwide) || (snake.y[0] == 0 || snake.y[0] == maphigh))
return 0;
for (int k = 1; k < snake.len; k++)
{
if (snake.x[0] == snake.x[k] && snake.y[0] == snake.y[k])
return 0;
}
return 1;
}
void gotoxy(int x, int y)
{//1.找到控制台这个窗口
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
/*HANDLE为句柄 ↑得到(输出窗口的)句柄。
Windows是一个以虚拟内存为基础的操作系统,很多时候,
进程的代码和数据并不全部装入内存,进程的某一段装入内存后,
还可能被换出到外存,当再次需要时,再装入内存。两次装入的地址绝大多数情况下是不一样的。
也就是说,同一对象在内存中的地址会变化。那么,程序怎么才能准确地访问到对象呢?为了解决这个问题,Windows引入了句柄。
数值上,是一个32位无符号整型值(32位系统下);逻辑上,相当于指针的指针;形象理解上,是Windows中各个对象的一个唯一的、固定不变的ID;
作用上,Windows使用句柄来标识诸如窗口、位图、画笔等对象,并通过句柄找到这些对象。*/
//2.设置光标
COORD coord;
/*COORD 为Windows.h中自带函数原型大体为struct _coord{short x;short y;}coord;*/
coord.X = x;
coord.Y = y;
//4.同步到控制台SetConsoleCursorPosition
SetConsoleCursorPosition(handle, coord);//定位到handle这个窗口,把光标打在coord坐标
}
void startgame()
{
system("cls");
drawmap();
while (1)
{
creatvirus();
keydown();
Sleep(snake.speed);//void sleep(int seconds)自带函数参数 seconds 为要暂停的毫秒数。
if (!snakestatus())//判断死亡时snakestaus为0,
{
gotoxy(mapwide / 2, maphigh / 2);
printf("Game Over");
getchar();
getchar();
break;
}
if (snake.len == snakesize)
{
gotoxy(mapwide / 3, maphigh / 2);
printf("恭喜您消灭了全部病毒,胜利(^-^)V");
getchar();
respect();
break;
}
}
}
int menuselect()
{
char number;
int a;
printf("
1.开始游戏
");
printf("
2.游戏介绍
");
printf("
3.游戏版本
");
printf("
4.设置
");
printf("
5.退出游戏
");
printf("
请选择(数字)");
while (1)
{
number = getchar();
a = (int)number - 48;
if (number <= '5' && number >= '1')
return a;
printf("
");
}
}
void goodbye()
{
system("cls");
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_INTENSITY | FOREGROUND_RED);//设置红色
gotoxy(0, 12);
printf(" 谢谢使用!再见!
");
getchar();
getchar();
}
void respect()
{
system("cls");
gotoxy(0, 4);
printf(" *在此向全国的医护人员表示敬意*
");
Sleep(1000);
printf(" *感谢他们的默默付出*
");
Sleep(1000);
printf(" *感谢他们对抗击疫情做出的贡献*
");
Sleep(1000);
printf(" *此致*
");
printf(" * 敬礼 *
");
Sleep(2000);
getchar();
}
void introduce()
{
system("cls");
gotoxy(0, 4);
printf(" 游戏规则
");
printf(" 2020年新冠病毒肆虐,威胁着人类
");
printf(" 玩家将控制蛇消灭随机出现的病毒⊙
");
printf(" 消灭所有病毒即可获得胜利。
");
printf("
");
printf(" Enter返回主菜单");
getchar();
getchar();
}
void edition()
{
system("cls");
gotoxy(0, 4);
printf(" *********************************************
");
printf(" * 欢 迎 *
");
printf(" * 版本号: 1.2 *
");
printf(" * 更新:1.修复了反方向自杀的问题 *
");
printf(" * 2.修复了蛇吃墙的问题 *
");
printf(" * 3.新增了菜单与设置功能 *
");
printf(" * 4.修改了部分整形变量节省空间 *
");
printf(" *********************************************
");
printf(" Enter返回主菜单");
getchar();
getchar();
}
int setup()
{
//system("color 6f"); //第一个为背景色,第二个为字体颜色
/*0 = 黑色 8 = 灰色
1 = 蓝色 9 = 淡蓝色
2 = 绿色 A = 淡绿色
3 = 湖蓝色 B = 淡浅绿色
4 = 红色 C = 淡红色
5 = 紫色 D = 淡紫色
6 = 黄色 E = 淡黄色
7 = 白色 F = 亮白色*/
char s;
int a;
system("cls");
printf("
1.修改难度
");
printf("
2.自义定设置
");
printf("
3.颜色设置
");
printf("
4.音效设置
");
printf("
5.返回
");
printf("
请选择(数字)");
while (1)
{
s = getchar();
a = (int)s - 48;
if (s <= '5' && s >= '1')
return a;
printf("
");
}
}
int setup1()
{
switch (setup())
{
case 1:
diffculty();
break;
case 2:
customize1();
break;
default:
break;
}
return 0;
}
int modifydiffculty()
{
char s;
int a;
system("cls");
printf("
1.简单
");
printf("
2.普通
");
printf("
3.困难
");
printf("
4.修罗地狱
");
printf("
请选择(数字)");
while (1)
{
s = getchar();
a = (int)s - 48;
if (s <= '4' && s >= '1')
return a;
printf("
");
}
}
void diffculty()
{
switch (modifydiffculty())
{
case 1:
len = 4;
speed = 500;
snakesize = 10;
system("cls");
gotoxy(8, 8);
printf(" 修改成功!
");
printf("
");
system("pause");
break;
case 2:
len = 4;
speed = 300;
snakesize = 25;
system("cls");
gotoxy(8, 8);
printf(" 修改成功!
");
printf("
");
system("pause");
break;
case 3:
len = 4;
speed = 70;
snakesize = 50;
system("cls");
gotoxy(8, 8);
printf(" 修改成功!
");
printf("
");
system("pause");
break;
case 4:
len = 4;
speed = 25;
snakesize = 70;
system("cls");
gotoxy(8, 8);
printf(" 修改成功!
");
printf("
");
system("pause");
break;
default:
break;
}
}
int customize()
{
char s;
int a;
system("cls");
printf("
1.自定义速度
");
printf("
2.自定义初始长度
");
printf("
请选择(数字)");
while (1)
{
s = getchar();
a = (int)s - 48;
if (s <= '2' && s >= '1')
return a;
printf("
");
}
}
void customize1()
{
int s;
switch (customize())
{
case 1://自定义速度
system("cls");
gotoxy(8, 8);
printf(" 请输入速度(1-999)");
scanf_s("%d", &s);
speed = (1000 - s);
break;
case 2:
system("cls");
gotoxy(8, 8);
printf(" 请输入初始长度:");
scanf_s("%d", &s);
len = s;
break;
default:
break;
}
}
对于刚学完C语言的初学者,直接做这种小游戏也是一件非常困难的事情,中间还有很大的鸿沟。老师上课讲授的知识非常有限,大部分知识还需要同学们自己去探索。
如果你用的时vs2010,那估计以上程序一定会报错,两个版本在scanf函数上有所不同,在2019中必须要求使用scanf_s.
vs2010
vs2019
scanf
scanf_s
其次,2019允许在程序运行时定义变量
例如:
for(int i=1;i<3;i++)
而在2010中是不允许这样书写的。
除上述两点外,2010和2019还有很多小地方不同,当然我们不需要特意记住这些不同,在2019都会给予相应的提示。
个人没有把自定义函数和main函数分开,毕竟只是自己写着玩。
程序的写法也有很多很多种,不必拘于一种,也期待各位写出更加简练高效的程序。
个人小白,如有错误也希望各位大佬能够指出。
边栏推荐
- IDEA2021.2安装与配置(持续更新)
- html+css+php+mysql实现注册+登录+修改密码(附完整代码)
- shell if else 使用
- 第十章 发现和记录 REST API
- 微信H5网页分享只显示链接处理办法
- [纯理论] FPN (Feature Pyramid Network)
- Error EPERM operation not permitted, mkdir ‘Dsoftwarenodejsnode_cache_cacach两种解决办法
- JS advanced four (map, reduce, filter, sort, arrow function, class inheritance, yield)
- Interceptors and filters (3) @interface custom annotation interception
- 国内首秀元宇宙Live House圆满收官,百事可乐虚拟偶像真的好会!!
猜你喜欢
随机推荐
什么是BOM
WordPress 固定链接设置
DAY 26 daily SQL clock 】 【 change 丨 restaurant turnover growth difficulty moderate 】 【
Chapter ten find and record the REST API
投资127亿!深圳,再添一所985
"Qidong well day lily" is the national geographical indications protection products?Ants investigation on July 29, the answer
【day04】IDEA, method
DBeaver 安装及配置离线驱动
Container is changed | deploy MySQL cluster in the Rancher
DAY 22 丨 page daily clock in SQL 】 【 recommend 【 difficulty moderate 】
Based article 】 【 learn with Rust | Rust, variables and data types
APP local number one-click login
金仓数据库KingbaseES客户端编程接口指南-ODBC(9. 疑难解答)
MySQL八股文背诵版
金仓数据库KingbaseES客户端编程接口指南-ODBC(8. 示例说明)
adb for mysql在什么平台进行开发啊
金仓数据库KingbaseES客户端编程接口指南-ODBC(6. KingbaseES ODBC 的扩展属性)
String.split()最详细源码解读及注意事项
TiDB upgrade share with case (TiDB v4.0.1 to v5.4.1)
es6 arrow function explanation