Das Gute, Alte Snake ^^



  • Hallo,
    Ich habe vor ein paar Monaten mal ein sehr einfaches Snake in C++ gemacht,
    vielleicht hilft es dir.

    #include <iostream>  
    #include <windows.h> 
    #include <conio.h>   
    
    using namespace std;
    
    //Funktionsprototypen:
    void gotoxy(int x,int y); //eine Funktion, um den Cursor zu positionieren
    void SetFutter(void); //eine Funktion, die das Futter positioniert
    
    //Variablen:
    int snake[1000][2]; //Alle Segmente der Schlange; x und y
    int laenge; //wie lang ist die Schlange?
    int kopfx;  //Koordinaten des Kopfes
    int kopfy;
    int futterx; //Koordinaten des Futters
    int futtery;
    char richtung; //Richtung, in die die Schlange gerade läuft
    int biss; //hat sich die Schlange selbst oder in die Wand gebissen?
    int i;  
    
    int main (void){
        //Ausgabe des Rahmens:
        system("cls"); //lösche Bildschirm = clear screen
        gotoxy(0,0); //Mache Kreuze in die Ecken
        cout << "+";
        gotoxy(0,21);
        cout << "+";
        gotoxy(41,0);
        cout << "+";
        gotoxy(41,21);
        cout << "+";
        for (i = 1; i <=40; i++){ //mache horizontale Rahmenlinien
            gotoxy(i,0);
            cout << "-";
            gotoxy(i,21);
            cout << "-";
        }
        for (i = 1; i <=20; i++){ //mache verikale Rahmenlinien
            gotoxy(0,i);
            cout << "|";
            gotoxy(41,i);
            cout << "|";
        }
        //Setup der Schlange:
        richtung = 'd'; //Die Schlange läuft am Anfang nach rechts, also Taste 'd'
        kopfx = 10; //Lege die Position des Kopfes fest
        kopfy = 10;
        laenge = 5; //Die Schlange ist am Anfang 5 lang.
        biss = 0; //Sie hat sich logischerweise auch noch nicht gebissen
        for (i = 0; i < 5; i++){ //Leg die Koordinaten des Körpers fest
            snake[i][0]= 10-i;
            snake[i][1]= 10;
        }
        SetFutter(); //Generiere Futter
        for (i = 0; i < laenge; i++){ //Gib die Schlange aus
             gotoxy(snake[i][0],snake[i][1]);
             cout << "O";
        }
        //Spiel:
        while(!biss){ //Solange Biss=0
                 if (kbhit()) //Wenn jemand die tastatur "Schlägt"; kb = keyboard
                 richtung = getch(); //dann lese die gedrückte taste in die Variable 'richtung'
                 kopfx = snake[0][0]; //lade die Kopfkoordinaten
                 kopfy = snake[0][1];
                 switch (richtung){ //Bewege den Kopf, jenachdem welcher Buchstabe gedrückt wurde
                        case 'd':
                             kopfx++;
                             break;
                        case 'a':
                             kopfx--;
                             break;
                        case 's':
                             kopfy++;
                             break;
                        case 'w':
                             kopfy--;
                             break;
                 }
                 //Lösche das letzte Segment der Schlange
                 gotoxy(snake[laenge-1][0],snake[laenge-1][1]);
                 cout << " ";
                 //Verschiebe die Koordinaten aller Segmente um 1 nach hinten
                 for (i = laenge-1; i > 0; i--){
                     snake[i][0] = snake[i-1][0];
                     snake[i][1] = snake[i-1][1];
                     if ((kopfx == snake[i][0]) && (kopfy == snake[i][1]))
                     biss = 1; //wenn der Kopf auf einem Segment der Schlange ist
                 }
                 //Speichere die neuen Kopfkoordinaten
                 snake[0][0] = kopfx;
                 snake[0][1] = kopfy;
                 //wenn Kopf = Futter
                 if ((kopfx == futterx) && (kopfy == futtery)){
                            SetFutter(); //Generiere neues Futter
                            laenge++; //lass die Schlange wachsen
                 }
                 if ((kopfx < 1) || (kopfx > 40)|| (kopfy < 1)|| (kopfy > 20))  
                 biss = 1;   //wenn der Kopf aus dem Spielfeld rausgeht    
                 gotoxy(kopfx,kopfy); //Gebe Kopf aus
                 cout << "O";
                 gotoxy(0,0); //gebe ein neues Kreuz aus.
                 cout << "+";
                 Sleep(70); //Verlangsame das Spiel ein wenig 
        }
        system("cls"); //Lösche Bildschirm
        cout << "Spiel zuende!\n" << endl; //Gib was aus
        cout << "\nDruecke die Eingabetaste...";
        getchar();  //Warte, bis der User Enter drückt  
        return 0;  //Gib nichts zurück, Ende
    }
    
    //Funktion gotoxy:
    void gotoxy(int x,int y) 
    { 
       COORD cur={x,y}; 
       SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),cur); 
    } 
    //Funktion setFutter
    void SetFutter(void){
         srand(time(NULL)); //Mach die Zufallszahlen abhängig von der Zeit
         int _fehler;
         do{ 
             _fehler = 0;
             futterx =(rand()%40)+1; //Generiere zufällige Koordianten
             futtery =(rand()%20)+1;
             for (i = laenge-1; i >= 0; i--){
                     if ((futterx == snake[i][0]) && (futtery == snake[i][1]))
                     _fehler = 1; //wenn das futter auf einem Segment der Schlnge landet, versuche es erneut
             }  
         }while(_fehler); 
         gotoxy(futterx,futtery);
         cout << "X"; //Gib das Futter aus
    }
    


  • Danke! 🙂
    Nur selten stellt jemand seinen Code public
    und dann noch mit Kommentaren....

    DANKE! 😃



  • Ja, mit dem Code wollte ich eigentlich mal ein Tutorial machen, kam aber in letzter Zeit nicht dazu.



  • Wenn du wirklich eines machst
    schick mir ne Pn oder ähnliches.
    Heiße auf YT PyroTec21



  • Ja, das werde dir was schicken (bin FensterSieben auf YT).



  • Das Ganze geht aber wesentlich eleganter und ohne dass man ständig alle Segmente verschieben muss :p



  • Ja, ich weis, aber damals wusste ich eben noch nicht wies anders geht. Vielleicht mach ich mal ein neues.



  • @cooky Aaaaaber es Funtkioniert! 😃
    Und hat mir sehr geholfen.
    Jetzt weiß ich wo ich noch was lernen muss zum Snake Programmieren 🙂
    (Hab das Buch C++ von A bis Z)



  • Ok, dann viel Spaß.

    In den nächsten Tagen werde ich meine überarbeitete Version einstellen - mit einem zweidimensionalen Ringspeicher für extra Speed.



  • LOL Ringspeicher ist doch gar nicht nötig 😃
    Zähl die Runden mit und halte die Länge der Snake fest dann hast Du quasi einen automatischen Ringpuffer 😉 (modulo ist da sehr hilfreich^^)



  • @MGDOS
    Danke! 😃
    Hab dich auf jedenfall Abo falls
    du ein Vid. machst.

    MFG



  • @ cooky:
    hat ich ja auch vor - das ist doch dann ein Ringspeicher.



  • MGOS schrieb:

    Ja, mit dem Code wollte ich eigentlich mal ein Tutorial machen, kam aber in letzter Zeit nicht dazu.

    Braucht auch kein Mensch...



  • Miese Tutorials schrieb:

    MGOS schrieb:

    Ja, mit dem Code wollte ich eigentlich mal ein Tutorial machen, kam aber in letzter Zeit nicht dazu.

    Braucht auch kein Mensch...

    Warum? Anfänger freuen sich über so etwas. Man sollte nur darauf achten auch wirklich schönen/brauchbaren/guten Code zu nutzen. (Und diese erste Snake Version ist.. na ja.. nicht umbedingt schön 😉 )



  • Wenn du damit meine meinst ok 🙂
    Aber wenn du die Version von MGOS meinst....
    Zeig du wie manns besser macht! 😉



  • N290 schrieb:

    Wenn du damit meine meinst ok 🙂
    Aber wenn du die Version von MGOS meinst....
    Zeig du wie manns besser macht! 😉

    Wurde doch schon geklärt 😉
    - Nicht immer alle Segmente verschieben sondern die Runden zählen und dann so was machen:

    DrawBlock(hwnd, old_pos[round % len], COLOR_GROUND);
    

    - Wenn die Schlange die Richtung 'w' hat darf sie im nächsten Schritt nicht die Richtung 's' haben. Das sollte man überprüfen.
    - Für die repräsentation der Schlange würde sich COORD ( http://msdn.microsoft.com/en-us/library/ms682119 ) anbieten.
    - Für ein so eindeutiges C-Stil Programm sollte man printf statt std::cout nutzen.
    - Globale Variablen sind pfui! (Und wenn man sie mal brauchen sollte dann bitte static)
    - Die momentane Struktur bietet keine Möglichkeit verschiedene Wände zu implementieren. (Auch nicht das "auf der anderen Seite der Karte wieder raus kommen")
    - Nach "if" einrücken 😉

    if (foo)
      bar()
    

    - Am besten gleich noch englische Bezeichner nehmen.
    - Über das schließen der Konsole gibts nen FAQ Eintrag ( http://www.c-plusplus.net/forum/111042 ) man siehe dort Lösung 3.

    Das wars erstmal, nur Kleinigkeiten aber die gehören halt dazu 😃



  • Hier, ich habe einige Sachen geändert:
    1. Nur wenige Globale Variable
    2. englische Bezeichnungen
    3. Ringspeicher
    4. Möglichkeit für zusätzliche Wände
    5. {} und einfache If eingerückt

    #include <iostream>  
    #include <windows.h> 
    #include <conio.h>   
    
    using namespace std;
    
    void gotoxy(int x,int y);
    void setfood(void);
    
    bool board[40][20];
    int fx, fy;
    
    int main()
    {
        int snake[1000][2];
        int length = 1;
        int head = 1;
        int tail = 0;
        int hx = 1;
        int hy = 2;
        int hor = 1;
        int ver = 0;
        char key;
        int i,j;
        snake[tail][0] = hx;
        snake[tail][1] = hy;
        bool gameover = false;
        system("cls");
        for (i = 0; i < 40; i++)
        {
            gotoxy(i,0);
            cout << "+";
            gotoxy(i,19);
            cout << "+";
            board[i][0] = 1;
            board[i][19] = 1;
            for (j = 1; j < 19; j++)
            {
                if (i == 0 || i == 39)
                {
                   gotoxy(i,j);
                   cout << "+";
                   gotoxy(i,j);
                   cout << "+";
                   board[i][j] = 1;
                }
                else
                    board[i][j] = 0;
            }
        }
        setfood();
        while (!gameover)
        {
              if (kbhit())
              {
                    key = getch();
                    switch (key)
                    {
                        case 'd':
                             hor = 1;
                             ver = 0;
                             break;
                        case 'a':
                             hor = -1;
                             ver = 0;
                             break;
                        case 's':
                             hor = 0;
                             ver = 1;
                             break;
                        case 'w':
                             hor = 0;
                             ver = -1;
                             break;
                    }
              }
              hx += hor;
              hy += ver;
              if (board[hx][hy])
                   gameover = true;
              else 
              {
                   gotoxy(hx,hy);
                   cout << "O";
                   board[hx][hy] = 1;
                   snake[head][0] = hx;
                   snake[head][1] = hy;
                   head++;
                   if (head >= 1000)
                      head = 0;
                   if (hx == fx && hy == fy)
                   {
                          setfood();
                          length++;
                   }
                   else
                   {
                       board[snake[tail][0]][snake[tail][1]] = 0;
                       gotoxy(snake[tail][0],snake[tail][1]);
                       cout << " ";
                       tail++;
                       if (tail >= 1000)
                           tail = 0;
                   }
              }
              Sleep(100);
        }
        system("cls");
        cout << "Game Over!" << endl << endl
             << "Score: " << length << endl << endl
             << "Press ENTER to quit... ";
        getchar();
    }
    void gotoxy(int x,int y)
    { 
       COORD cur={x,y}; 
       SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),cur); 
    }
    void setfood(void)
    {
         srand(time(NULL));
         do
         {
             fx =(rand()%38)+1; 
             fy =(rand()%18)+1;
         } while(board[fx][fy]);
         gotoxy(fx,fy);
         cout << "*";
    }
    

    Auf cout habe ich nicht verzichtet, zwar ist vieles eindeutig C-Stil, aber das braucht wieder zusätzlich Bibliotheken, wenn man sowieso iostream braucht (wen's stört, der kann's ändern).

    Das mit der gegensätzigen Richtung ist auch im Original drin, dann beist sich eben die Schlange selbst → Game Over.



  • Ich würde als Erstes:

    1. anstelle von cout direkt eine Konsolenfunktion für die Ausgabe benutzen

    2. anstelle board zu verwalten (soweit ich das überblicke, wird dieses Array nur zur Kollisionsüberprüfung benötigt), direkt via Konsolenfunktion auslesen, ob/was an der entsprechenden Stelle steht

    3. srand gehört ein einziges Mal ausgeführt, deshalb raus da und einmal zu Beginn von main aufrufen



  • @MGDOS schöner Code!
    Danke für Posten!
    🙂

    @cooky Ok.... das hab ich jetzt nicht erwartet 😉



  • Belli schrieb:

    Ich würde als Erstes:

    1. anstelle von cout direkt eine Konsolenfunktion für die Ausgabe benutzen

    2. anstelle board zu verwalten (soweit ich das überblicke, wird dieses Array nur zur Kollisionsüberprüfung benötigt), direkt via Konsolenfunktion auslesen, ob/was an der entsprechenden Stelle steht

    3. srand gehört ein einziges Mal ausgeführt, deshalb raus da und einmal zu Beginn von main aufrufen

    1. Stimmt wir sind ja hier im Windows Forum, das wäre natürlich optimal.
    2. Hm.. ich würde das so lassen 😃
    3. 👍 Gar nicht gesehen.

    @MGOS
    In Snake darf man die Richtung aber einfach nicht umkehren. Diese "falsche" Eingabe muss also ignoriert werden und darf nicht mit Spielende bestraft werden. Das gehört bei Snake halt einfach dazu 😉

    Zudem brauchst Du für printf keine extra header. <iostream> raus und <stdio.h> rein. Aber wie gesagt, direkte API Ausgabe ist natürlich die beste Lösung.

    Edit:
    bool ist auch C++, das muss raus 😃
    Zudem sind immer noch globale Variablen am Start -> könnte man aber problemlos als Parameter übergeben.


Anmelden zum Antworten