C++ 实现贪吃蛇游戏

724 阅读4分钟

基于C++开发的贪吃蛇游戏,运行后任意键开始游戏,W:贪吃蛇上移,S:贪吃蛇下移,A:贪吃蛇左移,D:贪吃蛇右移。

// 编译环境:Visual Studio 2022
// 编程语言:C++
// 程序名称:贪吃蛇

#include <stdio.h>    // 用到数据流的输入输出
#include <conio.h>    // 用到函数_getch()
#include <time.h>    // 用到函数time()
#include <Windows.h>  // 获取光标的API

#define WIDTH 50    // 地图的宽
#define HEIGHT 25    // 地图的高
#define MAXLENGTH 50  // 蛇的最大长度

char direction = 'a';  // 蛇的初始方向
int isFood = 0;      // 0代表蛇没吃到食物(1表示吃到食物)

// 食物类型
struct Food
{
    int x;  // 食物的横坐标x
    int y;  // 食物的纵坐标y
}food;    // 定义食物类型变量food

// 蛇类型
struct Sanke
{
    int x[MAXLENGTH];  // 蛇的横坐标x
    int y[MAXLENGTH];  // 蛇的纵坐标y
    int length;      // 蛇当前长度
    int speed;      // 蛇的速度
}snake;          // 定义蛇类型变量snake

// 光标位置
void cursorxy(int x, int y)
{
    /* 调用win32 API设置控制台光标的位置 */
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);

    COORD coord;  // 定义光标类型变量
    coord.X = x;  // 将x赋值给结构体变量数据X
    coord.Y = y;  // 将y赋值给结构体变量数据Y

    /* 将光标位置同步到控制台 */
    SetConsoleCursorPosition(handle, coord);
}

// 显示地图
void showMap()
{
    for (int i = 0; i < WIDTH; i += 2)
    {
        /* 绘制地图的第一行 */
        cursorxy(i, 0);
        printf("■");

        /* 绘制地图的第 HEIGHT 行 */
        cursorxy(i, HEIGHT - 1);
        printf("■");
    }

    for (int i = 1; i < HEIGHT - 1; i++)
    {
        /* 绘制地图的第一列 */
        cursorxy(0, i);
        printf("■");

        /* 绘制地图的第 WIDTH 列 */
        cursorxy(WIDTH - 2, i);
        printf("■");
    }
}

// 开始页面
void startPage()
{
    /* 显示开始界面信息 */
    cursorxy(16, 7);
    printf("欢迎来到贪吃蛇游戏");
    cursorxy(16, 11);
    printf("按任意键继续……");

    char str = _getch();  // 暂停
    system("cls");      // 清屏
    showMap();        // 重绘地图
}

// 失败页面
void failedPage()
{
    /* 显示失败页面信息 */
    cursorxy(16, 7);
    printf("游戏失败!");
    cursorxy(16, 11);
    printf("得分:%d", snake.length - 3);
}

// 显示食物和蛇
void showSnakeFood()
{
    /* 绘制蛇身 */
    snake.length = 3;  // 初始化蛇的长度

    snake.x[0] = 20;  // 初始化蛇头位置
    snake.y[0] = 11;

    /* 绘制蛇头 */
    cursorxy(snake.x[0], snake.y[0]);
    printf("●");

    /* 绘制蛇身 */
    for (int i = 0; i < snake.length; i++)
    {
        snake.x[i + 1] = snake.x[i] + 2;
        snake.y[i + 1] = snake.y[i];
        cursorxy(snake.x[i], snake.y[i]);
        printf("●");
    }

    /* 绘制食物 */
    food.x = 2 + (rand() % 23) * 2;  // 初始化食物位置
    food.y = 1 + rand() % 23;
    cursorxy(food.x, food.y);
    printf("★");

    /* 显示分数 */
    cursorxy(52, 12);
    printf("分数:%d", snake.length - 3);
}

// 生成新食物
void newFood()
{
    /* 用蛇头的位置判断蛇是否吃到食物 */
    if (snake.x[0] == food.x && snake.y[0] == food.y)
    {
        /* 找到食物合适的位置后退出循环 */
        while (true)
        {
            /* 为新食物赋值 */
            food.x = 2 + (rand() % 23) * 2;
            food.y = 1 + rand() % 23;

            int temp = 1;  // 1表示食物与蛇位置不相等(0表示相等)

            /* 判断新食物是否出现在蛇身上 */
            for (int i = 0; i < snake.length; i++)
            {
                /* 判断蛇身与食物的坐标是否相等 */
                if (snake.x[i] == food.x && snake.y[i] == food.y)
                {
                    temp = 0;  // 食物与蛇位置相等
                    break;    // 退出for循环
                }
            }

            if (temp)  // 判断食物与蛇位置是否相等
            {
                /* 显示食物 */
                cursorxy(food.x, food.y);
                printf("★");
                snake.length++;  // 蛇的长度加1
                isFood = 1;    // 蛇吃到食物

                /* 显示分数 */
                cursorxy(52, 12);
                printf("分数:%d", snake.length - 3);
                break;  // 退出while循环
            }
        }
    }
}

// 判断蛇是否越界(超出地图)和蛇头在蛇身上
int lifeSnake()
{
    /* 蛇头移动到地图外 */
    if (snake.x[0]<2 || snake.x[0]>WIDTH - 2 || snake.y[0]<1 || snake.y[0]>HEIGHT - 1)
    {
        return 0;  // 游戏失败(false)
    }

    /* 蛇头在蛇身上 */
    for (int i = 1; i < snake.length; i++)
    {
        /* 用蛇头与蛇身比较 */
        if (snake.x[0] == snake.x[i] && snake.y[0] == snake.y[i])
        {
            return 0;  // 游戏失败(false)
        }
    }

    return 1;  // 返回真(true)
}

// 控制蛇的方向
void snakeDirection()
{
    if (!isFood) // 如果蛇没有吃到食物就继续移动并清除蛇尾
    {
        /* 光标移动到蛇尾的位置 */
        cursorxy(snake.x[snake.length - 1], snake.y[snake.length - 1]);
        printf("  "); // 清除蛇尾
    }

    /* 更新蛇身位置 */
    for (int i = snake.length - 1; i > 0; i--)
    {
        snake.x[i] = snake.x[i - 1];
        snake.y[i] = snake.y[i - 1];
    }

    if (_kbhit()) // 检测到键盘信息
    {
        direction = _getch(); // 获取玩家输入
    }

    /* 键盘控制蛇移动 */
    switch (direction)
    {
    case 'w':  // 蛇头向上移动
        snake.y[0]--;
        break;
    case 's':  // 蛇头向下移动
        snake.y[0]++;
        break;
    case 'a':  // 蛇头向左移动
        snake.x[0] -= 2;
        break;
    case 'd':  // 蛇头向右移动
        snake.x[0] += 2;
        break;
    default:
        break;
    }

    /* 把光标移动到更新后的位置 */
    cursorxy(snake.x[0], snake.y[0]);
    printf("●");    // 显示更新位置后的蛇头
    isFood = 0;      // 更新蛇与食物的状态
    cursorxy(52, 12);  // 把光标移动到分数的位置
}

void main()  // 主函数
{
    srand((unsigned int)time(NULL)); // 初始化随机数
    snake.speed = 400;    // 初始化蛇的速度
    system("color B");    // 设置字体颜色
    showMap();        // 显示地图
    startPage();      // 显示欢迎信息
    showSnakeFood();    // 显示食物和蛇

    while (lifeSnake())    // 循环游戏直到游戏失败
    {
        snakeDirection();  // 控制蛇的方向
        newFood();      // 产生新食物
        Sleep(snake.speed);  // 蛇的速度(400ms移动一次)
    }

    system("cls");  // 清屏
    showMap();    // 显示地图
    failedPage();  // 显示失败信息
    char str = _getch(); // 程序暂停
}

Snipaste_2024-07-18_16-31-23.png

Snipaste_2024-07-18_16-32-38.png