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



  • 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 😃



  • Sincap80 schrieb:

    Leide kann ich es nicht Kompilieren da er komischerweise das "max" in der 97 Zeiler als Fehler markiert, es sei nicht deklariert. Was nu?

    Hast Du das Programm so, wie es oben ist, ohne Änderungen übernommen? Dann sollte es kompilieren (mit einem C++ - Compiler).

    Ansonsten könntest Du versuchen, das Makro selbst zu definieren, siehe:
    http://msdn.microsoft.com/en-us/library/windows/desktop/dd757150(v=vs.85).aspx

    Andere Möglichkeit wäre, max aus dem Namensraum std (Header algorithm) zu nehmen ...



  • Ich musste gerade feststellen, das der Threadersteller selbst mit einfachsten for() Schleifen nicht
    klarkommt. Nun ist mir klar warum er mit vielen Dingen hier völlig überfordert ist.

    http://www.c-plusplus.net/forum/p2360612#2360612



  • Das ist natürlich keine gute Vorraussetzung. Die Grundlagen sollte man natürlich beherrschen, schließlich muss man auch verstehen was man macht, nur Copy & Pasten bringt wenig Lernerfolg.


Anmelden zum Antworten