C语言 贪吃蛇
程序员文章站
2024-03-19 16:51:28
...
1.对于一个变成初学者来说,没有什么比写一个贪吃蛇更加有成就感了,
2.主要难点是要想让蛇的尾巴在移动时缩短,就要用新的数组存储身体的每一节指向的前一段身体的位置,这里我用的是genzongx和genzongy两个二维数组记录指向的坐标。
3.其次难点是怎样实现在蛇移动时也能从键盘输入方向来控制蛇的移动,我一开始百思不得其解,因为要从键盘输入的话就必定意味着程序要暂停在那里等待输入,但是这样的话游戏就没法正常进行了,然后我借鉴了公众号“C语言小代码”里的贪吃蛇代码,其中的一个名叫kbhit()的函数引起了我的注意,这个函数很神奇,当你什么都不输入时,程序运行到这里就会返回一个值0,否则返回1,于是我们就可以把这个函数写在if的条件中,然后里面写上读取键盘的语句,就完美地解决了这个问题。
4.其他问题相比之下都小了很多,只要有一定基础并且善于思考都是能很好解决的。
5.写程序大约用了3个多小时。
代码:
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<conio.h>
#include<time.h>
#define A 25 //长
#define B 20 //宽
char a[B][A],des;
int shetoux,shetouy,z1,z2,z3,z4,game,shi;
int weibax,weibay,genzongx[B][A],genzongy[B][A];
int i,j,xian,xian1,speed,foodnum,biansu,score;
void shiwu() { //生成食物
int xx,yy;
for(;;) {
xx=rand()%(B-2)+1;
yy=rand()%(A-2)+1;
if(a[xx][yy]!='+'&&a[xx][yy]!='O'&&a[xx][yy]!='$') break;
}
a[xx][yy]='$';
}
void dest(int qq) { //移动蛇身
z1=shetoux;
z2=shetouy;
z3=weibax;
z4=weibay;
switch(qq) {
case 1: shetoux=shetoux-1; break; //判断方向
case 2: shetoux=shetoux+1; break;
case 3: shetouy=shetouy-1; break;
case 4: shetouy=shetouy+1; break;
}
if(shetoux==B-1) shetoux=1; //判断蛇头位置
if(shetouy==A-1) shetouy=1;
if(shetoux==0) shetoux=B-2;
if(shetouy==0) shetouy=A-2;
genzongx[z1][z2]=shetoux;
genzongy[z1][z2]=shetouy;
a[z1][z2]='+';
if(a[shetoux][shetouy]=='+') game=0;
if(a[shetoux][shetouy]=='$') {
shi--; //减食物
score++; //加分
if(biansu==1&&speed!=1) { //变速
speed=speed-20;
if(speed==0) speed=1;
}
}
else {
a[weibax][weibay]=' '; //尾巴消失
weibax=genzongx[z3][z4];
weibay=genzongy[z3][z4];
}
a[shetoux][shetouy]='O'; //蛇头移动
}
//主函数
int main() {
for(;;) {
des=77; //初始键盘方向
shetoux=1; // 蛇头左下标
shetouy=4; // 蛇头右下标
game=1; //游戏是否结束
shi=0; //食物是否还有
weibax=1; //尾巴左下标
weibay=1; //尾巴右下标
xian=1;
score=0; //得分
biansu=0; //是否变速
printf("将1到1000的整数作为蛇的速度\n\n数值越小,蛇越快\n\n若输入为0,则会从500开始加速\n\n请输入速度:");
scanf("%d",&speed);
if(speed==0) {
biansu=1;
speed=500;
}
printf("\n请输入食物数量:");
scanf("%d",&foodnum);
system("cls");
srand((unsigned)time(0));
genzongx[1][1]=1,genzongy[1][1]=2,genzongx[1][2]=1,genzongy[1][2]=3,genzongx[1][3]=1,genzongy[1][3]=4;
for(i=0;i<B;i++) for(j=0;j<A;j++) a[i][j]=' '; //空白
for(i=0;i<A;i++) {
a[0][i]='_'; //上边界
a[B-1][i]='~'; //下边界
}
for(i=1;i<B-1;i++) a[i][0]=a[i][A-1]='|'; //左右边界
a[1][1]=a[1][2]=a[1][3]='+'; //蛇身
a[1][4]='O'; //蛇头
if(shi<foodnum) {
shiwu();
shi++;
}
printf(" 贪吃蛇(速度:%d)\n",speed); //打印初始界面
for(i=0;i<B;i++) {
for(j=0;j<A;j++) {
if(a[i][j]=='+') printf(""); //蛇身
else if(a[i][j]=='O') printf(""); //蛇头
else if(a[i][j]=='$') printf("屎"); //食物
else if(a[i][j]==' ') printf(" "); //空白
else printf("█"); //边界
}
printf("\n");
}
printf("\n按方向键开始游戏\n\n\n");
system("pause"); //程序暂停
system("cls"); //清空屏幕
for(;;) {
xian1=xian;
switch(des){
case 72: xian=1; break; //识别方向
case 80: xian=2; break;
case 75: xian=3; break;
case 77: xian=4; break;
default: break;
}
if(xian==1&&xian1==2) xian=xian1; //判断方向是否相反
if(xian==2&&xian1==1) xian=xian1;
if(xian==3&&xian1==4) xian=xian1;
if(xian==4&&xian1==3) xian=xian1;
for(;;) {
dest(xian);
if(shi<foodnum) { //生成食物
shiwu();
shi++;
}
system("cls"); //清空屏幕
printf("速度:%d 得分:%d\n\n",500-speed,score);
for(i=0;i<B;i++) { //打印地图
for(j=0;j<A;j++) {
if(a[i][j]=='+') printf("");
else if(a[i][j]=='O') printf("");
else if(a[i][j]=='$') printf("屎");
else if(a[i][j]==' ') printf(" ");
else printf("█");
}
printf("\n");
}
if(game==0) break;
Sleep(speed); //蛇的速度,数值越小蛇越快
if(kbhit()!=0) { //键盘获取方向,若没有输入,一直循环
des=getch();
des=getch();
}
break;
}
if(game==0) {
printf(" 你死了!\n");
break;
}
}
printf("\n按任意键继续玩");
system("pause");
system("cls");
}
}
运行效果图:
Dev-C++上可以直接编译运行成功。
(05.28更新)
优化了好几个地方,把原来的清屏打印改成了直接覆盖,并隐藏了光标,这样的话屏幕再也不会一闪一闪啦!彩色化了界面,去掉了速度模块和复活模块,去掉了头,优化了代码结构,大多用函数解决,使得读起来更好懂,但是也因此导致代码长了一倍,但是注释很多,还是比较好懂的。
代码:
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<conio.h>
#include<time.h>
#define A 25 //长
#define B 20 //宽
//全局变量
int z1,z2,z3,z4,i,j,xian,xian1,des;
char a[B][A]; //整个地图
int xx,yy; //食物坐标
int shetoux,shetouy; //蛇头坐标
int weibax,weibay; //尾巴坐标
int genzongx[B][A],genzongy[B][A]; //跟踪坐标
int speed,foodnum,score,game,shi;
//速度,预计食物数量,分数,是否结束,当前食物数量
//初始化变量
void Beginning() {
des=77; //初始键盘方向向右
shetoux=1; // 蛇头左下标
shetouy=4; // 蛇头右下标
game=1; //游戏是否结束
shi=0; //食物是否还有
weibax=1; //尾巴左下标
weibay=1; //尾巴右下标
xian=1;
score=0; //得分
srand((unsigned)time(0));
genzongx[1][1]=1,genzongy[1][1]=2,genzongx[1][2]=1,genzongy[1][2]=3,genzongx[1][3]=1,genzongy[1][3]=4;
for(i=0;i<B;i++) for(j=0;j<A;j++) a[i][j]=' '; //空白
for(i=0;i<A;i++) {
a[0][i]='_'; //上边界
a[B-1][i]='~'; //下边界
}
for(i=1;i<B-1;i++) a[i][0]=a[i][A-1]='|'; //左右边界
a[1][1]=a[1][2]=a[1][3]='+'; //蛇身
a[1][4]='O'; //蛇头
}
const WORD FORE_BLUE = FOREGROUND_BLUE; //蓝色文本属性
const WORD FORE_GREEN = FOREGROUND_GREEN; //绿色文本属性
const WORD FORE_RED = FOREGROUND_RED; //红色文本属性
const WORD FORE_YELLOW = FORE_RED | FORE_GREEN; //黄色文本属性
const WORD FORE_GRAY = FOREGROUND_INTENSITY; //灰色文本属性
const WORD BACK_BLUE = BACKGROUND_BLUE; //蓝色背景属性
const WORD BACK_GREEN = BACKGROUND_GREEN; //绿色背景属性
const WORD BACK_RED = BACKGROUND_RED; //红色背景属性
const WORD BACK_PURPLE = BACK_BLUE | BACK_RED; //紫色背景属性
const WORD BACK_CYAN = BACK_BLUE | BACK_GREEN; //青色背景属性
const WORD BACK_YELLOW = BACK_RED | BACK_GREEN; //黄色背景属性
const WORD BACK_GRAY = BACKGROUND_INTENSITY; //灰色背景属性
//打印位置
void Position(int x, int y) {
COORD pos={x-1,y-1};
HANDLE Out=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(Out, pos);
}
//隐藏光标
void Hide() {
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = false; //隐藏控制台光标
SetConsoleCursorInfo(handle, &CursorInfo);//设置控制台光标状态
}
//生成食物
void shiwu() {
while(foodnum>shi) {
while(1) {
xx=rand()%(B-2)+1;
yy=rand()%(A-2)+1;
if(a[xx][yy]!='+'&&a[xx][yy]!='O'&&a[xx][yy]!='$') break;
}
a[xx][yy]='$';
shi++;
}
}
//移动蛇身
void dest(int qq) {
z1=shetoux;
z2=shetouy;
z3=weibax;
z4=weibay;
switch(qq) {
case 1: shetoux=shetoux-1; break; //判断方向
case 2: shetoux=shetoux+1; break;
case 3: shetouy=shetouy-1; break;
case 4: shetouy=shetouy+1; break;
}
if(shetoux==B-1) shetoux=1; //判断蛇头位置
if(shetouy==A-1) shetouy=1;
if(shetoux==0) shetoux=B-2;
if(shetouy==0) shetouy=A-2;
genzongx[z1][z2]=shetoux;
genzongy[z1][z2]=shetouy;
a[z1][z2]='+';
if(a[shetoux][shetouy]=='+') game=0;
if(a[shetoux][shetouy]=='$') {
shi--; //减食物
score++; //加分
}
else {
a[weibax][weibay]=' '; //尾巴消失
weibax=genzongx[z3][z4];
weibay=genzongy[z3][z4];
}
a[shetoux][shetouy]='O'; //蛇头移动
}
//打印初始地图
void Mapstart() {
HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
CONSOLE_SCREEN_BUFFER_INFO csbi; //定义窗口缓冲区信息结构体
GetConsoleScreenBufferInfo(handle_out, &csbi); //获得窗口缓冲区信息
for(i=0;i<B;i++) {
for(j=0;j<A;j++) {
if(a[i][j]=='+') {
SetConsoleTextAttribute(handle_out, FORE_BLUE);
printf("");
}
else if(a[i][j]=='O') {
SetConsoleTextAttribute(handle_out, FORE_BLUE);
printf("");
}
else if(a[i][j]=='$') {
SetConsoleTextAttribute(handle_out, FORE_YELLOW);
printf("屎");
}
else if(a[i][j]==' ') {
SetConsoleTextAttribute(handle_out, FORE_GREEN);
printf(" ");
}
else {
SetConsoleTextAttribute(handle_out, FORE_GREEN);
printf("█");
}
}
printf("\n");
}
system("pause"); //程序暂停
Position(3,2);
printf(" ");
}
//设置食物数量
void Setfood() {
printf("\n请输入食物数量:");
scanf("%d",&foodnum);
system("cls");
}
//判断方向
void Direction() {
xian1=xian;
switch(des){ //识别方向
case 72: xian=1; break; //上
case 80: xian=2; break; //下
case 75: xian=3; break; //左
case 77: xian=4; break; //右
default: break;
}
if(xian==1&&xian1==2) xian=xian1; //判断方向是否相反
if(xian==2&&xian1==1) xian=xian1;
if(xian==3&&xian1==4) xian=xian1;
if(xian==4&&xian1==3) xian=xian1;
}
//更改地图
void Mapchange() {
HANDLE handle_out = GetStdHandle(STD_OUTPUT_HANDLE); //获得标准输出设备句柄
CONSOLE_SCREEN_BUFFER_INFO csbi; //定义窗口缓冲区信息结构体
GetConsoleScreenBufferInfo(handle_out, &csbi); //获得窗口缓冲区信息
SetConsoleTextAttribute(handle_out, FORE_BLUE); //蓝色
Position(shetouy*2+1,shetoux+1);
printf(""); //打印蛇头
Position(weibay*2+1,weibax+1);
printf(" "); //打印蛇尾
SetConsoleTextAttribute(handle_out, FORE_YELLOW); //黄色
Position(yy*2+1,xx+1);
printf("屎"); //打印食物
Position(1,21);
printf(" 得分:%d \n\n",score);
}
//读取键盘
void Key() {
if(kbhit()!=0) { //键盘获取方向,若没有输入,一直循环
des=getch();
des=getch();
}
}
//主函数
int main() {
Beginning();
Setfood();
Mapstart();
Hide();
while(1) {
Direction();
dest(xian);
shiwu(); //生成食物
Mapchange();
Key();
Sleep(200);
if(game==0) break;
}
printf(" 你死了! \n");
system("pause");
return 0;
}
效果图:
下一篇: 原生python实现knn分类算法