• C语言实现贪吃蛇[内附详细步骤]


    C语言贪吃蛇项目

    今天给分享一下使用C语言写个贪吃蛇小游戏,主要包含以下10部分内容:

    1、windows光标定位与隐藏

    2、欢迎界面

    3、打印围墙

    4、产生食物

    5、初始化蛇身

    6、响应按键

    7、蛇身运动

    8、碰撞检测

    9、结束界面

    10、程序运行

    1. windows光标定位与隐藏

    COORD 是window API中定义的一种结构体,表示一个字符在控制台屏幕上的坐标。定义为:

    typedef struct_COORD{

    SHORT X;  横坐标

    SHORT Y;  纵坐标

    }COORD;

    定位函数gotoxy,gotoDelete

    void gotoprint(int x, int y)

    {

        gotoxy(x, y);

        printf("■");

    }

    // 删除蛇尾

    void gotoDelete(int x, int y)

    {

        gotoxy(x, y);

        printf("  ");

    }

    2. 欢迎界面

    使用gotoxy函数将光标定义到页面相应的位置输出欢迎信息,页面左上角为(0,0)坐标。

    将用户输入的姓名信息保存下来以便后面使用。

    用户输入姓名后清屏,进入游戏界面。

    void welcome()

    {

        gotoxy(10, 5);

        printf("/**********************************************/");

        gotoxy(14, 8);

        printf("WELCOME TO THE GAME OF RETRO SNAKE");

        gotoxy(14, 12);

        printf("wasd控制蛇身上下左右运动,反向移动等同于吃到自己导致游戏结束,除了wasd任意键暂停");

        gotoxy(10, 20);

        printf("/**********************************************/");

        gotoxy(14, 16);

        printf("请输入姓名:");

        scanf("%s",username);

        system("cls");        

    }

    ​​​​​​​3.打印围墙

    贪吃蛇围墙只需要定位到相应位置输出"■"即可,本次游戏的围墙为57*27

    坐标图如下图所示:

     

    void creatgraph()

    {

    int i;

    // 横向围墙 58 / 2 == 29列

    for (i = 0; i < 58; i += 2)

        {

            gotoprint(i, 0);

            gotoprint(i, 26);

        }

        // 竖向围墙  1-25中间有25行 + 头尾两行  27行

        for (i = 1; i < 26; i++)

        {

            gotoprint(0, i);

            gotoprint(56, i);

        }

        

        // 游戏信息

    gotoxy(60,5);

    printf("hello,%s",username);

    gotoxy(60,15);

    printf("您当前的得分为:");

    gotoxy(76,15);

    printf("%d",score);

    }

    打印完后显示一下游戏信息。

    注意:

    汉字宽度是字符宽度的两倍,高度相等。即一个汉字占两个字节,一个英文字母占一个字节。

    因此,"■"输出一次占两个字节,纵向上占一个字节,底部自身携带一些空隙。

    ​​​​​​​4.产生食物

    1、构造食物

    struct Food

    {

        int x;

        int y;

    }food;

    2、定位食物

    保证食物必须在围墙内:

    x坐标范围: [2,54] -- 并且只要偶数部分,不是偶数部分需要转化为接近的偶数

    y坐标范围: [1,25]

    保证食物和蛇身没有重合,如果重合需要再次生成新的位置。

    3、输出食物

    void creatfood()

    {

    // 随机产生一个食物的位置

    int flag = 0;

    while(!flag)

    {

    srand((unsigned int)time(NULL));

    food.y = rand() % 25 + 1; // [1,25]

    food.x = rand() % 53 + 2; // [2,54] -- 只要偶数部分

    if(food.x % 2 != 0)

    {

    food.x = food.x+1; // 不是偶数部分转化为接近的偶数

    }

    // 不能与蛇身重复

    snake *p = head;

    while(p)

    {

    if(p->x == food.x && p->y == food.y)

    {

    // 重复 -- 重新生成坐标

    break;

    }

    p = p->next;

    }

    flag = 1;  

    }

    gotoxy(food.x, food.y);

        printf("吃");

    }

    ​​​​​​​5.初始化蛇身

    蛇身构造

    typedef struct Snakes

    {

        int x;

        int y;

        struct Snakes* next;

    }snake;

    snake* head;    // 声明蛇头指针

    绘制初始化的蛇身

    void initSnake()

    {

    head = (snake*)malloc(sizeof(snake));

        snake* p = (snake*)malloc(sizeof(snake));

        snake* q = (snake*)malloc(sizeof(snake));

        head->x = 16;

        head->y = 15;    

        p->x = 16;

        p->y = 16;

       

        q->x = 16;

        q->y = 17;

        head->next = p;

        p->next = q;

        q->next = NULL;

        

        //绘制初始蛇身

    gotoprint(16,15);

    gotoprint(16,16);

    gotoprint(16,17);    

    }

    ​​​​​​​6.响应按键

    getch()为输入字符函数,但是是阻塞的,如果用户不输入进步向下进行,不满足蛇身自动向前运动的需求,因此替换为_kbhit()进行非阻塞的输入监听,监听到键盘输入后,使用_getch从缓冲区中将输入的字符读出来放入全局变量ch中。

    另外,当程序执行时,循环一次需要进行一次碰撞检测,没有碰撞时,还需要进行蛇身的移动。

    int clickControl()

    {

    while(1)

    {

    // 检测是否碰撞边界

    if(collisionDetect() == 1) return 0;

    // _kbhit监听键盘有输入-非阻塞

    if(_kbhit())

    {

    ch = _getch();  

    }

    // 移动身体

    movingBody();  

    }

    return 1;

    }

    ​​​​​​​7.蛇身运动

    蛇身运动即:消除蛇尾节点,根据按键方向确定好新节点坐标,将新节点添加到蛇头位置即可。

    移动后可以加一些延迟,使用Sleep(xx); xx以ms为单位。

    void movingBody()

    {

    // 坐标修改

    int x = head->x;

    int y = head->y;

    switch(ch)

    {

    case UP:

    y-=1;

    break;

    case DOWN:

    y+=1;

    break;

    case LEFT:

    x-=2;

    break;

    case RIGHT:

    x+=2;

    break;

    default:

    ch = 0;

    break;

    }

    if(ch)

    {

    // 消除尾节点

    snake *p = head;

    while(p->next->next != NULL)

    {

    p = p->next;

    }

    snake *q = p->next;

    gotoDelete(q->x,q->y);

    free(q);

    p->next = NULL;

    // 新坐标结点置为头结点

    snake* newNode = (snake*)malloc(sizeof(snake));

    newNode->x = x;

    newNode->y = y;

    newNode->next = head;

    head = newNode;

    // 绘制蛇头

    gotoprint(x,y);

    // 延迟

    Sleep(500);

    }

    }

    注意:如果用户输入的是除了 wasd以外的按键则暂停游戏。

    ​​​​​​​8.碰撞检测

    碰撞检测主要有三种:

    1. 蛇身和边界
    2. 蛇头和蛇身
    3. 蛇头碰到食物

                    重新生成一个食物

                    在蛇身后面添加一个尾巴,可以不给x,y,因为下次移动的时候会直接将它释放掉。

                    加分

                    在分值位置更新分数

    int collisionDetect()

    {

    // 检测蛇头和边界

    if(head->x == 0 || head->x == 56 || head->y == 0 || head->y == 26)

    {

    Finish();

    return 1;

    }

    // 蛇头和蛇身

    snake *p = head->next;

    while(p != NULL)

    {

    if(head->x == p->x && head->y == p->y)

    {

    // 碰撞-结束

    Finish();

    return 1;

    }

    p = p->next;

    }

    // 碰到食物

    if(head->x == food.x && head->y == food.y)

    {

    creatfood();

    // 添加一个尾巴

    snake* newNode = (snake*)malloc(sizeof(snake));

    newNode->next = NULL;

    snake *p = head;

    while(p->next != NULL)

    {

    p = p->next;

    }

    p->next = newNode;

    score += 10;

    gotoxy(76,15);

    printf("%d",score);

    }

    return 0;

    }

    ​​​​​​​9.结束界面

    清屏

    显示用户名和得分

    void Finish()

    {

    system("cls");

        gotoxy(10, 10);

        printf("/**********************************************/");

        gotoxy(10, 20);

        printf("/**********************************************/");

        gotoxy(15, 14);

        printf("GAME   OVER      o(* ̄▽ ̄*)o");    

        gotoxy(18, 16);

        printf("%s,    你的得分 %d ",username, score);

        gotoxy(15, 18);

        printf("还不错哦,     继续努力O(∩_∩)O");

        gotoxy(0, 27);

        // 释放空间

        snake* p = head, *q;

        while (p != NULL) {

            q = p->next;

            free(p);

            p = q;

        }

        system("pause");

    }

    ​​​​​​​10.运行程序

    int main()

    {

    welcome();

    creatgraph();

    creatfood();

    initSnake();

    clickControl();

    return 0;

    }

  • 相关阅读:
    华为机试 - 任务最优调度
    Python入门:A+B问题
    Springboot集成Swagger3详细操作步骤
    vue父子组件传值与兄弟传值的注意点
    vue学习之事件绑定
    交换机基础(一)
    oracle21c报错 【ORA-65096: 公用用户名或角色名无效】
    数据结构第一篇【探究List和ArrayList之间的奥秘 】
    win10系统下使用openvino部署yolov5模型
    NewStarCTF2023 Reverse Week3 EzDLL WP
  • 原文地址:https://blog.csdn.net/amyliyanice/article/details/126820628