Reputation: 13
I am creating a Snake game on Linux. I was using iostream
to that point when I realized I need a getch()
function included within the ncruses.h
. I had a draw method which was printing all board elements to the console while using std::cout
and every character was displaying correctly. I had the whole board. But when I switched to ncurses and rewrite all the std::cout
to printf
(), then the program starts to write just a parts of the board. It is all done in while cycle and every cycle board is redrawn.
I am a newbie so please be kind.
Here is my main.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;
}
And here is my consoledraw.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");
}
Here is what I get when using ncurses:
And here is what I get using iostream:
Upvotes: 0
Views: 938
Reputation: 1869
The C library (printf()
) and the C++ library (std::cout
) buffer their output -- although by default the C and C++ library synchronize their buffers.
The ncurses library does raw (unbuffered) output, sometimes wrapped with in-band control sequences. If you mix output to the same device through the C or C++ library and the ncurses library, you're going to get garbage on your screen. Just like you have.
You should use only either the ncurses library or the standard library to handle input/output from the terminal. Do not mix them.
Upvotes: 3