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);//定位光标的函数
}


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 面试让HR都能听懂的MySQL锁机制,欢声笑语中搞懂MySQL锁「建议收藏」

    面试让HR都能听懂的MySQL锁机制,欢声笑语中搞懂MySQL锁「建议收藏」腾讯云数据库负责人林晓斌说过:“我们面试MySQL同事时只考察两点,索引和锁”。言简意赅,MySQL锁的重要性不言而喻。本文通过同事“侨总”的一场面试,带你通俗易懂的掌握MySQL各种锁机制,希望可以帮到你!

    2022年5月1日
    33
  • ArcGIS数据生产与精细化制图之中国年降水量分布图的制作

    ArcGIS数据生产与精细化制图之中国年降水量分布图的制作楼主按:在今年的Esri中国用户大会上,我听了几场关于ArcGIS用于制图方面的讲座,也在体验区与Esri中国的技术老师有一些交流。一直觉得ArcGIS在空间数据管理和分析方面很强大,而在制图方面却表现得不怎么样。我看到在国内很多人制图用的是CorelDraw、AI(可能不仅仅是国内,国外的专业制图也是),诚然这些软件作为专门的图形软件,在很多方面有不可比拟的优势,但是对于地理信息制图来说,图形不

    2022年7月27日
    10
  • 作为程序员,你真的刻意练习了吗

    点击上方☝Java编程技术乐园,轻松关注!及时获取有趣有料的技术文章我真的刻意练习了吗刻意练习真的很重要,作为一名程序员,在读完这本书之后,也听了有关这本书的一些解读。有一些自己的感受。我是大四的下学期开始健身的,不到三个月的时间,能明显感觉到自己有了胸肌和腹肌。而在没有去健身房之前,平时也会去跑跑步,去操场上玩玩双杆,然后做几个引体向上,在宿舍也做几个俯卧撑,但是这些练…

    2022年2月28日
    49
  • log4cpp 使用完全手册「建议收藏」

    log4cpp 使用完全手册「建议收藏」原文链接 点击打开链接一、log4cpp概述     Log4cpp是一个开源的C++类库,它提供了C++程序中使用日志和跟踪调试的功能,它的优点如下:提供应用程序运行上下文,方便跟踪调试;可扩展的、多种方式记录日志,包括命令行、文件、回卷文件、内存、syslog服务器、Win事件日志等;可以动态控制日志记录级别,在效率和功能中进行调整;所有配置可以通过配置文件进行动态调整;多语言支持,包括Ja…

    2022年7月13日
    20
  • 开源企业IM,免费企业即时通讯软件-ENTBOOST云通讯平台Windows(r174)版本号公布

    开源企业IM,免费企业即时通讯软件-ENTBOOST云通讯平台Windows(r174)版本号公布

    2021年11月21日
    71
  • 多进程多线程的区别_多进程和多线程效率

    多进程多线程的区别_多进程和多线程效率前一篇文章介绍了单任务的HTTP服务器,那么如何实现多任务的呢,本篇文章将实现HTTP服务的并发处理,分别从多进程,多线程,协程的方法来实现,代码有点多,引入了3个文件,重复度有点高,读者只看关键部分,就好了,主要是服务端的数据收发阶段。测试方法:将html文件方法和代码同路径下,运行代码,在浏览器中输入IP:端口/XX.html即可看到成功解析html文件(这里不讨论html中的内容,只需明白实现思路即可)如图:****1. 多进程实现HTTP服务器的并发import socketimport

    2022年8月8日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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