在本博客中,我们将学习如何使用 C++创建贪吃蛇游戏。贪吃蛇游戏是一款经典且流行的游戏,玩家在其中控制一条在屏幕上移动的蛇,试图吃食物并避免与墙壁或自己的尾巴相撞。我们将逐步完成该过程,并解释代码中使用的必要函数和参数。

准备工作

在我们开始编码之前,请确保您对编程语言有基本的了解 C++以及变量、循环和函数的概念。

此外,请确保您的系统上安装了 C++编译器。您可以选择任何流行的编译器,例如 GCC 或 Microsoft Visual C++。通过安装编译器和合适的集成开发环境 (IDE) (如 Code::Blocks 或 Visual Studio)来设置开发环境。

设置贪吃蛇游戏

让我们从设置贪吃蛇游戏的基本结构开始。我们将定义必要的变量并初始化游戏的初始状态。

#include <iostream>
    #include <conio.h>
    #include <stdio.h>
    #include <Windows.h>

    bool gameOver;

    const int width = 20;
    const int height = 20;

    int x, y, fruitX, fruitY, score;

    int tailX[100], tailY[100];
    int nTail;

    std::string fruit = "*";

    enum eDirections
    {
        STOP = 0,
        LEFT,
        RIGHT,
        UP,
        DOWN
    };

    eDirections dir;

    void Setup()
    {
        gameOver = false;
        dir = STOP;
        x = width / 2;
        y = height / 2;
        fruitX = rand() % width + 1;
        fruitY = rand() % height + 1;
        score = 0;
    }

在上面的代码中,我们声明了游戏的必要变量。以下是每个变量的简要说明:

  • gameOver :跟踪游戏是否结束。
  • widthheight :定义游戏屏幕的尺寸。
  • xy :表示蛇的当前位置。
  • fruitXfruitY :代表蛇需要吃的水果的位置。
  • score :存储玩家的分数。
  • tailXtailY :用于存储蛇尾巴位置的数组。
  • nTail :跟踪蛇尾巴的长度。
  • fruit :表示用于在屏幕上显示水果的字符。
  • eDirections :表示蛇可以移动的可能方向的枚举。

Setup() 函数用它们的初始值初始化这些变量,将蛇定位在屏幕的中心并随机放置水果。

为贪吃蛇游戏绘制边界

接下来,我们将实现 Draw() 函数,该函数将负责渲染游戏屏幕并显示蛇、水果和分数。

void Draw()
    {
        system("cls");
        for (int i = 0; i < width + 2; i++)
        {
            std::cout << "#";
        }
        std::cout << std::endl;
        for (int i = 1; i <= height; i++)
        {
            for (int j = 1; j <= width + 1; j++)
            {
                if (j == 1 || j == width + 1)
                    std::cout << "#";
                if (i == y && j == x)
                {
                    std::cout << "O";
                }
                else if (j == fruitX && i == fruitY)
                {
                    std::cout << fruit;
                }
                else
                {
                    bool print = false;
                    for (int k = 0; k < nTail; k++)
                    {
                        if (tailX[k] == j && tailY[k] == i)
                        {
                            std::cout << "o";
                            print = true;
                        }
                    }
                    if (!print)
                        std::cout << " ";
                }
            }
            std::cout << std::endl;
        }
        for (int i = 0; i < width + 2; i++)
        {
            std::cout << "#";
        }
        std::cout << std::endl;
        std::cout << "Score: " << score << std::endl;
    }

Draw() 函数使用循环和条件语句的组合在控制台屏幕上绘制游戏的每个元素。以下是代码的每个部分的作用:

  • system("cls") :清除控制台屏幕。
  • 第一个循环打印游戏屏幕的顶部边框,由“#”字符组成。
  • 第二个循环遍历游戏屏幕的每一行。
  • 嵌套循环遍历游戏屏幕的每一列。
  • 如果当前位置与蛇头 (x, y) 匹配,则打印“O”来表示蛇头。
  • 如果当前位置与水果的位置匹配(水果 X,水果 Y),则打印水果字符。
  • 如果当前位置与蛇尾巴的任何部分匹配,它将打印“o”来表示蛇的尾巴。
  • 如果以上条件都不满足,它将打印一个空白区域。
  • 每行之后,将打印一个新行。
  • 最后,显示底部边框和玩家的分数。

处理贪吃蛇游戏中的用户输入

现在,让我们实现 Input() 函数,它将负责处理用户输入并相应地更新蛇的方向。

void Input()
    {
        if (_kbhit())
        {
            switch (_getch())
            {
            case 'a':
                dir = LEFT;
                break;
            case 'd':
                dir = RIGHT;
                break;
            case 'w':
                dir = UP;
                break;
            case 's':
                dir = DOWN;
                break;
            case 'x':
                gameOver = true;
                break;
            }
        }
    }

Input() 函数使用 conio.h 库中的 _kbhit()_getch() 函数来检测键盘输入。以下是代码的每个部分的作用:

  • _kbhit() :检查当前是否按下了某个键。
  • _getch() :检索按下的键的字符。

switch 语句检查按下的键的值并相应地更新 dir 变量。可能的方向是:

  • “a”:左
  • “d”:右
  • “w”:向上
  • 's':向下
  • “x”:退出游戏

更新贪吃蛇游戏逻辑

Logic() 函数负责更新游戏的逻辑,包括移动蛇、检测碰撞和更新分数。

void Logic()
    {
        int prevX = tailX[0];
        int prevY = tailY[0];
        int prev2X, prev2Y;
        tailX[0] = x;
        tailY[0] = y;
        for (int i = 1; i < nTail; i++)
        {
            prev2X = tailX[i];
            prev2Y = tailY[i];
            tailX[i] = prevX;
            tailY[i] = prevY;
            prevX = prev2X;
            prevY = prev2Y;
        }
        switch (dir)
        {
        case LEFT:
            x--;
            break;
        case RIGHT:
            x++;
            break;
        case UP:
            y--;
            break;
        case DOWN:
            y++;
            break;
        }
        if ((x > width || x < 0) || (y > height || y < 0))
        {
            std::cout << "\t\tGame Over" << std::endl;
            std::cout << "\t    You Hit the wall!";
            gameOver = true;
        }
        for (int i = 0; i < nTail; i++)
        {
            if (tailX[i] == x && tailY[i] == y)
            {
                std::cout << "\t\tGame Over" << std::endl;
                std::cout << "\t    You Hit the Tail!";
                gameOver = true;
            }
        }
        if (x == fruitX && y == fruitY)
        {
            score += 10;
            nTail++;
            fruitX = rand() % width + 1;
            fruitY = rand() % height + 1;
        }
    }

Logic() 函数中,我们根据当前方向更新蛇的位置。以下是代码的每个部分的作用:

  • 我们将蛇头的先前位置存储在 prevXprevY 中。
  • 我们用蛇头的新位置(2 和 3)更新尾数组的第一个元素( tailX[0]tailY[0] )。
  • 我们通过向前移动先前的位置来更新尾巴的其余部分。
  • 我们根据当前方向更新蛇的头部位置。
  • 我们检查蛇是否撞到墙上了。如果有,我们将 gameOver 设置为 true 并显示游戏结束消息。
  • 我们检查蛇是否与自己的尾巴相撞。如果有,我们将 gameOver 设置为 true 并显示游戏结束消息。
  • 我们检查蛇是否吃了水果。如果有,我们增加分数,增加尾巴的长度,并为水果生成一个新的随机位置。

将一切整合在一起

现在我们已经实现了所有必要的函数,让我们编写 main() 函数将所有内容放在一起并运行游戏。

int main()
    {
        Setup();
        while (!gameOver)
        {
            Draw();
            Input();
            Logic();
            Sleep(150);
        }
        std::cout << fruitX << " " << fruitY;
        return 0;
    }

main() 函数中,我们调用 Setup() 函数来初始化游戏。然后,我们进入一个游戏循环,该循环一直持续到 gameOver 为真。在循环中,我们调用 Draw()Input()Logic() 函数来更新和渲染游戏。我们还使用 Sleep() 函数在每帧之间添加一个小延迟来控制游戏速度。

总结

祝贺!您已经使用控制台在 C++中成功创建了贪吃蛇游戏。你学习了如何处理用户输入、更新游戏逻辑和显示游戏屏幕。随意尝试并为游戏添加新功能,例如音效或其他关卡。

我希望您喜欢本教程并发现它内容丰富。如果您有任何问题或建议,请随时在下面发表评论。祝您编码愉快!

参考