SDL funktioniert nicht, wenn nach anderer Funktion aufgerufen wird



  • So sieht der Quelltext bis nach dem Start von SDL komplett aus. Man kann das starten aber auch gleidch an den Anfang von int main() stellen, dann verhält sich das Programm identisch. Und wie schon gesagt, der Variablen Screenx und ScreenY sind keine mögliche Fehlerquelle, weil ich auch direkt Zahlenwerte einsetzen kann und es in Kombination mit Starten(); trotzdem nicht geht.

    #include <stdlib.h>
    #include <SDL/SDL.h>
    //#include <cmath>
    //#include <time.h>
    //#include <fstream>
    
    //Variablen deklarieren
    
    bool laeuft = true;
    bool windowed = true;
    bool tastegedrueckt = false;
    bool ballmussneu = false; //Wenn jemand Punkt gemacht hat, damit neu eingesetzt wird
    const char Programmname[7] = {'N','e','w','P','o','n','g'};
    int ScreenX = 1024;
    int ScreenY = 768;
    int Schwierigkeit = 0;
    int Gewinnpunkte = 0;
    int SpielfeldX = 0;
    int SpielfeldY = 0;
    int SpielfeldversatzX = 0;
    int SpielfeldversatzY = 0;
    int Punkte1 = 0;
    int Punkte2 = 0;
    double BallSpeedX = 0.00001;
    double BallSpeedY = 0;
    double Speed1 = 0; //Spieler brauchen nur einen Speed, da ja nur in eine Richtung bewegen
    double Speed2 = 0;
    //Folgende 2 für fließendere Bewegungen
    double BallX = 0;
    double BallY = 0;
    
    #include "Spiel_starten.h"
    #include "Punktestand_zeichnen.h"
    using namespace std;
    
    int main(int argc, char *argv[])
    {
    	//Spiel starten	
    	//Programm initialisieren	
    	SDL_Surface *screen, *icon;
    	SDL_Rect ball, player1, player2, mittellinie, punkte;
    	SDL_Event event;
    	Uint8 *keys;
    	if (SDL_Init(SDL_INIT_VIDEO) == -1) {
        	printf("SDL konnte nicht initialisiert werden:  %s\n", SDL_GetError());
        	exit(1);
    	}
    	atexit(SDL_Quit);
    
        Starten(&ScreenX, &ScreenY, &windowed, &Schwierigkeit, &Gewinnpunkte, &SpielfeldX, &SpielfeldY, &SpielfeldversatzX, &SpielfeldversatzY); 
        //Bildoberfläche erstellen
    	if (!windowed)
    	{
    	   	screen = SDL_SetVideoMode(1024, 768, 32, SDL_FULLSCREEN | SDL_DOUBLEBUF);
    	   	SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
    	   	if (screen == NULL) {
    	   	    printf("Videomodus konnte nicht geladen werden: %s\n", SDL_GetError());
    	   	    exit(1);
    	   	}
    	} else {
    		//Fenstertitel definieren
    		SDL_WM_SetCaption (Programmname, Programmname);
    		//Fenstericon festlegen
    		icon = SDL_LoadBMP ("icon.bmp");
    		//Hintergrund des Icons transparent färben.
    		SDL_SetColorKey(icon, SDL_SRCCOLORKEY, SDL_MapRGB(icon->format, 255, 0, 0));
    		SDL_WM_SetIcon (icon, NULL);
    
    		//Programmfenster als Icon darstellen
    		SDL_WM_IconifyWindow ();
    
    		screen = SDL_SetVideoMode(ScreenX, ScreenY, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
    	  	SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
    	  	if (screen == NULL) {
    	  	    printf("Videomodus konnte nicht geladen werden: %s\n", SDL_GetError());
    	  	    exit(1);
    	   	}
    	}
    


  • Was tut denn diese ominöse Funktion Starten? Kommt die überhaupt mal zurück?



  • Sie liest eine Textdatei aus und ändert die Werte der Variablen entsprechend. Zurückkehren? Muss sie das denn? Am Ende der Funktion läuft das Programm doch automatisch weiter, oder?



  • Little Programmer schrieb:

    Zurückkehren? Muss sie das denn? Am Ende der Funktion läuft das Programm doch automatisch weiter, oder?

    Sie muss nicht explizit, also mit einer return-Anweisung, zurückkehren. Aber sie muss es tun. Wenn da drin eine Endlosschleife steckt, oder auf irgendetwas gewartet wird, was nicht eintritt, würde das das geschilderte Verhalten erklären.

    Da du aber auch nach dreimaliger Aufforderung diese Funktion noch immer nicht gezeigt hast, wird die weitere Fehlersuche wohl an dir hängen bleiben.



  • Sorry, 🙄, hab's irgendwie nicht mitbekommen, dass du auch den Quelltext der Funktion an sich wolltest und einfach so wollt ich ihn dir nicht an den kopf knallen, weils, wie du unten siehst, etwas länger ist. Bitte geb mich deswegen nicht auf. Die Funktion lautet:

    #include "Konfiguration_laden.h"
    #include "Spielfeld_skalieren.h"
    #include "Spiel_starten.h"
    using namespace std;
    
    void Starten(int* ScreenX, int* ScreenY, bool* windowed, int* Schwierigkeit, int* Gewinnpunkte, int* SpielfeldX, int* SpielfeldY, int* SpielfeldversatzX, int* SpielfeldversatzY)
    {
    
    //Konfigurationen laden
    //ScreenX = 1024;
    //ScreenY = 768;
    //windowed = true;
    //Schwierigkeit = 1;
    //Gewinnpunkte = 9;
    
    if (Auslesen(ScreenX, ScreenY, windowed, Schwierigkeit, Gewinnpunkte) < 4)
    {
    	//Funktion hierfür finden: printf("Konfigurationen konnten nicht gelesen werden!");
    }
    
    Skalieren(ScreenX, ScreenY, SpielfeldX, SpielfeldY, SpielfeldversatzX, SpielfeldversatzY);
    }
    

    Die Unterfunktion Auslesen:

    #include <fstream>
    //Funktionen laden
    #include "Bildschirmaufloesung_auslesen.h"
    #include "Fenstermodus_auslesen.h"
    #include "Schwierigkeit_auslesen.h"
    #include "Gewinnpunkte_auslesen.h"
    #include "Konfiguration_laden.h"
    using namespace std;
    
    int Auslesen (int* ScreenX, int* ScreenY, bool* windowed, int* Schwierigkeit, int* Gewinnpunkte)
    {
    //Konfiguration laden
    int configLaenge = 0;
    char AktuellesTextstueck[20];
    int VorgegangeneZeichen = 0;
    int Position = 0;
    //config.txt auslesen
    ifstream Konfiguration("config.txt", ios::in);
    
    //Länge der Datei ermitteln
    Konfiguration.seekg(0, ios::end);
    configLaenge = Konfiguration.tellg();
    
    //An Beginn springen
    Konfiguration.seekg(0, ios::beg);
    
    bool confwirdgelesen = true;
    int Konfigurationen = 0;
    while (confwirdgelesen)
    {
    	//20 Zeichen langes Textstück auslesen
    	for (int textpos = 0; textpos < 20; textpos++)
    	{
    		AktuellesTextstueck[textpos] = Konfiguration.get();
    		Konfiguration.seekg(1, ios::cur);
    		Position++;
    	}
    
    	//Beenden, wenn an Dateiende oder fertig mit auslesen	
    	if (Konfiguration.tellg() > configLaenge)
    	{
    	confwirdgelesen = false;
    	}
    
    	if (Konfigurationen == 4)
    	{
    	confwirdgelesen = false;
    	}
    
    	//config.txt schließen
    	Konfiguration.close();
    
    	//Vergleichen, ob eine der Einstellungen erreicht ist
    
    	Konfigurationen = Konfigurationen + Aufloesung(&Position, AktuellesTextstueck, ScreenX, ScreenY);
    	Konfigurationen = Konfigurationen + Fenstermodus(&Position, AktuellesTextstueck, windowed);
    	Konfigurationen = Konfigurationen + Schwierigkeitsauslesung(&Position, AktuellesTextstueck, Schwierigkeit);
    	Konfigurationen = Konfigurationen + Gewinnpunktauslesung(&Position, AktuellesTextstueck, Gewinnpunkte);
    
    	//Zurücksetzen, damit nächster Textabschnitt ein Zeichen nach letzem beginnt
    	VorgegangeneZeichen++;
    	Position = VorgegangeneZeichen;
    }
    return Konfigurationen;
    }
    

    Die Unterfunktion Skalieren:

    #include "Spielfeld_skalieren.h"
    
    void Skalieren(int* ScreenX, int* ScreenY, int* SpielfeldX, int* SpielfeldY, int* SpielfeldversatzX, int* SpielfeldversatzY)
    {
    //Spielfeld an gewählte Auflösung anpassen
    double XVerhaeltnis = *ScreenX/1024;
    double YVerhaeltnis = *ScreenY/768;
    
    //Wenn die X-Seite im normalen Bildschirmverhältnis länger als die Y-Seite ist:
    if (XVerhaeltnis > YVerhaeltnis)
    {
    	*SpielfeldX = (*ScreenY/768) * 1024;
    	*SpielfeldY = *ScreenY;
    }
    
    //Wenn die Y-Seite im normalen Bildschirmverhältnis länger als die Y-Seite ist:
    if (XVerhaeltnis < YVerhaeltnis)
    {
    	*SpielfeldY = (*ScreenX/1024) * 768;
    	*SpielfeldX = *ScreenX;
    }
    
    //Wenn beide Seiten im normalen Bildschirmverhältnis gleich lang sind:
    if (XVerhaeltnis == YVerhaeltnis)
    {
    	*SpielfeldX = *ScreenX;
    	*SpielfeldY = *ScreenY;
    }
    
    //Spielfeldversatz bestimmen
    *SpielfeldversatzX = (*ScreenX - *SpielfeldX) / 2;
    *SpielfeldversatzY = (*ScreenY - *SpielfeldY) / 2;
    }
    

    und noch die ganzen Unterfunktionen von Auslesen:

    Bildschirmauflösung auslesen:

    #include <fstream>
    #include "Bildschirmaufloesung_auslesen.h"
    using namespace std;
    
    int Aufloesung(int* Position, char AktuellesTextstueck[20], int* ScreenX, int* ScreenY)
    {
    int Uebereinstimmung = 0;
    int Funktioniert = 0;
    char aufloesung[18] = {'s','c','r','e','e','n',' ','r','e','s','o','l','u','t','i','o','n',':'};
    //Bildschirmauflösung auslesen
    for (int x = 0; x < 18; x++)
    {
    	if (AktuellesTextstueck[x] == aufloesung[x])
    	{			
    		Uebereinstimmung++;
    	}
    }
    if (Uebereinstimmung == 18)
    {
    	//Bildschirmauflösung auslesen, dazu erst zurück, ein Feld hinter das 18te
    	ifstream Konfiguration("config.txt", ios::in);
    	Konfiguration.seekg(*Position, ios_base::beg);
    
    	//Leerzeichen überspringen
    	while (Konfiguration.get() == ' ')
    	{
    		Konfiguration.seekg(1, ios_base::cur);
    	}
    
    	//X-Zahl auslesen
    	for (int zahlpos = 0; zahlpos < 20; zahlpos++)
    	{
    		if (Konfiguration.get() != 'x')
    		{
    			AktuellesTextstueck[zahlpos] = Konfiguration.get();
    		} else {
    			AktuellesTextstueck[zahlpos] = ' ';
    			zahlpos = 20;
    		}
    		Konfiguration.seekg(1, ios_base::cur);
    	}
    
    	//Text in Zahl umwandeln
    	*ScreenX = atoi (AktuellesTextstueck);
    
    	//Y-Zahl auslesen
    	for (int zahlpos = 0; zahlpos < 20; zahlpos++)
    	{
    		if (Konfiguration.get() != 'x')
    		{
    			AktuellesTextstueck[zahlpos] = Konfiguration.get();
    		} else {
    			AktuellesTextstueck[zahlpos] = ' ';
    			zahlpos = 20;
    		}
    		Konfiguration.seekg(1, ios_base::cur);
    	}
    
    	//Schließen
    	Konfiguration.close();
    
    	//Text in Zahl umwandeln
    	*ScreenY = atoi (AktuellesTextstueck);
    
    	//Konfiguration erfolgreich geladen
    	Funktioniert++;
    }
    Uebereinstimmung = 0;
    return Funktioniert;
    }
    

    Fenstermodus auslesen, also ob im Vollbild oder Fenster gespielt werden soll:

    #include <fstream>
    #include "Fenstermodus_auslesen.h"
    using namespace std;
    
    int Fenstermodus(int* Position, char AktuellesTextstueck[20], bool* windowed)
    {
    int Uebereinstimmung = 0;
    int Funktioniert = 0;
    char fenster[9] = {'w','i','n','d','o','w','e','d',':'};
    //Fenstermodus auslesen
    for (int x = 0; x < 9; x++)
    {
    	if (AktuellesTextstueck[x] == fenster[x])
    	{			
    		Uebereinstimmung++;
    	}
    }
    if (Uebereinstimmung == 9)
    {
    	//Fenstermodus auslesen, dazu erst zurück, ein Feld hinter das 9te
    	ifstream Konfiguration("config.txt", ios::in);
    	Konfiguration.seekg(*Position, ios_base::beg);
    
    	//Leerzeichen überspringen
    	while (Konfiguration.get() == ' ')
    	{
    		Konfiguration.seekg(1, ios_base::cur);
    	}
    
    	//Wenn mit y beginnt, also yes erwartet wird, wird Fenstermodus aktiviert
    	if ((Konfiguration.get() == 'y') || (Konfiguration.get() == 'Y'))
    	{
    		*windowed = true;
    	}
    
    	//Schließen
    	Konfiguration.close();
    
    	//Konfiguration erfolgreich geladen
    	Funktioniert++;
    }
    Uebereinstimmung = 0;
    return Funktioniert;
    }
    

    Schwierigkeitsgrad auslesen:

    #include <fstream>
    #include "Schwierigkeit_auslesen.h"
    using namespace std;
    
    int Schwierigkeitsauslesung(int* Position, char AktuellesTextstueck[20], int* Schwierigkeit)
    {
    int Uebereinstimmung = 0;
    int Funktioniert = 0;
    char schwierigkeit[11] = {'d','i','f','f','i','c','u','l','t','y',':'};
    //Schwierigkeit auslesen
    for (int x = 0; x < 11; x++)
    {
    	if (AktuellesTextstueck[x] == schwierigkeit[x])
    	{			
    		Uebereinstimmung++;
    	}
    }
    if (Uebereinstimmung == 11)
    {
    	//Schwierigkeit auslesen, dazu erst zurück, ein Feld hinter das 11te
    	ifstream Konfiguration("config.txt", ios::in);
    	Konfiguration.seekg(*Position, ios_base::beg);
    
    	//Leerzeichen überspringen
    	while (Konfiguration.get() == ' ')
    	{
    		Konfiguration.seekg(1, ios_base::cur);
    	}
    
    	//Schwierigkeit auslesen
    	for (int zahlpos = 0; zahlpos < 20; zahlpos++)
    	{
    		if (Konfiguration.get() != ' ')
    		{
    			AktuellesTextstueck[zahlpos] = Konfiguration.get();
    		} else {
    			AktuellesTextstueck[zahlpos] = ' ';
    			zahlpos = 20;
    		}
    		Konfiguration.seekg(1, ios_base::cur);
    	}
    
    	//Schließen
    	Konfiguration.close();
    
    	//Text in Zahl umwandeln
    	*Schwierigkeit = atoi (AktuellesTextstueck);
    
    	//Konfiguration erfolgreich geladen
    	Funktioniert++;
    }
    Uebereinstimmung = 0;
    return Funktioniert;
    }
    

    Nötige Punkte für Spielsieg auslesen:

    #include <fstream>
    #include "Gewinnpunkte_auslesen.h"
    using namespace std;
    
    int Gewinnpunktauslesung(int* Position, char AktuellesTextstueck[20], int* Gewinnpunkte)
    {
    int Uebereinstimmung = 0;
    int Funktioniert = 0;
    char gewinn[14] = {'p','o','i','n','t','s',' ','t','o',' ','w','i','n',':'};
    //Gewinnpunkte auslesen
    for (int x = 0; x < 14; x++)
    {
    	if (AktuellesTextstueck[x] == gewinn[x])
    	{			
    		Uebereinstimmung++;
    	}
    }
    if (Uebereinstimmung == 14)
    {
    	//Gewinnpunkte auslesen, dazu erst zurück, ein Feld hinter das 11te
    	ifstream Konfiguration("config.txt", ios::in);
    	Konfiguration.seekg(*Position, ios_base::beg);
    
    	//Leerzeichen überspringen
    	while (Konfiguration.get() == ' ')
    	{
    		Konfiguration.seekg(1, ios_base::cur);
    	}
    
    	//Gewinnpunkte auslesen
    	for (int zahlpos = 0; zahlpos < 20; zahlpos++)
    	{
    		if (Konfiguration.get() != ' ')
    		{
    			AktuellesTextstueck[zahlpos] = Konfiguration.get();
    		} else {
    			AktuellesTextstueck[zahlpos] = ' ';
    			zahlpos = 20;
    		}
    		Konfiguration.seekg(1, ios_base::cur);
    	}
    
    	//Schließen
    	Konfiguration.close();
    
    	//Text in Zahl umwandeln
    	*Gewinnpunkte = atoi (AktuellesTextstueck);
    
    	//Konfiguration erfolgreich geladen
    	Funktioniert++;
    }
    Funktioniert = 0;
    return Funktioniert;
    }
    


  • OMG 🙂



  • Little Programmer schrieb:

    Die Unterfunktion Auslesen:

    Prüf doch mal, ob diese while-Schleife tatsächlich verlassen wird.



  • Oh ja, hätte ich nicht gedacht, vielen Dank. Das war es. Ka, wieos die while-Schleife nicht beendet wird, aber das lässt sich herausfinden und jetzt weiß ich schonmal, woran es hängt. Danke. 🙂



  • Nur mal einige Verbesserungsmöglichkeiten zu deinem Programm:

    • weniger globale Variablen
    • mehr Klassen. Eine Vektorklasse würde dich schon mal davor bewahren, X und Y immer separat zu übergeben.
    • mehr Funktionen
    • vor allem kürzere Funktionen
    • Variablen dann deklarieren, wenn man sie braucht
    • Stringliterale statt Array-Initialisierungslisten mit vergessener Nullterminierung
    • Zusammengesetzte Operatoren += statt Operation und Zuweisung + und =
    • Du programmierst C++! Also nutze die Möglichkeiten. Zu Klassen habe ich schon etwas gesagt, etwas mehr Standardbibliothek würde auch nicht schaden.

    Wie gesagt, das sind nur einige der Punkte.



  • Sorry, vielleicht lachst du jetzt, aber ich bin Anfänger und hab etwa einen Zentimeter in einem C++ Buch bisher gelesen, weiter kam ich noch nicht. Ich weiß nichtmal, was eine Klasse ist. Ich hab mir aber vorgenommen, in den nächsten zwei Wochen zumindest mein Anfängerbuch mal durchzulesen.
    Globale Variablen und das deklarieren von Variablen am Dateianfang finde ich eigentlich praktisch. Wenn etwas nicht zufriedenstellend funktioniert und ich die Variable ändern möchte, muss ich sie nicht lange suchen, sondern weiß sofort, wo sie steht. Wie macht man das denn sonst, wenn die Variablen alle irgendwo im Quelltext deklariert werden?

    Ich werd versuchen, in nächster Zeit mehr C++ zu lernen und meine Quelltexte zu verbessern.


Anmelden zum Antworten