Console Flackert wegen System("cls"), Alternative?



  • Hallo,
    Ich bin neu hier und hoffe ihr seit gnädig mit mir 😃

    Nutze gerade Devc++, habe aber auch VS2010 drauf.
    Windows 8.1 (Developer Prewiev)

    Also ich bin gerade dabei Pokemon zu Programmieren. Aber es hängt schon beim laufen :D. Ich hatte es schonmal mit setconsolecurserposition und gotoxy. Da konnte ich zwar laufen aber nicht anderes darstellen wir ränder mit einem # oder so.
    Nun habe ich es ohne versucht und alles klappt bis auf das Problem das meine Console flackert wenn ich gehe wegen dem System("cls").

    Was kann ich stattdessen tun oder ersetzen?

    Mein Quellcode:

    #include <cstdio>
    #include <conio.h>
    #include <iostream>
    #include <Windows.h>
    using namespace std;

    int x=10,y=10, menu=0;
    const int KEY_UP = 0x48;
    const int KEY_DOWN = 0x50;
    const int KEY_LEFT = 0x4b;
    const int KEY_RIGHT = 0x4d;
    const int KEY_ESCAPE = 0x1b;
    const int CONSOLE_WIDTH = 80;
    const int CONSOLE_HEIGHT = 25;

    template<typename T>
    T clamp(const T& min, const T& max, const T& value);
    void getStartbild (void);
    void getAnleitung (void);
    void getAusgabe (void);
    void setMAP (void);
    void setRichtung (void);
    void setBlockade (void);
    void getLadevorgang (void);
    void getMaplaufen (void);
    void clearscreen (void);
    void Menuauswahl (void);
    void setMap1 (void);
    void ClearScreen(void);

    char array[25][80];
    char T = '@';

    int d=0, w=0;
    int Left=0, Right=0, Up=0, Down=0;

    int main()
    {
    setlocale(LC_ALL, "German");

    Menuauswahl();

    system("pause");
    return 0;
    }

    void Menuauswahl (void)
    {

    do{
    system("cls");

    cout<<"1. Spiel neu starten"<<endl;
    cout<<"2. Anleitung"<<endl;
    cout<<"3. Spiel Beenden"<<endl;

    cout<<endl<<"Ihre Auswahl: ";
    cin>>menu;

    switch(menu)
    {
    case 1: getMaplaufen();
    break;

    case 2: getAnleitung();
    break;

    case 3: exit(0);
    break;

    }

    }while(true);
    }

    void getMaplaufen (void)
    {
    do{

    setMAP();

    setRichtung();

    system("cls");

    getAusgabe();

    cout<<"Bitte geben sie die Richtung an in die sie gehen möchten."<<endl;

    }while(d=1);

    }

    void setRichtung (void)
    {
    // setBlockade();

    int key = _getch();
    if (!key || key == 0xe0)
    key = _getch();

    switch (key)
    {
    case KEY_LEFT: if(Left == 0)
    {--x;}
    break;
    case KEY_RIGHT:if(Right == 0)
    {++x;}
    break;
    case KEY_UP: if(Up == 0)
    {--y;}
    break;
    case KEY_DOWN: if(Down == 0)
    {++y;}
    break;
    }
    Left = 0; Right = 0; Down = 0; Up = 0;

    x = clamp(0, CONSOLE_WIDTH-22, x);
    y = clamp(0, CONSOLE_HEIGHT-2, y);

    }

    void setBlockade (void)
    {
    for(int a=3;a<10;a++)
    {for(int b=15;b<16;b++)
    {for(int c=50;c<51;c++)
    {if( array[a][b] == T || array[a][c] == T )
    {Left=1;}
    }
    }
    }
    /*
    if( array[a][b] == T )
    {
    Right=1;
    }
    f( array[a][b] == T )
    {
    Down=1;
    }
    f( array[a][b] == T )
    {
    Up=1;
    }*/
    }

    void setMAP (void)
    {
    setBlockade();

    //Map
    for(int a=0;a<25;a++)
    {
    for(int b=0;b<60;b++)
    {
    array[a][b] = ' ';
    }
    }

    //Ränder
    for(int a=24;a<25;a++)
    {
    for(int b=0;b<59;b++)
    {
    array[a][b] = '-';
    }
    }

    for(int a=0;a<24;a++)
    {
    for(int b=59;b<60;b++)
    {
    array[a][b] = '|';
    }
    }

    setMap1();

    array[24][59] = '+';
    }

    void setMap1 (void)
    {
    //Home Sweet Home
    for(int a=5;a<10;a++)
    {
    for(int b=5;b<15;b++)
    {
    array[a][b] = '#';
    }
    }

    //Keriz Haus
    for(int a=5;a<10;a++)
    {
    for(int b=40;b<50;b++)
    {
    array[a][b] = '#';
    }
    }

    //Prof. Eichs Labor
    for(int a=15;a<19;a++)
    {
    for(int b=25;b<45;b++)
    {
    array[a][b] = '#';
    }
    }
    }

    void getAusgabe (void)
    {

    for(int a=0;a<25;a++)
    {
    for(int b=0;b<60;b++)
    {
    cout<<array[a][b];
    }
    cout<<endl;
    }

    }

    Mit freundlichen Grüßen



  • Sincap80 schrieb:

    Ich hatte es schonmal mit setconsolecurserposition und gotoxy. Da konnte ich zwar laufen aber nicht anderes darstellen wir ränder mit einem # oder so.

    Verstehe ich nicht. Du malst einmal das ganze Spielfeld und danach nur noch das, was sich verändert mit Position löschen und neuzeichnen.

    Wenn Du für jeden Zug das ganze Feld löschst und neu malst, dann wird es wohl flackern, auch wenn Du den Bildschirm mit WinAPI-Funktionen löschst ....



  • Ich hab jetzt nicht dein Code durchgeschaut aber schau mal mein Beispiel an:

    Da flackert nix. Vielleicht kannst du ja damit was anfangen ... Uuuh ich hab C mit C++ etwas gemischt ich böser Rabauke. 😃

    #include <iostream>
    #include <conio.h>
    using namespace std;
    
    void DisplayPlayer(unsigned x, unsigned y);
    
    int main()
    {
    unsigned ctr;
    unsigned x=1,y=1;
    
    DisplayPlayer( x, y );
    
    while(1)
    {
    	ctr = getch();
    
    	if ( ctr == 100 ) // 100 = D  ( Laufe nach rechts )
    	{
    		clrscr();
    		x++;
    		DisplayPlayer( x, y);
    	}
    
    	if ( ctr == 97 ) // 97 = A  ( Laufe nach links )
    	{
    		clrscr();
    		x--;
    		DisplayPlayer( x, y);
    	}
    
    	if ( ctr == 115 ) // 115 = S ( Laufe nach unten )
    	{
    		clrscr();
    		y++;
    		DisplayPlayer( x, y);
    	}
    
    	if ( ctr == 119 ) // 119 = W ( Laufe nach oben )
    	{
    		clrscr();
    		y--;
    		DisplayPlayer( x, y);
    	}
    }
    
    }
    //---------------------------------------------------------------------------
    
    void DisplayPlayer(unsigned x, unsigned y)
    {
    	gotoxy(x,y);
    	cout<<"\x4"<<"\n";
    }
    


  • Hallo Sincap80!

    Leider lässt es sich nicht testen, da zwei Funktionen fehlen:

    void getAnleitung (void);
    int clamp( int min, int max, int value);
    

    Die untere ist essentiell.

    Immer das ganze Feld neuzeichnen macht keinen Sinn. Ich würde den Hintergrund
    der alten Position neuzeichnen und dann die Figur an der neuen Position.

    Die Lösung von Bassmaster lässt sich mit VS auch nicht kompilieren, da sowohl clrscr() alsauch gotoxy() nicht gefunden werden. Da hilft aber google weiter:

    // siehe http://msdn.microsoft.com/en-us/library/windows/desktop/ms682022.aspx
    void clrscr( void);

    // siehe http://social.msdn.microsoft.com/Forums/en-US/d3ec2d1d-044d-441f-9472-4a284eee3e9b/alternative-to-gotoxy-
    void gotoxy(int x,int y);

    Das es nicht flackert liegt aber sicher daran, das ausser der Figur auch nichts
    gezeichnet wird ...



  • Vielleicht macht es ja auch Sinn statt der Console eine GUI zu nehmen.

    Für Windows zB. so:
    http://msdn.microsoft.com/en-us/library/windows/desktop/ms646268.aspx



  • merano schrieb:

    Hallo Sincap80!

    Leider lässt es sich nicht testen, da zwei Funktionen fehlen:

    void getAnleitung (void);
    int clamp( int min, int max, int value);
    

    Die untere ist essentiell.

    Sry hier der fehlende Code:

    template<typename T>
    T clamp(const T& min, const T& max, const T& value)
    {
    return (value < min ? min : value > max ? max : value);
    }



  • merano schrieb:

    Immer das ganze Feld neuzeichnen macht keinen Sinn. Ich würde den Hintergrund
    der alten Position neuzeichnen und dann die Figur an der neuen Position.

    Wenn ich es nicht neu zeichne dann verschiebt es sich in der Konsole.
    Probiert es mal aus. Ich muss es in der Konsole lösen. Hat jemand eine Lösung?

    MfG



  • Dann machst Du wohl was falsch. Such mal im Konsole-Forum, da solltest Du einige Beispiele finden. Eines wäre wohl das hier:
    http://www.c-plusplus.net/forum/306013



  • Sincap80 schrieb:

    merano schrieb:

    Immer das ganze Feld neuzeichnen macht keinen Sinn. Ich würde den Hintergrund
    der alten Position neuzeichnen und dann die Figur an der neuen Position.

    Wenn ich es nicht neu zeichne dann verschiebt es sich in der Konsole.
    Probiert es mal aus. Ich muss es in der Konsole lösen. Hat jemand eine Lösung?

    MfG

    Offensichtlich verwendest du system("cls") um den Cursor in die linke obere Ecke
    zu bekommen.
    Das Löschen des Screens auf diese Art ist uneffektiv und in diesem Fall auch unnötig.

    void getMaplaufen (void) 
    { 
    do{ 
    	setMAP(); 
    	setRichtung(); 
    	// system("cls"); 
    	gotoxy(0,0);
    	array[y][x] = T; 
    	getAusgabe(); 
    	cout<<"Bitte geben sie die Richtung an in die sie gehen möchten."; 
    }while(d=1);
    

    PS: Wenn man den Screen wirklich löschen möchte dann z.B. so wie es dir bereits mehrere Leute hier
    vorgeschlagen haben.

    Das Spielfeld ist mit 80x25 auch zu gross wenn noch eine Zeile Text drunter passen soll. Ich würde das
    durchgängig mit define oder const lösen.

    const int CON_WIDTH = 80; 
    const int CON_HEIGHT = 25; 
    
    char array[CON_HEIGHT][CON_WIDTH];
    

    Wobei es hier eigentlich nur 24 Zeilen sein sollten ...

    Und natürlich darf man kein Zeilenendezeichen ausgeben, da man dann noch eine Zeile mehr benötigt ...



  • Alternativ kann man das gotoxy(0,0) auch in getAusgabe() verschieben.



  • Weitere Routinen für Console finden sich auch hier:

    Using the Console
    http://msdn.microsoft.com/en-us/library/windows/desktop/ms686971.aspx



  • merano schrieb:

    void getMaplaufen (void) 
    { 
    do{ 
    	setMAP(); 
    	setRichtung(); 
    	// system("cls"); 
    	gotoxy(0,0);
    	array[y][x] = T; 
    	getAusgabe(); 
    	cout<<"Bitte geben sie die Richtung an in die sie gehen möchten."; 
    }while(d=1);
    

    Erstmal Danke das du mir hilfst 😃
    Wenn ich das mit gotoxy löse, ist das genau das gleiche, als würde ich system cls benutzen 😞



  • Der Debugger gibt mir "'gotoxy': Bezeichner wurde nicht gefunden." aus, nachdem ich system("cls") durch gotoxy(0,0) ersetzt habe? Was mach ich falsch?



  • EdwardBlack schrieb:

    Der Debugger gibt mir "'gotoxy': Bezeichner wurde nicht gefunden." aus, nachdem ich system("cls") durch gotoxy(0,0) ersetzt habe? Was mach ich falsch?

    Der Threadersteller hat es bereits eingebaut ...

    http://www.spieleprogrammierer.de/18-c-cplusplus-csharp-java-und-andere-sprachen/21261-hilfe-bei-einem-programm-cursor-bewegen-auf-der-console/



  • Sincap80 schrieb:

    Erstmal Danke das du mir hilfst 😃
    Wenn ich das mit gotoxy löse, ist das genau das gleiche, als würde ich system cls benutzen 😞

    Nur das es nicht mehr flackert.

    Wenn es doch flackert liegt es daran, das nicht alle Zeilen auf den Screen passsen. Wenn du das
    Fenster versuchsweise etwas vergroesserst flackert da nichts, da immer an den gleichen Stellen
    gezeichnet wird. Ich wuerde empfehlen das Zeichenfeld etwas zu verkleinern, oder notfalls
    das Consolenfenster zu vergroessern.

    Besser wäre natürlich nur die Zeichen zu zeichnen, die sich wirklich ändern.

    Es gibt dann natürlich auch noch die Möglichkeit mit zwei verschiedenen Screens
    zu arbeiten. -> Siehe meinen Link "Weitere Routinen für Console"



  • merano schrieb:

    Besser wäre natürlich nur die Zeichen zu zeichnen, die sich wirklich ändern.

    Ja habe ich mir auch gedacht, aber da weis ich jetzt nicht wie. Ich habe es nun so gemacht dass ich nur 1x Die ganze Map ausgebe und dann nur noch den Player. Das funktioniert aber nicht. Wie soll ich das machen?



  • Sincap80 schrieb:

    merano schrieb:

    Besser wäre natürlich nur die Zeichen zu zeichnen, die sich wirklich ändern.

    Ja habe ich mir auch gedacht, aber da weis ich jetzt nicht wie. Ich habe es nun so gemacht dass ich nur 1x Die ganze Map ausgebe und dann nur noch den Player. Das funktioniert aber nicht. Wie soll ich das machen?

    Wo soll das Problem sein ?

    Wir gehen davon aus, das du weisst wo der player ist. Ausserdem gibt es ein array das
    den Hintergrund enthält. Für die Fläche (in diesem Fall nur ein zeichen) holst Du aus dem array
    die Fläche auf der aktuell der Player ist und zeichnest das an die Stelle wo der Player ist.

    Zum Schluss zeichnest Du den Player an der neuen Position neu 😃



  • Sincap80 schrieb:

    nur 1x Die ganze Map ausgebe und dann nur noch den Player. Das funktioniert aber nicht. Wie soll ich das machen?

    Zum Beispiel so (einfach mal auf die Schnelle aus dem Ärmel gespuckt, unter Zuhilfenahme einiger Konsolenroutinen, die ich mir im Laufe der Zeit mal zusammengeschrieben habe):

    #include <windows.h>
    
    void SetCursorPosition(int x, int y)
    {
        COORD pos = {x, y};
    
        SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
    }
    
    void SetCursorVisible(BOOL v)
    {
        CONSOLE_CURSOR_INFO ci;
    
        GetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &ci);
    
        ci.bVisible = v;
    
        SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &ci);
    }
    
    void DruckSimpleText(int x, int y, char const *text)
    {
        COORD target = {x, y};
        DWORD written;
    
        WriteConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), text,
                                                strlen(text),
                                                target, &written);
    }
    
    void DruckSimpleChar(int x, int y, char c)
    {
        char text[2] = {c, 0};
    
        DruckSimpleText(x, y, text);
    }
    
    void ClearScreen(WORD attribute = 7)
    {
        CONSOLE_SCREEN_BUFFER_INFO csbi;
        COORD target = {0, 0};
        DWORD written;
    
        GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
        FillConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE), ' ',
                                                csbi.dwSize.X * csbi.dwSize.Y,
                                                target, &written);
        FillConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE), attribute,
                                                csbi.dwSize.X * csbi.dwSize.Y,
                                                target, &written);
    }
    
    int getInput()
    {
        INPUT_RECORD ir;
    
        DWORD dummy;
        do
        {
            ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &ir, 1, &dummy);
        }while(ir.EventType != KEY_EVENT || !ir.Event.KeyEvent.bKeyDown);
    
        return ir.Event.KeyEvent.uChar.AsciiChar;
    }
    
    int peekInput()
    {
        INPUT_RECORD ir;
    
        DWORD anz;
    
        PeekConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &ir, 1, &anz);
    
        if(ir.EventType == KEY_EVENT && !ir.Event.KeyEvent.bKeyDown)
        {
          ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &ir, 1, &anz);
          return 0;
        }
    
        return anz;
    }
    
    void SetWindowExt(int x, int y, int yMulti = 1)
    {
        SMALL_RECT sr_window = {0, 0, x - 1, y - 1};
        COORD      extension;
        CONSOLE_SCREEN_BUFFER_INFO csbi;
    
        GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
    
        extension.X = max(x, csbi.dwMaximumWindowSize.X);
        extension.Y = max(y, csbi.dwMaximumWindowSize.Y);
    
        SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), extension);
        SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE), TRUE, &sr_window);
    
        extension.X = x;
        extension.Y = y * yMulti;
        SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), extension);
    }
    
    void move(char dir)
    {
       static int x = 5;
       static int y = 5;
       static char aktDir = 'd';
    
       DruckSimpleChar(x, y, ' ');
    
       if(dir == 'a' || dir == 'w' || dir == 's' || dir == 'd')
          aktDir = dir;
    
       switch(aktDir)
       {
          case 'a': x--; if(x < 2) x = 17; break;
          case 'w': y--; if(y < 2) y = 17; break;
          case 'd': x++; if(x > 17) x = 2; break;
          case 's': y++; if(y > 17) y = 2; break;
       }
    
       DruckSimpleChar(x, y, 'O');
    }
    
    int main()
    {
       SetWindowExt(20, 15); SetWindowExt(50, 30);
       ClearScreen();
       SetCursorVisible(false);
    
       //Spielfeldbegrenzung
       DruckSimpleText(1, 1, "------------------");
       DruckSimpleText(1, 18, "------------------");
    
       for(int y = 2; y < 18; ++y)
          DruckSimpleText(1, y, "|                |");   
    
       DruckSimpleText(1, 21, "Richtung? (a, w, s, d, x)");
    
       char Richtung = 'd';
    
       do
       {
          if(peekInput())
             Richtung = getInput();
    
          if(Richtung == 'x')
             break;
    
          move(Richtung);
    
          Sleep(200);
    
       }while(true);
    
       SetCursorVisible(true);
    
    }
    


  • Belli schrieb:

    Zum Beispiel so (einfach mal auf die Schnelle aus dem Ärmel gespuckt, unter Zuhilfenahme einiger Konsolenroutinen, die ich mir im Laufe der Zeit mal zusammengeschrieben habe):

    Ok haha ich hoffe die Routine bekomme ich auch 😃
    Leide kann ich es nicht Kompilieren da er komischerweise das "max" in der 97 Zeiler als Fehler markiert, es sei nicht deklariert. Was nu?



  • merano schrieb:

    Wo soll das Problem sein ?

    Wir gehen davon aus, das du weisst wo der player ist. Ausserdem gibt es ein array das
    den Hintergrund enthält. Für die Fläche (in diesem Fall nur ein zeichen) holst Du aus dem array
    die Fläche auf der aktuell der Player ist und zeichnest das an die Stelle wo der Player ist.

    Zum Schluss zeichnest Du den Player an der neuen Position neu 😃

    Ich nehme es aus der Array Position z.b. array[1][1] mache dort ein ' ' und dann auf array[1][2] zeichne ich den Player ein. Dann muss ich es doch wieder ausgeben. Dann habe ich doch wieder das Problem dass es entweder in der Console verrutscht oder mit system cls flackert.

    Sry wenn ich dich nerve 😃


Anmelden zum Antworten