我是从C语言的深厚背景开始学习C++的。这是我的第一个程序,正在用作学习经验。一个简单的蛇游戏。一切运行顺利,唯一的问题是,无论我做什么,玩家得分达到4后,总是在墙的左下角(从底部向上1行)内产生食物。进去=游戏结束。

它在Linux服务器上运行。我尝试弄乱border参数,但是我很难弄清楚要更改的内容,因为一切在我看来都不错。 (显然不是。)
我在下面粘贴整个程序。很短我只需要其中一个专家来阅读/运行该程序,然后带我去学校学习一下可能很简单的方法即可。请原谅过多的评论。我用这些来教书(我在pastebin上有一个追随者,这很奇怪)

/*
  Snake Game - Tragedy
  My First Program In C++
  I'm Using This Much As A Learning Experience For Myself
  And Would Like To Help Those Reading The Code For This Goofy Game
  Understand C++ A Bit Better Too
  Therefore I'm Trying To Explain As Much As Possible In Real Time
*/
#include <iostream> //Standard
#include <stdlib.h> //Standard
#include <unistd.h> //For POSIX Access
#include <sys/ioctl.h> //For Display Window, TTY Window (Console Window)
#include <termios.h> //For Line Buffering - See Below
#include <stdio.h> //Old Friend

#define CLRSCR "\e[1;1H\e[2J" //Command To Clear Terminal Screen - Change Accordingly

using namespace std; /*
                    A NameSpace Is Used As Additional Information
                    To Differentiate Between Similar Functions/Variables
                    That Have The Same Name In Different Libraries
                    Using 'namespace' You Can Define The Context
                    In Which Names Are Defined

                    Withoug Using The STD NameSpace, The Computer Will Try
                    To Call cout Or cin As If It Weren't Defined In A NameSpace
                    Trying To Call Something That Doesn't Exist = Error
                    So, Without Using namespace std; When You Write For Example:
                    'cout << value;' You'd Have To Write 'std::cout << value;''

                  */
//Create Boundaries
const int width = 50;
const int height = 25;
const char block = 'o';

void ClearScreen(void)
{
    cout << CLRSCR;
}

//Global Arrays For Data Records
int background[height][width]; // Background
int snake[50][2];              // Max Snake Length
int food[2] = {0,0};             // Snake Food
int score = 0;                 // Score
int snakelen = 3;              // Snake Starting Length
int snakespeedx = 1;           // Horizontal Speed
int snakespeedy = 1;           // Vertical Speed
int lap = 200;                   // Waiting Time Betweeen Frames


//Declaring Global Temporary Variables To Save Memory
int px, py, nx, ny; //Postions
char k;
int h, w;
int x, y;
int movementx = snakespeedx;      //Snake Movement
int movementy = 0;                //Snake Movement

//Check For Keyboard Press
/*
  Reference Link:
    https://www.quora.com/With-which-function-can-I-replace-kbhit-in-C++-because-the-header-conio-h-doesnt-exist-in-linux

  Ubuntu Users:
    sudo apt-get install libncurses5-dev libncursesw5-dev

  Life Saver:
    http://www.flipcode.com/archives/_kbhit_for_Linux.shtml
*/
int bytesWaiting, i;
int _kbhit()
{
    static const int STDIN = 0;
    static bool initialized = false; //The Boolean Data Type Is Used To Declare A Variable Whose Value Will Be Set As True (1) Or False (0)

    if (! initialized)
    {
        //Use Termios To Turn Off Line Buffering
        termios term;
        tcgetattr(STDIN, &term);
        term.c_lflag &= ~ICANON;
        tcsetattr(STDIN, TCSANOW, &term);
        setbuf(stdin, NULL);
        initialized = true;
    }
    ioctl(STDIN, FIONREAD, &bytesWaiting);
    return bytesWaiting;
}

//Initialise background borders Onto Array
void initialise_background(void)
{
    //int i;
    // Insert Top Border
    for(i=0; i<width; i++)
    {
        background[0][i]=1;
    }
    //Insert Left Border
    for(i=0; i<height; i++)
    {
        background[i][0]=1;
    }
    //Insert Right Border
    for(i=0; i<height; i++)
    {
        background[i][width-1]=1;
    }
    //Insert Bottom Border
    for(i=0; i<width; i++)
    {
        background[height-1][i]=1;
    }
}

//Initialise Snake Coordinates
void initialise_snake(void)
{
    snake[0][0]=3; //Coordinates X
    snake[0][1]=3; //Coordinates Y

    snake[1][0]=3+1; //Coordinates X
    snake[1][1]=3; //Coordinates Y

    snake[2][0]=3+2; //Coordinates X
    snake[2][1]=3; //Coordinates Y

    snake[3][0]=3+3; //Coordinates X
    snake[3][1]=3; //Coordinates Y

    snake[4][0]=3+4; //Coordinates X
    snake[4][1]=3; //Coordinates Y
}

//Update Snake
void update_snake_coordination(void)
{
    //int px,py,nx, ny;
    px = snake[0][0];
    py = snake[0][1];
    snake[0][0] = px + movementx;
    snake[0][1] = py + movementy;
    nx = snake[0][0];
    ny = snake[0][1];

    for(i=1; i<snakelen; i++)
    {
        nx = snake[i][0];
        ny = snake[i][1];
        snake[i][0] = px;
        snake[i][1] = py;
        px = nx;
        py = ny;
    }
}

//Install Snake Coordinates Into Background Array = ( 1 To Draw And 0 To Erase)
void draw_snake_in_background(const int rev)
{
    //int x, y;
    for(i = 0; i<snakelen; i++)
    {
        x = snake[i][0];
        y = snake[i][1];
        if((x!=0)&&(y!=0))
        {
            background[y][x] = rev;
        }
    }
}

//Print Array Frame
void print_array_frame(void)
{
    for(h=0; h<height; h++)
    {
        for(w=0; w<width; w++)
        {
            i=background[h][w];
            if(i==1)
            {
                cout << block;
            }
            else if (i == 2)
            {
                cout << "+";
            }
            else
            {
                cout << " ";
            }
        }
        cout << endl;
    }
}

//Update Loop
void mainloop(void)
{
    ClearScreen();
    draw_snake_in_background(1); // Install Snake
    print_array_frame();         // Print Frame
    draw_snake_in_background(0); // Uninstall Snake
}

//Waiting Function
void sleepcp(int milliseconds) // Cross-Platform Sleep Function
{
    clock_t time_end;
    time_end = clock() + milliseconds * CLOCKS_PER_SEC/1000;
    while (clock() < time_end)
    {
        //
    }
}

//Reaction To Keyboard Press
void reaction_on_keyboard(const char k)
{
    if(k=='d'||k=='6')
    {
        //Right Turn
        movementx = snakespeedx;
        movementy = 0;
    }
    else if(k=='a'||k=='4')
    {
        //Left Turn
        movementx = -snakespeedx;
        movementy = 0;
    }
    else if(k=='w'||k=='8')
    {
        //Turn Up
        movementx = 0;
        movementy = -snakespeedy;
    }
    else if(k=='s'||k=='2')
    {
        //Turn Down
        movementx = 0;
        movementy = snakespeedy;
    }
    else if(k=='q'||k=='z'||k=='c')
    {
        cout << "[+] Exit Safely [+]"<<endl;
        exit(0);
    }
}

//Create Snake Food
void cook_food(void)
{
    if (food[0]==0)
    {
        x = rand() % width + 1;
        y = rand() % height + 1;
        food[0] = x;
        food[1] = y;
        background[y][x] = 2;
    }
}

//Check Snake & Food Status
void capture_food(void)
{
    x = food[0];
    y = food[1];

    if ((x==snake[0][0])&&(y==snake[0][1]))
    {
        background[y][x] = 0;
        food[0] = 0;
        score ++;
        snakelen ++;
        cook_food();
    }
}

//Check Snake is Not Touching Boundary
void check_over_lapping(void)
{
    //int px,py;
    px = snake[0][0];
    py = snake[0][1];

    if((px==0)||(px==(width-1))||(py==0)||(py==(height-1)))
    {
        cout << "[+]        Game Over           [+]" << endl;
        exit(0);
    }
}

//Loop
void loop(void)
{
    int frame = 0;
    x = 0;
    y = 0;

    while(x<500)
    {
        sleepcp(lap);
        if(_kbhit())   //If Keyboard Pressed
        {
            cin >> k; //Character
            reaction_on_keyboard(k);
        }
        mainloop();                 //RUn Main Loop FUnction
        update_snake_coordination();//Update Snake Coordinates
        check_over_lapping();       //Check Snake Status
        cook_food();                //Make Sure Food is Available
        capture_food();             //Snake Eaten Food?
        cout << "[ Frame : " << frame << "  | Score  : " << score << " ] "<< endl; //Print Status
        frame ++;
    }
}

//Main Trigger Function
main()
{
    initialise_background(); //Install All Variables
    initialise_snake();      //Install Snake data
    loop();                  //Run Update Loop
}

这是运行游戏时发生的情况:
oooooooooooooooooooooooooooooooooooooooooooooooooo
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                                                o
o                       ooooooo                  o
o                                                o
o                                                o
o                                                o
+<---Places Here Every Time                      o
oooooooooooooooooooooooooooooooooooooooooooooooooo
[ Frame : 169  | Score  : 4 ]

任何帮助或输入,不胜感激!

最佳答案

您的背景数组是高度*宽度。将食物放入数组时,将其放置在rand() % width + 1rand() % height + 1上,它们的范围分别为宽度1和高度1。如果您在宽度x坐标或高度y坐标处生成食物,则将在背景数组的边界之外阅读。发生的情况是,您的程序初始化时使用的种子在x宽度的位置上生成食物,并且由于布局方式与background[y + 1][0]相同的数组位置而导致。

您可能需要按以下方式更改cook_food:

void cook_food(void)
{
    if (food[0]==0)
    {
        x = rand() % (width - 1) + 1;
        y = rand() % (height - 1) + 1;
        food[0] = x;
        food[1] = y;
        background[y][x] = 2;
    }
}

我要指出的是,无论您使用什么进行编译,它实际上都不是C++程序。您正在使用非常C的样式,以C的方式存储数据,并调用C标准库函数。您可能需要阅读isocpp C++ FAQ,其中有一些指向学习C++的人的资源指针。

C++实现可能要使用标准库中的std::uniform_int_distribution类,这样可以更清楚地知道食物X和Y坐标的最小值和最大值。您还将拥有“食物”和“蛇”对象来跟踪它们的X和Y坐标,而不是将这些值存储在直接使用的数组中。

编辑:您一直在询问有关蛇的碰撞检测的评论中的一些问题。我相信,鉴于上述代码,该方法将检测蛇对蛇的碰撞:
bool is_snake_touching_itself() {
    for (std::size_t i = 1; i < snakelen; ++i) {
        if (snake[0][0] == snake[i][0] && snake[0][1] == snake[i][1]) {
            return true;
        }
    }

    return false;
}

07-28 01:26
查看更多