I’m trying to create a simple ASCII 3D spinning cube animation in the Windows console using C++:
#include <iostream>
#include <cmath>
#include <cstring>
#include <windows.h>
#include <thread>
using namespace std;
const int WIDTH = 80;
const int HEIGHT = 40;
const float cubeWidth = 20;
float A = 0, B = 0, C = 0;
float distanceFromCamera = 100;
float K1 = 40;
char buffer[WIDTH * HEIGHT];
float zBuffer[WIDTH * HEIGHT];
float cosA, sinA, cosB, sinB, cosC, sinC; // biến lượng giác dùng chung
void gotoxy(HANDLE hConsole, int x, int y) {
COORD pos{(SHORT)x, (SHORT)y};
SetConsoleCursorPosition(hConsole, pos);
}
void rotate(float i, float j, float k, float &x, float &y, float &z) {
// rotation quanh 3 trục
float x1 = i;
float y1 = j * cosA - k * sinA;
float z1 = j * sinA + k * cosA;
float x2 = x1 * cosB + z1 * sinB;
float y2 = y1;
float z2 = -x1 * sinB + z1 * cosB;
x = x2 * cosC - y2 * sinC;
y = x2 * sinC + y2 * cosC;
z = z2;
}
void calculatePoint(float i, float j, float k, char ch) {
float x, y, z;
rotate(i, j, k, x, y, z);
z += distanceFromCamera;
float ooz = 1 / z;
int xp = int(WIDTH / 2 + K1 * ooz * x * 2);
int yp = int(HEIGHT / 2 - K1 * ooz * y);
int idx = xp + yp * WIDTH;
if (idx >= 0 && idx < WIDTH * HEIGHT) {
if (ooz > zBuffer[idx]) {
zBuffer[idx] = ooz;
buffer[idx] = ch;
}
}
}
int main() {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
// Ẩn con trỏ nhấp nháy
CONSOLE_CURSOR_INFO cursorInfo;
GetConsoleCursorInfo(hConsole, &cursorInfo);
cursorInfo.bVisible = FALSE;
SetConsoleCursorInfo(hConsole, &cursorInfo);
while (true) {
fill(buffer, buffer + WIDTH * HEIGHT, ' ');
fill(zBuffer, zBuffer + WIDTH * HEIGHT, 0);
// tính lượng giác 1 lần m���i frame
cosA = cosf(A); sinA = sinf(A);
cosB = cosf(B); sinB = sinf(B);
cosC = cosf(C); sinC = sinf(C);
for (float i = -cubeWidth; i < cubeWidth; i += 0.5f) {
for (float j = -cubeWidth; j < cubeWidth; j += 0.5f) {
calculatePoint(i, j, -cubeWidth, '@');
calculatePoint(cubeWidth, j, i, '$');
calculatePoint(-cubeWidth, j, -i, '~');
calculatePoint(-i, j, cubeWidth, '#');
calculatePoint(i, -cubeWidth, -j, ';');
calculatePoint(i, cubeWidth, j, '+');
}
}
gotoxy(hConsole, 0, 0);
for (int k = 0; k < WIDTH * HEIGHT; k++) {
cout << ((k % WIDTH) ? buffer[k] : '\n');
}
A += 0.04f;
B += 0.03f;
this_thread::sleep_for(chrono::milliseconds(16));
}
return 0;
}
The rendering works fine, but there’s one major issue: Each frame prints below the previous one, so the terminal keeps scrolling down endlessly instead of updating in place like a normal animation.
Even though I use "\x1b[H" to move the cursor back to the top, the console still scrolls downward — every new frame is printed below the previous one.
How can I correctly render each frame in the same position (without scrolling) on Windows console, preferably without using third-party graphics libraries? (Im using VSCode on Windows 11).
What I’ve tried:
- Using "\x1b[2J" or "\033[H" to clear screen / move cursor
- Using std::flush after printing
- Running on different terminals (CMD, PowerShell, Windows Terminal)
Expected behavior: I want the cube to rotate in place (in a fixed area of the console), not scroll down.
cout- this means standard output. This is wrong tool for animation in text mode. You should use some API this is able to output text directly into console.cout << std::flushorcout.flush()beforesleep_for. This could be related.for (int k = 0; k < WIDTH * HEIGHT; k++) { cout << ((k % WIDTH) ? buffer[k] : '\n'); }is a rather slow way to print the whole buffer. Just add another character to the width and make that a\nand then print the whole buffer at once.std::cout) and low level action (SetConsoleCursorPosition). You cannot know exactly how C++coutis implemented (it is an implementation detail that can change without notice) and relying on expected interaction is a sure path to problems.