Ncurses отображает мусор при использовании printf в цикле while - PullRequest
0 голосов
/ 07 января 2020

Я создаю игру Snake на Linux. Я использовал iostream до того момента, когда понял, что мне нужна функция getch(), включенная в ncruses.h. У меня был метод рисования, который печатал все элементы доски на консоль при использовании std::cout, и каждый символ отображался правильно. У меня была вся доска. Но когда я переключился на ncurses и переписал все std::cout на printf (), тогда программа начинает писать только части доски. Все это делается в то время как цикл, и каждая доска цикла перерисовывается.

Я новичок ie, поэтому, пожалуйста, будьте добры.

Вот мой главный. cpp

#include <iostream>
#include <chrono>
#include <thread>
#include <ncurses.h>
#include <stdio.h>

#include "board.h"
#include "consoledraw.h"
#include "snake.h"
#include "fruit.h"

void sleepThread()
{
static constexpr int SLEEP_MS = 1000;

std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_MS));
}

int main()
{
std::cout << "\e[8;30;140t"; // set console window size

Board _board;
Snake _snake;
consoledraw draw;
Fruit _fruit;

_board.setBoardSize(64, 36); // cca 16:9
_board.setDefaultItemType();
_board.makeSnake(_snake);
_board.setSnakeOnBoard(_snake);
_board.makeFruit(_fruit);
_board.setFruitOnBoard(_fruit);

int score = 0;

initscr();
setlocale(LC_ALL, "");
// raw();
cbreak();
curs_set(0);
noecho();
scrollok(stdscr, TRUE);
keypad(stdscr, TRUE);

while (true)
{
    draw.redraw(_board);
    // printf("Your score is: \r\v"); // TODO << score << std::endl;
    sleepThread();
    _board.clearBoard();
    _snake.moveSnake(_snake);

    if (_snake.checkSelfCollision(_snake) == true)
    {
        draw.clearConsole();
        printf("Game Over!\n");
        return 0;
    };

    if (_snake.eatFood(_fruit) == true)
    {
        _board.makeFruit(_fruit);
        _board.setFruitOnBoard(_fruit);
        score++;
    }
    _board.setSnakeOnBoard(_snake);
    _board.setFruitOnBoard(_fruit);
}
endwin();
return 0;
}

А вот моя консолидия. cpp

#include "consoledraw.h"

consoledraw::consoledraw()
{

}

void consoledraw::redraw(Board &board)
{
clearConsole();
drawBoard(board);
}

void consoledraw::clearConsole()
{
// Kompletne vymaze celou konzoli a nasrtavi kurzor do leveho horniho rohu.
refresh();
}

void consoledraw::drawBoard(Board &board)
{
auto b = board.getBoard();

// Top border line
drawHorizontalBorderLine(b[0].size(), true);

// Board
for (unsigned int y = 0; y < b.size(); y++)
{
    printf(LINE_VERTICAL); // border line

    for (unsigned int x = 0; x < b[y].size(); x++)
    {
        drawSymbol(b[y][x]);
    }
    printf(LINE_VERTICAL"\r\v"); // border line + newline
}

// Down border line
drawHorizontalBorderLine(b[0].size(), false);
}

void consoledraw::drawSymbol(ItemType itemType)
{
if (itemType == ItemType::Empty)
{
    printf(BLOCK_TRANSPARENT);
}
else if (itemType == ItemType::Tsss)
{
    printf(BLOCK_MEDIUM_SHADE);
}
else if (itemType == ItemType::Food)
{
    printf(BLOCK_LIGHT_SHADE);
}
else if (itemType == ItemType::TsssHead)
{
    printf(BLOCK_DARK_SHADE);
}
}

void consoledraw::drawHorizontalBorderLine(unsigned long boardWidth, bool isTop)
{
// Left corner
if (isTop)
{
    printf(LINE_UPLEFT_CORNER);
}
else
{
    printf(LINE_DOWNLEFT_CORNER);
}

// Line
for (unsigned int i = 0; i < boardWidth; i++)
{
    printf(LINE_HORIZONTAL);
}

// Right corner
if (isTop)
{
    printf(LINE_UPRIGHT_CORNER);
}
else
{
    printf(LINE_DOWNRIGHT_CORNER);
}

printf("\r\v");
}

Вот что я получаю при использовании ncurses:

enter image description here

И вот что я получаю, используя iostream:

enter image description here

1 Ответ

3 голосов
/ 07 января 2020

Библиотека C (printf()) и библиотека C ++ (std::cout) буферизуют свои выходные данные, хотя по умолчанию библиотеки C и C ++ синхронизируют свои буферы.

Библиотека ncurses делает необработанный (небуферизованный) вывод, иногда обернутый внутриполосными последовательностями управления Если вы смешаете вывод на одно устройство через библиотеку C или C ++ и библиотеку ncurses, вы получите мусор на своем экране. Как и у вас.

Вы должны использовать only либо библиотеку ncurses, либо стандартную библиотеку для обработки ввода / вывода с терминала. Не смешивайте их.

...