C语言实现贪吃蛇小游戏

贪吃蛇1.0

规则
  1. 初始蛇身长为2,向右移动,每吃到一次食物身长加1,积分加10
  2. 键盘wasd控制移动方向
  3. 碰到墙壁、障碍物或者吃到自身时死亡,游戏结束

 

代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <windows.h>
#include <conio.h>

#define WIDE 60 //地图宽
#define HIGH 20 //地图高

typedef struct _body //蛇身一块的坐标信息
{
    int x;
    int y;
} BODY;

typedef struct snake //蛇的信息
{
    int size;
    BODY list[WIDE * HIGH]; //蛇身坐标
    BODY food;              //当前食物的坐标
    COORD coord;            //光标位置
    BODY tail;              //原本蛇尾的坐标
    int dx;                 //蛇的移动方向,默认向右
    int dy;
} SNAKE;

void hide_cur();                    //终端窗口隐藏光标
void init_snake(SNAKE *snake);      //初始化蛇的信息
void init_food(SNAKE *snake);       //随机生成食物位置
void init_wall();                   //初始化墙
void show_ui(SNAKE *snake);         //显示蛇、食物
void start_game(SNAKE *snake);      //开始游戏
void move_snake(SNAKE *snake);      //根据按键改变蛇坐标信息
void snake_direction(SNAKE *snake); //根据按键改变蛇的移动方向
void eat_food(SNAKE *snake);        //蛇是否碰到食物
int eat_self(SNAKE *snake);         //判断蛇是否吃到自己,吃到返回 1,否则 0
void game_over(SNAKE *snake);       //游戏结束

int main()
{
    system("cls"); //清屏

    hide_cur(); //终端窗口隐藏光标

    SNAKE *snake = (SNAKE *)malloc(sizeof(SNAKE));
    init_snake(snake); //初始化蛇的信息

    start_game(snake); //开始游戏
    return 0;
}

void hide_cur()
{
    CONSOLE_CURSOR_INFO cci;
    cci.dwSize = sizeof(cci);
    cci.bVisible = FALSE;
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
}

void init_ui()
{
    for (int i = 0; i < HIGH; i++)
    {
        for (int j = 0; j < WIDE; j++)
        {
            printf("#");
        }
        printf("\n");
    }
}

void init_snake(SNAKE *snake)
{
    //初始化蛇首坐标
    snake->list[0].x = WIDE / 2;
    snake->list[0].y = HIGH / 2;
    //初始化蛇尾坐标
    snake->list[1].x = WIDE / 2 - 1;
    snake->list[1].y = HIGH / 2;
    //初始化蛇身长度
    snake->size = 2;
    //随机生成初始食物位置
    init_food(snake);
    //默认移动方向向右
    snake->dx = 1;
    snake->dy = 0;
}

void init_food(SNAKE *snake)
{
    srand(time(NULL));

    snake->food.x = rand() % (WIDE - 3) + 1; //-2、+1都是防止出界
    snake->food.y = rand() % (HIGH - 3) + 1; //-2、+1都是防止出界
}

void init_wall()
{
    //显示墙
    for (int i = 0; i < HIGH; i++)
    {
        for (int j = 1; j < WIDE + 1; j++)
        {
            if (i == 0 || i == HIGH - 1 || j == 1 || j == WIDE)
                printf("#");
            else
                printf(" ");
        }
        printf("\n");
    }
}

void show_ui(SNAKE *snake)
{
    //显示蛇
    for (int i = 0; i < snake->size; i++)
    {
        if (!snake->list[i].x && !snake->list[i].y)
            return;

        //设置光标位置
        snake->coord.X = snake->list[i].x;
        snake->coord.Y = snake->list[i].y + 1; //加 1是避免和终端窗口中的命令语句重叠
        SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);

        if (i == 0) //蛇头
        {
            printf("@");
        }
        else //蛇身
        {
            printf("*");
        }
    }

    //清除屏幕上原本蛇尾部分
    snake->coord.X = snake->tail.x;
    snake->coord.Y = snake->tail.y + 1;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);
    printf(" ");

    //显示食物
    snake->coord.X = snake->food.x;
    snake->coord.Y = snake->food.y + 1;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), snake->coord);
    printf("+");
}

void start_game(SNAKE *snake)
{
    init_wall(); //初始化墙

    while (snake->list[0].x < WIDE - 1 && snake->list[0].x > 0 && snake->list[0].y < HIGH - 2 && snake->list[0].y > -1) //没撞墙时
    {
        snake_direction(snake); //控制蛇的方向

        move_snake(snake); //更新蛇的坐标

        show_ui(snake); //显示蛇、食物

        eat_food(snake); //蛇是否碰到食物

        if (eat_self(snake)) //判断蛇是否吃到自己
            break;

        Sleep(200); //延时0.2s
    }

    game_over(snake);
}

void snake_direction(SNAKE *snake)
{
    char key = 0;
    while (_kbhit())    //按下按键进入循环
        key = _getch(); //获取按键值
    switch (key)
    {
    case 'w':
        snake->dx = 0;
        snake->dy = -1;
        break;

    case 's':
        snake->dx = 0;
        snake->dy = 1;
        break;
    case 'a':
        snake->dx = -1;
        snake->dy = 0;
        break;
    case 'd':
        snake->dx = 1;
        snake->dy = 0;
        break;
    default:
        break;
    }
}

void move_snake(SNAKE *snake)
{
    //记录原本蛇尾位置
    snake->tail.x = snake->list[snake->size - 1].x;
    snake->tail.y = snake->list[snake->size - 1].y;

    //蛇身位置改变
    for (int i = snake->size - 1; i > 0; i--)
        snake->list[i] = snake->list[i - 1];

    //蛇首位置改变
    snake->list[0].x += snake->dx;
    snake->list[0].y += snake->dy;
}

void game_over(SNAKE *snake)
{
    system("chcp 65001"); //防止终端汉字乱码
    system("cls");        //清屏,美观

    //居中打印结果
    COORD coord;
    coord.X = WIDE / 2 - 10;
    coord.Y = HIGH / 2;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
    printf("游戏结束,得分:%d\n", 10 * (snake->size - 2));

    //美观考虑,移动光标
    coord.X = 0;
    coord.Y = HIGH;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);

    Sleep(2000); //延时2s
    exit(0);
}

int eat_self(SNAKE *snake)
{
    for (int i = 1; i < snake->size; i++)
        if (snake->list[0].x == snake->list[i].x && snake->list[0].y == snake->list[i].y)
            return 1;

    return 0;
}

void eat_food(SNAKE *snake)
{
    if (snake->list[0].x == snake->food.x && snake->list[0].y == snake->food.y)
    {
        //重新生成初始食物位置
        init_food(snake);

        //蛇身长度加 1
        snake->size++;
    }
}

 

运行方法
  1. 打开命令行窗口,输入 gcc -o greedy_snake.c greedy 进行编译

  2. 输入 ./greedy_snake 开始运行

 

效果演示
image-20210827092930036

 

待实现功能

关卡设置,积分达到一定值进入下一关

加入障碍物、巡逻者等

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值