C语言简易贪吃蛇(附完整代码)

C语言简易贪吃蛇(附完整代码)贪吃蛇小游戏这是楼主刚学完C语言写的第一个小游戏,代码主要参考:https://blog.csdn.net/qq_37074040/article/details/54766680我在模仿代码的过程中发现了原作者程序中的一些bug,以下f附有我加以改进后的代码。1.游戏界面楼主认为这个小游戏游戏界面的核心在于光标的控制。只要我们能让光标到达…

大家好,又见面了,我是你们的朋友全栈君。

                   贪吃蛇小游戏

刚学完C语言写的第一个小游戏,代码主要参考:
https://blog.csdn.net/qq_37074040/article/details/54766680
我在模仿代码的过程中发现了原作者程序中的一些bug,以下f附有我加以改进后的代码。

1.游戏界面
这个小游戏游戏界面的核心在于光标的控制。只要我们能让光标到达我们想要的地方,我们就能完成游戏界面的绘制,蛋的生成。简直就像天上地下,无所不能。
实现:gotoxy()函数

2.游戏体验感
如何将用户的输入读入,而不显示在屏幕上?
实现:getch()函数(包含在<conio.h>中)
如何防止用户的非法输入?玩游戏的过程中难免会摁到其他的键,如何让它不影响到我们的游戏?如果蛇在往前行走,我们控制方向向后,该怎么处理?
实现:保存蛇的前进状态。

3.游戏关键
蛇该如何打印?如何实现蛇的行走?
如何完成吃蛋的过程?
游戏结束的条件是什么?
这几个问题都是实现游戏的关键步骤,但是实际操作起来并没有想象中的那么难,希望读者结合下文代码自行思考。

代码还可以大幅度优化,读者可以自行思考。

如果发现代码有bug,欢迎下方留言。

如果觉得楼主的代码对你有帮助的话,可以点个关注,点个赞,谢谢!

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <time.h>
#include <conio.h>
#define frame_height 30//地图尺寸
#define frame_width 50
#define UP 'w'//移动
#define DOWN 's'
#define LEFT 'a'
#define RIGHT 'd'
int i,j,k,sp,score;
char ch=UP,state=UP,choo,n;//初始化方向
int grow=0;
struct Food//食物
{ 

int x;//横坐标
int y;//纵坐标
} food;
struct Snake//蛇
{ 

/*用数组储存蛇的每一部分的坐标*/
int x[100];
int y[100];
int len;//长度
int speed;//速度
} snake;
void map(void);//地图
void update_food(void);//更新食物
void move_snake(void);//蛇的移动
int alive(void);//判断蛇是否死亡
void get_speed(void);//更新速度
void gotoxy(int x,int y);//移动光标,进行游戏界面的打印
int main()
{ 

do
{ 

score=0;//初始化分数为0
/*让用户进行难度选择,有彩蛋*/
printf("Choose the degree of difficulty:\n1:easy\t2:middle 3:difficult\n");
n=getch();
switch(n)
{ 

case '1':
{ 

sp=300;
break;
}
case '2':
{ 

sp=230;
break;
}
case '3':
{ 

sp=180;
break;
}
default:
{ 

printf("Congratulations!Welcome to Devil's difficulty\n");
sp=120;
break;
}
}
system("cls");//每次新一局游戏先清屏,包含在<stdlib.h>
map();//打印地图
/*开始游戏*/
while(1)
{ 

update_food();//生产食物
get_speed();//获取速度
move_snake();//移动
Sleep(snake.speed);//延时函数,speed数值越大延时越长
if(!(alive()))//判断蛇是否死亡
{ 

break;//死亡则退出循环
}
}
printf("Game Over!\n");
printf("1:Restart\t2:exit");
choo=getch();
}
while(choo=='1');
return 0;
}
void map()
{ 

srand(time(NULL));
/*打印第一个食物*/
/*Attention!此处留了一个bug:可能食物 的位置与初始的蛇重合,然后食物就会消 失,读者可以加以改进*/
food.x=rand()%(frame_height-2)+1;
food.y=rand()%(frame_width-2)+1;//在框内
gotoxy(food.x,food.y);//把光标移动到该坐标
printf("$");//打印食物
/*snake的初始化*/
snake.x[0]=frame_height/2;
snake.y[0]=frame_width/2;
gotoxy(snake.x[0],snake.y[0]);
printf("@");
snake.len=3;
snake.speed=200;
for(k=1; k<snake.len; k++)
{ 

snake.x[k]=snake.x[k-1]+1;
snake.y[k]=snake.y[k-1];
gotoxy(snake.x[k],snake.y[k]);
printf("@");
}
/*墙壁*/
for(j=0; j<frame_width; j++)
{ 

gotoxy(0,j);
printf("#");
gotoxy(frame_height-1,j);
printf("#");
}
for(i=0; i<frame_height-1; i++)
{ 

gotoxy(i,0);
printf("#");
gotoxy(i,frame_width-1);
printf("#");
}
gotoxy(2,frame_width+3);
if(n=='1') printf("Difficulty: easy");
else if(n=='2') printf("Difficulty: middle");
else if(n=='3') printf("Difficulty: difficult");
else printf("Welcome to the Devil's difficulty");
gotoxy(4,frame_width+3);
printf("UP: w");
gotoxy(6,frame_width+3);
printf("DOWN: s");
gotoxy(8,frame_width+3);
printf("LEFT: a");
gotoxy(10,frame_width+3);
printf("RIGHT:d");
gotoxy(12,frame_width+3);
printf("Your score:%d",score);
gotoxy(28,frame_width+3);
printf("Made by Zhao Hejie");
}
/*食物*/
void update_food()
{ 

if(snake.x[0]==food.x&&snake.y[0]==food.y)//吃到食物
{ 

score+=10;
gotoxy(12,frame_width+3);
printf("Your score:%d",score);
srand(time(NULL));
/*以下是更新食物的代码,里面排除了 食物与蛇重合的情况,读者可以参考以 下代码完成对上述bug的改进*/
int flag=1;//标记变量
do
{ 

food.x=rand()%(frame_height-2)+1;
food.y=rand()%(frame_width-2)+1;//在框内
for(i=0; i<snake.len; i++)
{ 

if(food.x==snake.x[i]&&food.y==snake.y[i])
{ 

flag=0;//有重合
break;
}
}
}
while(flag==0);
/*打印食物*/
gotoxy(food.x,food.y);
printf("$");
snake.len++;
grow=1;//表明长了,在move_snake函数中有用到
}
}
/*移动蛇*/
void move_snake()
{ 

while(kbhit())//键盘有输入
{ 

ch=getch();
}
if(!grow)//没有长
{ 

gotoxy(snake.x[snake.len-1],snake.y[snake.len-1]);
printf(" ");//走了,在数组的最后打印空格,清除原有的蛇尾
}
for(k=snake.len-1; k>0; k--)//更新蛇的坐标,除了蛇头,其余位置继承上一个点的坐标
{ 

snake.x[k]=snake.x[k-1];
snake.y[k]=snake.y[k-1];//移动位置
}
switch(ch)//改变方向
{ 

case UP:
{ 

if(state==DOWN)//如果此时方向向下,输入向上的作用要被无视
{ 

snake.x[0]++;
break;
}
else
{ 

snake.x[0]--;
state=UP;//其余的改变状态为向上
break;
}
}
case DOWN:
{ 

if(state==UP)
{ 

snake.x[0]--;
break;
}
else
{ 

snake.x[0]++;
state=DOWN;
break;
}
}
case LEFT:
{ 

if(state==RIGHT)
{ 

snake.y[0]++;
break;
}
else
{ 

snake.y[0]--;
state=LEFT;
break;
}
}
case RIGHT:
{ 

if(state==LEFT)
{ 

snake.y[0]--;
break;
}
else
{ 

snake.y[0]++;
state=RIGHT;
break;
}
}
/*摁其余键,保持原有状态*/
default:
{ 

if(state==DOWN)
{ 

snake.x[0]++;
break;
}
else if(state==UP)
{ 

snake.x[0]--;
break;
}
else if(state==LEFT)
{ 

snake.y[0]--;
break;
}
else if(state==RIGHT)
{ 

snake.y[0]++;
break;
}
}
}
gotoxy(snake.x[0],snake.y[0]);
printf("@");//打印蛇头
grow=0;//初始成长状态为0
gotoxy(frame_height,0);//光标移动到地图左下角下方
}
/*存活状态*/
int alive(void)
{ 

if(snake.x[0]==0||snake.x[0]==frame_height-1||snake.y[0]==0||snake.y[0]==frame_width-1)//撞墙
return 0;
for(k=1; k<snake.len; k++) //咬到自己
{ 

if(snake.x[0]==snake.x[k]&&snake.y[0]==snake.y[k])
return 0;
}
return 1;
}
/*加速*/
/*speed越大,蛇的速度越小*/
void get_speed()
{ 

if(snake.len<=6)
snake.speed=sp;
else if(snake.len<=10)
snake.speed=sp-20;
else if(snake.len<=20)
snake.speed=sp-50;
else if(snake.len<=30)
snake.speed=sp-60;
else
snake.speed=sp-70;
}
/*移动光标*/
void gotoxy(int x,int y)
{ 

HANDLE hout;
COORD cor;
/* typedef struct _COORD { SHORT X; // horizontal coordinate SHORT Y; // vertical coordinate } COORD; 用该结构体来储存坐标 */
hout=GetStdHandle(STD_OUTPUT_HANDLE);//从标准输出设备中取得一个句柄
/*这其中x,y的赋值对象要注意,不懂的好好想想*/
cor.X=y;
cor.Y=x;
SetConsoleCursorPosition(hout,cor);//定位光标的函数
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/144985.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 深入理解Java类加载器(1):Java类加载原理解析

    深入理解Java类加载器(1):Java类加载原理解析1      基本信息每个java开发人员对java.lang.ClassNotFoundExcetpion这个异常肯定都不陌生,这背后就涉及到了java技术体系中的类加载。Java的类加载机制是java技术体系中比较核心的部分,虽然和大部分开发人员直接打交道不多,但是对其背后的机理有一定理解有助于排查程序中出现的类加载失败等技术问题,对理解java虚拟机的连接模型和java语言的动态性

  • webstorm关闭eslint检测

    webstorm关闭eslint检测vue项目已经设置关闭eslint,但是代码还是很多标红线的地方,原因是webstorm这个ide默认启用了eslint,可以在设置中关闭把Enable的勾去掉即可

  • connectionstrings汇总

    connectionstrings汇总http://www.connectionstrings.com/所有的数据库连接语句

  • 腾讯 OCR 情况

    腾讯 OCR 情况

  • 文字超出三行省略…显示全文「建议收藏」

    文字超出三行省略…显示全文「建议收藏」1、在开发过程中,我们经常会用到这种超出三行显示…的要求,使用css属性是可以的,但是需要考虑兼容性问题实现单行文本的溢出显示省略号,我们应该都知道用text-overflow:ellipsis

  • postman安装使用教程(标贝科技)「建议收藏」

    postman安装使用教程(标贝科技)「建议收藏」postman安装使用教程文章目录postman安装使用教程前言一、postman安装二、postman使用前言postman是Chrome浏览器的插件,是一款功能强大的网页调试工具(接口调试神器)一、postman安装1.下载:https://www.postman.com/downloads/2.安装双击postman应用程序进入到postman主界面,如下证明安装成功3.界面主要功能介绍二、postman使用1.状态码解释各位小伙伴可以学习一下关于接口

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号