Reputation: 2052
I would like to animate a 40x20 block of characters that I am cout
-ing. I would like to clear the console with system("cls");
and then have the next block on character instantly appear. Currently the next block is coming on typewriter style.
The most simplest answer to my question would just to have a 20 line by 40 character oss stream cout at once, instead of doing it typewriter style.
Main.cpp:
mazeCreator.cout();
Sleep(5000);
system("cls");
cout()
void MazeCreator::cout() {
char wallChar = (char) 219;
char pavedChar = (char) 176;
char lightChar = ' ';
char startChar = 'S';
char finishChar = 'F';
char errorChar = '!';
char removedWallChar = 'R';
char landmarkLocationChar = 'L';
ostringstream oss;
for (int row = 0; row < rows; row++) {
oss << " ";
for (int col = 0; col < columns; col++) {
if (mazeArray[row][col] == wall)
oss << wallChar;
else if (mazeArray[row][col] == paved)
oss << pavedChar;
else if (mazeArray[row][col] == light)
oss << lightChar;
else if (mazeArray[row][col] == start)
oss << startChar;
else if (mazeArray[row][col] == finish)
oss << finishChar;
else if (mazeArray[row][col] == removedWall)
oss << removedWallChar;
else if (mazeArray[row][col] == landmarkLocation)
oss << landmarkLocationChar;
else
oss << errorChar;
}
oss << "\n";
}
oss << "\n\n";
cout << oss.str();
}
Upvotes: 1
Views: 3676
Reputation: 52739
You could maintain two 2D arrays in your code, one with the current block of characters on the screen (let's call it cur
) and one with the next block (let's call it next
).
Assume cur
stores the block that's on screen right now. Set up the next block by writing into the next
array. When you're ready to put it on the screen, loop through cur
and next
simultaneously, and only for characters where they differ, use SetConsoleCursorPosition
to jump to that location and write the new character.
Once you've done that, copy the contents of next
into cur
and move on to the next block.
UPDATE: Here's an example:
class console_buffer
{
public:
console_buffer(int rows, int columns)
// start out with spaces
: cur(rows, vector<char>(columns, ' ')),
next(rows, vector<char>(columns, ' '))
{
}
void sync()
{
// Loop over all positions
for (int row = 0; row < cur.size(); ++row)
for (int col = 0; col < cur[row].size(); ++col)
// If the character at this position has changed
if (cur[row][col] != next[row][col])
{
// Move cursor to position
COORD c = {row, col};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
// Overwrite character
cout.put(next[row][col]);
}
// 'next' is the new 'cur'
cur = next;
}
void put(char c, int row, int col)
{
next[row][col] = c;
}
private:
vector<vector<char> > cur;
vector<vector<char> > next;
};
...
int main()
{
console_buffer buf(40, 20);
// set up first block
... some calls to buf.put() ...
// make first block appear on screen
buf.sync();
// set up next block
... some calls to buf.put()
// make next block appear on screen
buf.sync();
// etc.
}
Upvotes: 2
Reputation: 61910
You can implement double buffering using CreateConsoleScreenBuffer. Something along these lines should work. I've used this once, quite a while ago, so it might not be perfect.
HANDLE current = GetStdHandle (STD_OUTPUT_HANDLE);
HANDLE buffer = CreateConsoleScreenBuffer (
GENERIC_WRITE,
0,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
WriteConsole (/*fill with what you're drawing*/);
system ("cls"); //clear this screen before swapping
SetConsoleActiveScreenBuffer (buffer);
WriteConsole (/*do it to the other one now*/);
system ("cls");
SetConsoleActiveScreenBuffer (current); //swap again
//repeat as needed
CloseHandle (buffer); //clean up
Upvotes: 0