Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/157.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我的基于文本的游戏显示一帧后 我正在研究蛇的经典游戏,蛇在屏幕上到处吃东西,在C++中长时间。我在Youtube上看到了一个例子,但我决定让它更加面向对象,并且我正在使用ncurses(Linux中)使它更加精致_C++_Ncurses - Fatal编程技术网

我的基于文本的游戏显示一帧后 我正在研究蛇的经典游戏,蛇在屏幕上到处吃东西,在C++中长时间。我在Youtube上看到了一个例子,但我决定让它更加面向对象,并且我正在使用ncurses(Linux中)使它更加精致

我的基于文本的游戏显示一帧后 我正在研究蛇的经典游戏,蛇在屏幕上到处吃东西,在C++中长时间。我在Youtube上看到了一个例子,但我决定让它更加面向对象,并且我正在使用ncurses(Linux中)使它更加精致,c++,ncurses,C++,Ncurses,我一直在一个时间点编程,在这一点上,还没有设置食物。它只是一条蛇,当按下箭头键时开始移动,一旦碰到墙就会崩溃。让我无法继续下去的是,游戏似乎在蛇的实际位置后面显示了一个画面。当它移动时,我按下箭头键来改变方向,它在转向之前在同一方向上再移动一次。(我将帧速率调低到每秒一帧,以使这一点变得明显。)此外,如果我让它直接进入墙,它会从墙移动到第二个位置,然后触发一场游戏并退出。然而,如果我在第二个位置推动一个垂直方向,它会靠着墙向上移动,然后开始沿着墙移动。q(退出)按钮没有这种犹豫,一旦usleep

我一直在一个时间点编程,在这一点上,还没有设置食物。它只是一条蛇,当按下箭头键时开始移动,一旦碰到墙就会崩溃。让我无法继续下去的是,游戏似乎在蛇的实际位置后面显示了一个画面。当它移动时,我按下箭头键来改变方向,它在转向之前在同一方向上再移动一次。(我将帧速率调低到每秒一帧,以使这一点变得明显。)此外,如果我让它直接进入墙,它会从墙移动到第二个位置,然后触发一场游戏并退出。然而,如果我在第二个位置推动一个垂直方向,它会靠着墙向上移动,然后开始沿着墙移动。q(退出)按钮没有这种犹豫,一旦usleep功能完成,游戏就会退出。看起来输入函数和逻辑函数都像预期的那样工作,但是draw函数在某种程度上是滞后的,尽管它紧跟在其他两个函数之后

下面是代码,我将把我使用的命令放在最上面,以防任何使用Linux或类似环境的人想自己尝试。我这样做是为了在屏幕底部打印蛇的坐标,但它们与蛇的绘制位置相匹配。(例如,如果向左走,你可以看到x变为2,然后游戏结束,尽管它的程序很清楚,一旦蛇变为0,就可以杀死它,你可以通过转动它使它沿着第1列移动。)我花了两天的时间试图解决这个问题,即使使用gdb,我也一直在寻找其他我想要改变的东西,但我似乎无法理解这一点。请把我从这种疯狂中解救出来

g++-g snakes.cpp-lncurses-o snakes

// draw is one frame behind

#include <iostream>
#include <unistd.h>
#include <ncurses.h>

#define WIDTH 30
#define HEIGHT 30
#define MS_PER_FRAME 750
#define START_LENGTH 1

using namespace std;

bool gameOver;
enum eDirection { STOP, LEFT, RIGHT, UP, DOWN };

class Snake
{
public:
    Snake(int i, int j);
    bool isHead(int i, int j);
    bool isTail(int i, int j);
    void moveSnake();
    bool collisionOccurred();
    void drawSnake();
    void setDirection(eDirection newDir);
    
private:
    short int x, y, length;
    short int tailx[20], taily[20];
    eDirection dir;
} snake (WIDTH / 2, HEIGHT / 2);

Snake::Snake(int i, int j)
{
    x = i;
    y = j;
    length = START_LENGTH;
    dir = STOP;
}

bool Snake::isHead(int i, int j)
{
    if (i == x && j == y)
        return true;
    else
        return false;
}

bool Snake::isTail(int i, int j)
{
    for (short int r = 0; r < length; r++)
        if (i == tailx[r] && j == taily[r])
            return true;
    return false;
}

void Snake::moveSnake()
{
    for (short int r = length; r >= 1; r--)
    {
        tailx[r] = tailx[r-1];
        taily[r] = taily[r-1];
    }
    tailx[0] = x;
    taily[0] = y;
    switch (dir)
    {
        case LEFT:
            x--;
            break;
        case RIGHT:
            x++;
            break;
        case UP:
            y--;
            break;
        case DOWN:
            y++;
            break;
    }
}

bool Snake::collisionOccurred()
{
    if (x == 0 || x == WIDTH+1)
        return true;
    if (y == 0 || y == HEIGHT+1)
        return true;
    for (int l = 0; l < length; l++)
        if (dir != STOP && (x == tailx[l] && y == taily[l]))
            return true;
    return false;
}

void Snake::drawSnake()
{
    mvaddch(y, x, 'O' | COLOR_PAIR(2));
    for (int l = 0; l < length; l++)
        mvaddch(taily[l], tailx[l], 'o' | COLOR_PAIR(2));
    mvprintw(HEIGHT+2, 0, "Snake: %d, %d\n", x, y);
}

void Snake::setDirection(eDirection newDir)
{
    dir = newDir;
}

void drawBorder()
{
    for (int i = 0; i <= WIDTH+1; i++)
        mvaddch(0, i, '#' | COLOR_PAIR(1));
    for (int i = 0; i <= WIDTH+1; i++)
        mvaddch(HEIGHT+1, i, '#' | COLOR_PAIR(1));
    for (int i = 0; i <= WIDTH+1; i++)
        mvaddch(i, 0, '#' | COLOR_PAIR(1));
    for (int i = 0; i <= WIDTH+1; i++)
        mvaddch(i, WIDTH+1, '#' | COLOR_PAIR(1));
}

void init()
{
    gameOver = false;
    initscr();
    noecho();
    keypad(stdscr, TRUE);
    nodelay(stdscr, TRUE);
    curs_set(0);
    start_color();
    init_pair(1, COLOR_YELLOW, COLOR_BLUE); // border
    init_pair(2, COLOR_GREEN, COLOR_BLACK); // snake
    init_pair(3, COLOR_RED, COLOR_BLACK); // fruit
    drawBorder();
}

void deinit()
{
    endwin();
}

void draw()
{
    for (int j = 1; j <= HEIGHT; j++)
    {
        move(j, 0);
        for (int i = 1; i <= WIDTH; i++)
        {
            mvaddch(j, i, ' ');
        }
    }
    snake.drawSnake();
    refresh;
}

void input()
{
    switch (getch())
    {
        case KEY_UP:
            snake.setDirection(UP);
            break;
        case KEY_DOWN:
            snake.setDirection(DOWN);
            break;
        case KEY_LEFT:
            snake.setDirection(LEFT);
            break;
        case KEY_RIGHT:
            snake.setDirection(RIGHT);
            break;
        case 'q':
            gameOver = true;
            break;
    }
}

void logic()
{
    if (!gameOver)
        snake.moveSnake();
    if (snake.collisionOccurred())
        gameOver = true;
}

int main()
{
    init();
    draw();
    while (!gameOver)
    {
        usleep(MS_PER_FRAME * 1000);
        input();
        logic();
        draw();
    }
    deinit();
    return 0;
}
//绘图落后一帧
#包括
#包括
#包括
#定义宽度30
#定义高度30
#每帧750定义MS_
#定义起始长度1
使用名称空间std;
布尔·加莫弗;
枚举eDirection{停止、左、右、上、下};
蛇类
{
公众:
Snake(inti,intj);
bool-ishad(inti,intj);
bool isTail(int i,int j);
void moveSnake();
布尔碰撞发生();
void drawSnake();
void setDirection(edidirection newDir);
私人:
短整数x,y,长度;
短int tailx[20],taily[20];
编辑主任;
}蛇(宽/2,高/2);
Snake::Snake(inti,intj)
{
x=i;
y=j;
长度=起始长度;
dir=停止;
}
布尔蛇::isHead(inti,intj)
{
如果(i==x&&j==y)
返回true;
其他的
返回false;
}
bool Snake::isTail(inti,intj)
{
for(短int r=0;r=1;r--)
{
tailx[r]=tailx[r-1];
taily[r]=taily[r-1];
}
tailx[0]=x;
taily[0]=y;
交换机(dir)
{
案例左:
x--;
打破
案例权利:
x++;
打破
个案:
y--;
打破
按大小写:
y++;
打破
}
}
bool Snake::碰撞发生()
{
如果(x==0 | | x==WIDTH+1)
返回true;
如果(y==0 | | y==高度+1)
返回true;
对于(int l=0;l对于(inti=0;i噢,天哪,我终于想出了这个办法,我很惊讶编译器没有抓住它。关于getch进行刷新的响应引导我朝着正确的方向前进,尽管这本身并不是问题

简单明了,我忘记了绘图例程中刷新后的括号,所以当时它没有刷新。我不知道getch会进行刷新,尽管这并不重要,因为在几毫秒后重新计算蛇的位置后会再次进行刷新,如果是这样的话。但是,去掉括号意味着它没有刷新然后,只有格奇在蛇被移动之前,解释了为什么它看起来像是背后的一个框架


现在我只想知道为什么编译器没有在没有括号的情况下出错,以及刷新会做什么(如果有的话)。

尝试将其解析为一个最小的可复制示例,您可能会找到您的答案。如果没有,我们将在这里。
getch
与箭头键一起使用时可能会返回两个键码。这似乎不是问题我修改了它,所以getch将其返回值转换为int,然后基于该int调用switch语句。在这两者之间,它将在按下的键的蛇坐标下打印。它保持为-11(我假设错误)除非我按下一个键。箭头是258到261,只在一帧上显示,但在我按下它后,它们仍然会在两帧上显示。通常是在下一帧上显示-11,然后是相应的代码。这支持了我的想法,即在读取输入之前绘制屏幕,即使它不是这样编码的。
getch进行刷新。如果您使用的是snake的原始版本,则情况会有所不同,因为BSD curses没有在getch中进行刷新。