Update the console without flashing C++

Asked

Viewed 68 times

1

Hello, I’m doing a game of the cover, the game is already finished, however, I believe by the high frequency of system("cls"), the console keeps flashing, and I wanted to know how to fix it

Here my void with the drawing:

void Draw(){            //Void com todo o Draw;
    system("cls");
    cout << endl;

    for(int i = 0; i < largura+2; i++)              //Printa primeira linha
        cout << "#";

    cout << endl;

    for(int i = 0; i < altura; i++){
            for(int j = 0; j < largura; j++){

            obsPos = false;             //Seta obsPos como falso

            for(int q = 0; q < obsQuantidade; q++){
                if(obstaculoY[q] == i && obstaculoX[q] == j){           //Verifica se o obstaculo está naquela posição, caso esteja obsPos é setado para true;
                        obsPos = true;
                }
            }

            if(j == 0)                 //Printa paredes
                cout << "#";


            if (i == y && j == x){          //Printa cabeça da cobra
                setConsoleColour(DARK_GREEN);
                cout << "O";
                setConsoleColour(WHITE);

            }

            else if (i == FRUTAY && j == FRUTAX)      //Printa fruta
            {
                setConsoleColour(BRIGHT_RED);
                cout << "*";
                setConsoleColour(WHITE);
            }

            else if(obsPos == true){            //Printa o obstaculo com a condição do obsPos como true
                cout << "@";
            }


            else{
                bool printar = false;               //Criando variavel para dar print no corpo da cobra
                for(int k = 0; k < rabo; k++){
                    if(tailX[k] == j && tailY[k] == i){        //Para cada vez que o k for menor que o valor do rabo verificar se ele é igual a um espaço da cobra
                        setConsoleColour(BRIGHT_GREEN);
                        cout << "o";                    //Caso seja printa "o"
                        setConsoleColour(WHITE);
                        printar = true;                 //Caso não coloca variavel printar como true
                    }
                }

                if(!printar){            //Caso printar seja falso coloca espaço em branco
                    cout << " ";
                }

            }

            if(j == largura-1)                  //Printa paredes da direita
                cout << "#";

            }
        cout << endl;

}
  • Dude, I don’t think there’s a way - after all, you’re using the console to print characters. If it bothers you, you have to use a graphical library.

1 answer

0


The system("cls") is a big problem for all beginners who want to play a little game on the console, because the use of system is already something dangerous as well as the use of the function cls is bad in this case, because it is slow added to being a system function that is also heavy, so we can see the screen "flashing" with ease when we need to repeat it several times.

However, it is possible to avoid this problem and manage to make your game work, although not perfect, there are many methods, including libraries, that would solve your problem as conium. h and curses. h, but the choice of these methods depends on what type of screen cleaning or frame update you want to do, in this example of a game of the covering I believe that the best and the least dated method of all would be:

  • Mount the console as if it were two array sizes you need, the buffer and the frameAtual
  • Create a class that stores the buffer matrix (the frame on the screen), and the frameAtual matrix (which stores the latest information), together with the player positions (which can be easily adapted to a cover) and then with the methods of moving the player, check and update the screen.
  • The selective update method will run a for running all over the screen checking what the differences between the buffer and the frameAtual and passing the differences to real-time screen, then updating the real buffer, this works exactly because the slow part of cleaning the console is not the code itself, it is the I/O speed of the windows console, which is very low, then hundreds of ifs and a selective update end up being much faster and pleasing to the eyes than cleaning everything and redo.

I made a simplistic beem prototype with this in practice for you to use base for this idea using just an 'A' player, it’s a perfect method for a cover style game or tetris, so I think it’s the most ideal even though you need to adapt or rewrite a lot of stuff that you already have ready:

#include <iostream> // acabei usando printf nas coisas por que dizem que é mais rápido kk
#include <windows.h>
#include <conio.h>  //kbhit

#define screenWidth 70
#define screenHeight 30

#define KEY_UP 80
#define KEY_DOWN 72
#define KEY_RIGHT 77
#define KEY_LEFT 75

using namespace std;

void ShowConsoleCursor(bool showFlag);
void setCursorPosition(int x, int y);

class game {
    //Frame atual e frame buffer
    char frameAtual[screenWidth][screenWidth], buffer[screenWidth][screenWidth];
    char Player;
    int plX, plY;
        
    public:
        //Inicia a posição do player na tela e seta os dois frames como vazio
        void Init() {
            Player = 'A';
            plX = 20; plY = 20;
            for (int y = 0; y < screenHeight; y++) {
                for (int x = 0; x < screenWidth; x++) {
                    frameAtual[x][y] = buffer[x][y] = ' ';
                }
            }
            frameAtual[plX][plY] = Player;
        }
        void MainL() {
            bool loop = true;
            DrawAll();
            while (loop == true) {
                UpdateBuffer();
                Move();
                SelDraw();
            }
        }
    private:
        //função bem simples para registrar o movimento
        void Move() {
            char keyPressed;
            if (kbhit()) {
                keyPressed = getch();

                switch(keyPressed){ //esse switch analisa qual tecla foi digitada
                    case KEY_UP: // Seta para cima
                        frameAtual[plX][plY] = ' ';
                        plY += 1;
                        frameAtual[plX][plY] = Player;
                    break;
                        
                    case KEY_DOWN: // Seta para baixo
                        frameAtual[plX][plY] = ' ';
                        plY -= 1;
                        frameAtual[plX][plY] = Player;
                    break;
                    
                    case KEY_RIGHT: // Seta para direita
                        frameAtual[plX][plY] = ' ';
                        plX += 1;
                        frameAtual[plX][plY] = Player;
                    break;
                    
                    case KEY_LEFT: // Seta para esquerda
                        frameAtual[plX][plY] = ' ';
                        plX -= 1;
                        frameAtual[plX][plY] = Player;
                    break;
                }
            }
        }
        
        //primeira função de criar a tela vazia
        void DrawAll() {
            for (int y = 0; y < screenHeight; y++) {
                for (int x = 0; x < screenWidth; x++) {
                    printf("%c", frameAtual[x][y]);
                }
                printf("\n");
            }
        }
        //Atualização de frame seletivo - Checa as diferenças no buffer e no frame atual e corrige elas
        void SelDraw() {
            for (int y = 0; y < screenHeight; y++) {
                for (int x = 0; x < screenWidth; x++) {
                    if (frameAtual[x][y] != buffer[x][y]) {
                        setCursorPosition(x,y); printf("%c", frameAtual[x][y]);
                    }
                }
            }
        }
        
        //Atualizar o buffer setando oq está no frame mais recente nele
        void UpdateBuffer() {
            for (int y = 0; y < screenHeight; y++) {
                for (int x = 0; x < screenWidth; x++) {
                    buffer[x][y] = frameAtual[x][y];
                }
            }
        }
};

int main() {
    
    ShowConsoleCursor(false);
    
    game g;
    g.Init();
    g.MainL();
    return 0;
}
//Tirar o cursor da tela (opcional)
void ShowConsoleCursor(bool showFlag)
{
    HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);

    CONSOLE_CURSOR_INFO     cursorInfo;

    GetConsoleCursorInfo(out, &cursorInfo);
    cursorInfo.bVisible = showFlag;
    SetConsoleCursorInfo(out, &cursorInfo);
}
//Pode ser um gotoxy ou qualquer outra função para manipular a posição do cursor 
void setCursorPosition(int x, int y)
{
    static const HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    std::coutflush();
    COORD coord = { (SHORT)x, (SHORT)y };
    SetConsoleCursorPosition(hOut, coord);
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.