Snake in C Programmieren (Schlange wachsen lassen)
-
Ich werde mir mal deine Punkte anschauen. Schon mal vielen Dank für die Hilfe. Ja das Problem ist, dass die Schlange nicht wächst.
-
weiter:
zeichne_zufallswaende(): Wenn du Pech hast wird Futter mit Wand überschrieben.Konstanten schreibt man eigentlich per Konvention in Großbuchstaben.
Die feste Größe ist etwas ungünstig, wenn das Fenster zu klein ist entsteht Chaos. Man kann per Windows-API die Fenstergröße abfragen oder auch setzen (Code auf Anfrage), ist aber aktuell vielleicht nicht Priorität Nr. 1...
gut: Alles mögliche konfigurierbar per #define und diese alle an einem Ort ganz oben.
Ich würde die Sache anders strukturieren, dann wird es imho übersichtlicher. Durch Prototypen können die diversen Funktionen nach der main() kommen: Erst das Wesentliche und dann die Details.
Hier mal meine Version. Wie gesagt, über vieles lässt sich diskutieren, jeder hat seine Art. Wichtig ist: Erst mit Papier und Bleistift einen genauen Plan erstellen und dann erst zur Tastatur greifen (was ich aber ehrlich gesagt auch nicht immer mache...).
Für das Schlangenwachstum: Du merkst dir die Positionen der einzelnden Schlangenteile in einem Array. Bei jeder Bewegung schiebst du die Arrayelemente eins weiter nach links und fügst ans Ende die neue Position ein.
#include <stdio.h> #include <conio.h> #include <stdlib.h> #include <windows.h> #include <time.h> //siehe Anmerkung #define HOEHE 40 #define BREITE 70 //hier bietet sich ein typedef enum an #define LEER 0 #define WAND 1 #define SCHLANGE 2 #define FUTTER 3 #define ZEICHEN_WAND '#' #define ZEICHEN_SCHLANGE 'o' #define ZEICHEN_FUTTER '@' #define ANZAHL_FUTTER 5 #define ANZAHL_ZUFALLSWAENDE 10 //fehlte #define MAX_SCHLANGENLAENGE 5 //ja, ich schrieb globale Variablen sind doof, aber manchmal wie hier ersparen sie einem zusätzliche Parameter die in (fast?) jeder Funktion vorkommen. Kann man sicherlich drüber diskutieren... unsigned int Spielfeld[BREITE][HOEHE]; unsigned int Schlangenelemente[MAX_SCHLANGENLAENGE]; //Prototypen void set_cursor_position(const int x, const int y); void initialisiere_spielfeld(void); void erzeuge_futter(const int); void erzeuge_zufallswaende(const int); void erzeuge_schlange(void); void zeige_spielfeld(void); char benutzereingabe(void); void schlange_bewegen_wachsen(const char, int const * ); int main() { char taste; int is_game_over=0; srand((unsigned int)time(NULL)); //initialisiert den Zufallszahlengenerator mit einem "zufälligen" Wert (genannt seed) initialisiere_spielfeld(); erzeuge_zufallswaende(ANZAHL_ZUFALLSWAENDE); //gezeichnet (auf dem Monitor) wird hier nicht erzeuge_futter(ANZAHL_FUTTER); erzeuge_schlange(); do { zeige_spielfeld(); //enthält cursorpos setzen taste = benutzereingabe(); if(taste=='e') //vorzeitig beenden return 0; schlange_bewegen_wachsen(taste, &is_game_over); } while (!is_game_over); set_cursor_position(28, 20); printf("Gamer Over"); _getch(); return 0; }
-
Grmbl. Meine Deklaration von Schlangenelemente ist natürlich falsch. Entweder ein [2] dahinter oder typedef struct nutzen. Jaja, wenn man schnell sein will...
-
Und wieder Mist gebaut:
void schlange_bewegen_wachsen(const char, int * const);und es fehlt int Schlangenlaenge. Ich glaub ich bin erstmal ruhig.
-
Ohne mir jetzt den ganzen Code durchgelesen zu haben, wieso lässt du nicht das Futter verschwinden nachdem es die Schlange "gegessen" hat und erhöhst die Länge der Schlange um 1?
-
Bitmapper schrieb:
erhöhst die Länge der Schlange um 1?
Weil das nicht reichen würde. Wenn Schlangenlaenge nicht global wäre würde der Compiler meckern "unused". Es gibt bisher keine Schlangenwachsfunktion.
-
420815 schrieb:
Bitmapper schrieb:
erhöhst die Länge der Schlange um 1?
Weil das nicht reichen würde. Wenn Schlangenlaenge nicht global wäre würde der Compiler meckern "unused". Es gibt bisher keine Schlangenwachsfunktion.
Ich habe mir das so vorgestellt:
Es gibt eine Variable (von mir aus auch global) die immer die aktuelle Länge der Schlange beinhaltet.
Diese wird um eins erhöht immer wenn die Schlange ein stück Futter "isst" und die Funktion die die Schlange zeichnet, zeichnet sie eben immer so lang wie in der Variable steht.
-
Natürlich, aber das muss halt auch erstmal implementiert werden, ich habe oben ja was dazu geschrieben (Array).
-
Schon mal vielen Dank für eure Hilfe.
Besonders an dich 420815. Mein Hauptproblem ist, dass ich nicht weiß wo und wie ich das Array für die Wachsfunktion einfügen muss. Ich muss ja irgendwie erkennen können, wie lang die Schlange derzeit sein müsste und in welche Richtung die Schlange gerade fährt. Je nach dem muss ich dann entsprechend viele Teile der Schlange anzeigen lassen (natürlich auch noch an der richtigen Stelle) und entsprechend viele Teile löschen. Wo und Wie ich das aber überall reinschreiben muss ist mir ein unlösbar zu scheindendes Rätsel.
Jedenfalls konnte ich dank euch schon mal ein paar kleiner Probleme (bzw. Dinge die zu Problemen werden könnten) beseitigen. Das Hauptproblem besteht aber leider immer noch.
-
Wow. Ich hab das massiv unterschätzt. Hier mal so wie ich es machen würde. Der Code ist UNGETESTET, gcc spuckt aber zumindestens keine Warnungen aus. Kann fehlerhaft sein!!
#define MAX_SCHLANGENLAENGE 5 #define INITIAL_X 1 #define INITIAL_Y 1 #define TASTE_OBEN 'w' #define TASTE_UNTEN 's' typedef struct { signed int x; signed int y; } coord_t; unsigned int Spielfeld[BREITE][HOEHE]; coord_t Schlangenelemente[MAX_SCHLANGENLAENGE]; //von Kopf=[0] bis Schwanz=[MAX_SCHLANGENLAENGE-1] unsigned int LaengeSchlange; void init(void) { LaengeSchlange=1; Schlangenelemente[0].x=INITIAL_X; Schlangenelemente[0].y=INITIAL_Y; } void schlange_bewegen_wachsen(const char taste, int * const is_g_over) { int i; coord_t bewegung; coord_t kopf_neu; coord_t segment_neu; *is_g_over=0; switch(taste) //Annahme: Koordinatensystemursprung ist unten links { case TASTE_OBEN: bewegung.x=0; bewegung.y=1; break; case TASTE_UNTEN: bewegung.x=0; bewegung.y=-1; break; //... default: return; //ungültige Taste -> keine Bewegung -> nix zu tun } kopf_neu.x=Schlangenelemente[0].x+bewegung.x; kopf_neu.y=Schlangenelemente[0].y+bewegung.y; if(Spielfeld[kopf_neu.x][kopf_neu.y]==WAND || Spielfeld[kopf_neu.x][kopf_neu.y]==SCHLANGE) //gegen die Wand gefahren oder gegen sich selber? { *is_g_over=1; return; } else if(Spielfeld[kopf_neu.x][kopf_neu.y]==FUTTER) //wachsen lassen? { if(LaengeSchlange<MAX_SCHLANGENLAENGE) //noch Platz? { //neues Schlangenstück da wo jetzt der Schwanz ist der wegbewegt wird, davon die Koordinaten sichern segment_neu=Schlangenelemente[LaengeSchlange-1]; //bewegen for(i=0;i<LaengeSchlange;i++) { Schlangenelemente[i].x+=bewegung.x; Schlangenelemente[i].y+=bewegung.y; } //verlängern LaengeSchlange++; //und neues Segment einbauen Schlangenelemente[LaengeSchlange-1]=segment_neu; } } else //nur bewegen { for(i=0;i<LaengeSchlange;i++) { Schlangenelemente[i].x+=bewegung.x; Schlangenelemente[i].y+=bewegung.y; } } }
-
Was ich schrieb
Für das Schlangenwachstum: Du merkst dir die Positionen der einzelnden Schlangenteile in einem Array. Bei jeder Bewegung schiebst du die Arrayelemente eins weiter nach links und fügst ans Ende die neue Position ein.
ist falsch. Wenn die Schlange nur bewegt wird ändern sich im Array nur die x und y Werte, da wird nichts verschoben. Das passiert nur wenn die Schlange wächst.
-
Und wieder eine Ungereimtheit: Entweder man zeichnet die Schlangenteile direkt ins Spielfeld, dann muss man in schlange_bewegen_wachsen() auch das mit einbauen. Oder man trennt das und malt bei der Ausgabe erst das komplette Feld und zeichnet dann die Schlange ein, dann fehlt in meiner Hauptschleife nach zeige_spielfeld() (oder zeichne_) noch ein zeige/zeichne_schlange().
-
Mensch 420815, registriere dich doch mal
dann kannst du auch deine Beiträge nachträglich bearbeiten