Forum: PC-Programmierung direkt in den Ausgabe-Buffer schreiben [C++ Konsolenanwendung]


von Bartosz B. (bartosz)


Angehängte Dateien:

Lesenswert?

Hi all, ich habe eine Bitte an euch. Könntet ihr mir sagen, wie ich 
direkt in den Ausgabe-Buffer scrheibe? Ich habe gehört, dass das geht.

Zum Problem: Ich habe ein char-Array, in dem das Spielfeld ist. Dieses 
ist 28*36 Felder groß. Da das Feld ständig neu gezeichnet werden muss, 
bekomme ich eine Flimmerkiste. Ich weiß, diese nested for loops sind ein 
Flaschenhals, aber mit diesem char-Array konnte ich bisher so leicht 
arbeiten.
1
void Spiel::render_output()
2
{
3
  Konsole_leeren();
4
  Spielfeld_Original[Gegner.Y][Gegner.X] = '\xB2'; //▓
5
  Spielfeld_Original[du.Y][du.X] = 'O';
6
7
  for (int i = 0; i < vert; i++)
8
  {
9
    for (int j = 0; j < hor; j++)
10
    {
11
      std::cout << Spielfeld_Original[i][j];
12
    }
13
    std::cout << '\n'; //optimiert
14
  }
15
16
  Spielfeld_Original[Gegner.Y][Gegner.X] = ' ';
17
  Spielfeld_Original[du.Y][du.X] = ' ';
18
}

Ach ja und
1
Konsole_leeren();
 wurde hier bereits behandelt. 
Beitrag "Warum ist diese Prozedur schneller als system("cls")"

von cppbert (Gast)


Lesenswert?


von Mathias A. (mrdelphi)


Lesenswert?

Hi,

Bartosz B. schrieb:
> Hi all, ich habe eine Bitte an euch. Könntet ihr mir sagen, wie ich
> direkt in den Ausgabe-Buffer scrheibe? Ich habe gehört, dass das geht.

Darauf hab ich jetzt ad-hoc leider keine Antwort -- aber wahrscheinlich 
ist das gar nicht nötig, um das Flimmern zu beseitigen: ich vermute dass 
es nur daher kommt, dass Du die Konsole vor dem Rendern leeren lässt. 
Dadurch verschwinden alle Zeichen für kurze Zeit, und werden dann neu 
geschrieben. Alle Zeichen, die sich gegenüber dem vorigen Rendern nicht 
geändert haben, werden dadurch immer wieder kurz schwarz (oder welche 
Farbe der Hintergrund eben hat) -- das wird als Flimmern sichtbar.

Es sollte reichen, vor dem Rendern nur den Cursor nach links oben zu 
setzen -- und nicht noch die Konsole mit Leerzeichen zu füllen.

Also z.B. Konsole_leeren nur noch ganz am Anfang mal aufrufen, und in 
render_output dann stattdessen nur noch diesen Teil davon:
1
SetConsoleCursorPosition(hOut, topLeft);

: Bearbeitet durch User
von Erwin von Bohlen und Hallbach (Gast)


Lesenswert?

[X] Ich bin zu doof eine Suchmaschine zu benutzen.

von Bartosz B. (bartosz)


Lesenswert?

Danke an @Mathias für die Idee und Erklärung.
1
void Spiel::render_output()
2
{
3
  HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
4
  SetConsoleCursorPosition(hOut, { 0,0 });
5
6
  Spielfeld_Original[Gegner.Y][Gegner.X] = '\xB2'; //▓
7
  Spielfeld_Original[du.Y][du.X] = 'O';
8
9
  for (int i = 0; i < vert; i++)
10
  {
11
    for (int j = 0; j < hor; j++)
12
    {
13
      std::cout << Spielfeld_Original[i][j];
14
    }
15
    std::cout << '\n'; //optimiert
16
  }
17
18
  Spielfeld_Original[Gegner.Y][Gegner.X] = ' ';
19
  Spielfeld_Original[du.Y][du.X] = ' ';
20
}
 funktioniert schon viel besser, das Flimmern ist weg – bis auf dass man 
den Cursor von oben nach unten hin- und herspringen sieht. Aber das 
bekommt man wohl nicht weg?


> Ich bin zu doof eine Suchmaschine zu benutzen.
Nein, ich habe mir die Mühe gemacht, aber ich kam mit den Beispielen und 
Dokus nicht zurecht. @cppbert s Link ist schon besser ^^

von Mathias A. (mrdelphi)


Lesenswert?

Bartosz B. schrieb:
> funktioniert schon viel besser, das Flimmern ist weg – bis auf dass man
> den Cursor von oben nach unten hin- und herspringen sieht. Aber das
> bekommt man wohl nicht weg?

Freut mich!  Doch, den Cursor bekommt man auch weg: man kann ihn 
unsichtbar schalten. In deinem Fall bietet sich an, entweder ausschalten 
am Beginn von render_output und am Ende wieder einschalten (dann blinkt 
er in der rechten unteren Ecke), oder ganz am Anfang mal ausschalten und 
erst beim Beenden des Spiels wieder einschalten.

Wie das ein/ausschalten genau geht weiß ich gerade nicht auswendig, und 
hängt auch vom verwendeten Terminal ab. Meist ist es eine bestimmte 
Escape-Sequenz (d.h. eine Zeichenkette, die mit dem ASCII-Code für 
Escape (=27) beginnt und die, wenn man sie auf dem Terminal ausgibt, 
dort eine Aktion ausführt). Müsste aber per Google gut zu finden sein 
wie das beim Windows Terminal geht.

von cppbert (Gast)


Lesenswert?

Von stackoverflow
1
#include <windows.h>
2
3
void hidecursor()
4
{
5
   HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
6
   CONSOLE_CURSOR_INFO info;
7
   info.dwSize = 100;
8
   info.bVisible = FALSE;
9
   SetConsoleCursorInfo(consoleHandle, &info);
10
}

von Bartosz B. (bartosz)


Lesenswert?

Ich schalte den Cursor nun am Anfang des Spiels aus und beim Beenden 
wieder ein.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.