Dateiausleseklasse funktioniert einzeln aber nicht in Projekt



  • Hi,
    ich habe mit (größerer) Hilfe hier aus dem Forum eine Klasse zum Auslesen von Dateien geschrieben. Die Klasse an sich funktioniert. Ich habe ein kleines Spiel geschrieben, dass so seine Konfiguration laden soll. Lade ich aber die Konfigurationsdatei mit folgendem Inhalt:

    Ändere alle Parameter, die du ändern möchtest.
    Füge keine Kommas, bzw. Kommazahlen und keine negativen Zahlen ein!

    screen resolution: 10x5
    windowed: no
    ai-level: 2 (max. 3)
    gamespeed: 0.1
    points to win: 12

    Bitte ändere keinen weiteren Text in dieser Datei oder NewPong wird nicht
    mehr korrekt funktionieren.

    Dazu habe ich eine Auslesefunktion, die sich der Dateiausleseklasse bedient:

    #include "ConfigLoader.h"
    #include "Starten.h"
    
    void Starten(int& ScreenX, int& ScreenY, bool& windowed, int& Schwierigkeit, double& Geschwindigkeit, int& Gewinnpunkte, int& SpielfeldX, int& SpielfeldY, int& SpielfeldversatzX, int& SpielfeldversatzY)
    {
        //Standardwerte, falls bestimmte Variablen nicht geladen werden können
        ScreenX = 640;
        ScreenY = 480;
        windowed = false;
        Schwierigkeit = 2;
        Geschwindigkeit = 1.0;
        Gewinnpunkte = 10;
        SpielfeldX = 640;
        SpielfeldY = 480;
        SpielfeldversatzX = 0;
        SpielfeldversatzY = 0;
    
        ConfigLoad Konfiguration("config.txt");
        while (Konfiguration.ReadNextLine())
        {
            if(Konfiguration.FoundString("screen resolution:"))
            {
                std::string::size_type Position;
                Position = Konfiguration.StringPos("screen resolution:") + 19;
                ScreenX = Konfiguration.ReadInt(Position);
                if (Konfiguration.FoundString("x"))
                {
                    Position = Konfiguration.StringPos("x") + 1;
                    ScreenY = Konfiguration.ReadInt(Position);
                }
            }
    
            if(Konfiguration.FoundString("windowed:"))
            {
                if(Konfiguration.FoundString("yes"))
                    windowed = true;
            }
    
            if(Konfiguration.FoundString("ai-level:"))
            {
                std::string::size_type Position;
                Position = Konfiguration.StringPos("ai-level:") + 10;
                Schwierigkeit = Konfiguration.ReadInt(Position);
            }
    
            if(Konfiguration.FoundString("gamespeed:"))
            {
                std::string::size_type Position;
                Position = Konfiguration.StringPos("gamespeed:") + 11;
                Geschwindigkeit = Konfiguration.ReadDouble(Position);
            }
    
            if(Konfiguration.FoundString("points to win:"))
            {
                std::string::size_type Position;
                Position = Konfiguration.StringPos("points to win:") + 15;
                Gewinnpunkte = Konfiguration.ReadInt(Position);
            }
        }
    
        //SpielfeldX/Y und Spielfeldversatz X/Y bestimmen
        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;
    }
    

    Das obskure ist, lese ich die config.txt Datei in einem Testprogramm mit dieser Funktion aus und lasse mir alles in der Konsole ausgeben, liest sie korrekt sämtliche Werte aus. Verwende ich aber die Funktion in meinem kleinen Spiel, so enthalten alle Variablen Unfug. Ich kann mir leider, weil das Spiel über SDL läuft keine Variablenwerte ausgeben lassen, aber z.B. die Integervariable Gewinnpunkte, welche den Wert 12 haben sollte, den sie auch im Beispielprogramm hat, scheint keinen gültigen Zahlwert zu enthalten. Will ich mit ihr eine for-Schleife durchführen, wird diese direkt übersprungen:

    for(int test = 0; test < Gewinnpunkte; test++)
    {
    //Hier kommt das Programm nie hin
    }
    

    Ich bin im Moment ziemlich ratlos, vor allem da sowohl die Ausleseklasse, wie auch die Auslesefunktion einzeln tadellos funktionieren. Hier nochmal die Einbindung der Auslesefunktion. Auch wenn ich dort keinen Fehler vermute:

    #include <cstdlib>
    #include "C:/Programme/CodeBlocks/SDL-1.2.13/include/SDL.h"
    #include "Spieler.h"
    #include "Ball.h"
    #include "ConfigLoader.h"
    #include "Starten.h"
    #include "Punktestand_zeichnen.h"
    #include "Mittellinie_zeichnen.h"
    #include "Kollisionsabfrage.h"
    
    using namespace std;
    
    //Globale Variablen
    int ScreenX = 640;
    int ScreenY = 480;
    bool windowed = true;
    int Schwierigkeit = 2;
    double Geschwindigkeit = 1.0;
    int Gewinnpunkte = 5;
    int SpielfeldX = 640;
    int SpielfeldY = 480;
    int SpielfeldversatzX = 0;
    int SpielfeldversatzY = 0;
    
    int main(int argc, char *argv[])
    {
    
    //anderes Zeug
    
    Starten(ScreenX, ScreenY, windowed, Schwierigkeit, Geschwindigkeit, Gewinnpunkte, SpielfeldX, SpielfeldY, SpielfeldversatzX, SpielfeldversatzY);
    
    //und weiter gehts
    }
    

    Ich hoffe sehr, jemand wird aus dem Problem schlau. Ich bin noch ziemlich C++-Unerfahren und dieses kleine Spiel beschäftigt mich jetzt schon fast ein halbes Jahr. Bisher sieht es so aus, als wäre das Nichtfunktionieren des Auslesens der Konfigurationsdatei der letzte Fehler im Programm. Wäre echt froh, wenn ich es endlich fertig stellen könnte. 🙂


  • Mod

    Ich kann mir eine Menge mögliche Fehlerquellen vorstellen, aber spontan fällt mir nichts auf. Dein Quelltext ist ein bisschen lang, kannst du versuchen das auf ein minimales Beispiel zu kürzen, das den Fehler zeigt?

    Ansonsten der Supertipp: Wenn du das Programm mit einem Debugger durchgehst, wirst du diese Sorte von Fehlern sehr sehr schnell finden.



  • Das Problem ist, ich weiß nicht, wo genau der Fehler liegt. Das mit dem Debugger ist ne gute Idee. Muss ich erstmal schauen, wie der von Code::Blocks funktioniert.



  • Wie berichtet ConfigLoad über Fehler? Wirft es Exceptions oder läuft das Programm einfach stillschweigend weiter, wenn zB "config.txt" gar nicht existiert?
    Code::Blocks ist eine IDE und hat keinen Debugger, sondern benutzt einen, z.B. gdb. Zum Debuggen kompilierst du mit DEBUG Einstellungen und startest dann Debug->Start (F8). Vorher setzt Du z.B. in Zeilen 19, 21, 33 usw. Haltepunkte, dann siehst Du genau was passiert.



  • ConfigLoad meldet über std::cerr, wenn eine Datei nicht öffnen geht. Andere Fehlerausgaben sind nicht vorgesehen. Versucht man halt eine Int, Double oder sonst etwas dort auszulesen, wo keine steht, so liefert ConfigLoad die Variable mit dem Wert 0 zurück. Aber das ist hier ja auch nicht der Fall und wenn ich die Datei in einem einzelnen Projekt auslese funktioniert es auch.

    Hab nen Moment gegoogled, aber entweder bediene ich den Debugger total falsch, oder er geht in meinem Zusammenhang nicht. Ich kann keine Watches setzen, weil die Option in meinem Rechtsklickmenü fehlt, obwohl ich das Watches-Fenster offen habe. Und ich habe Haltepunkte, die einfach ignoriert werden. Das Programm läuft ganz normal ab und in der Debuggerausgabe steht für jeden Haltepunkt:

    Breakpoint 1 ("C:/(Ordner)/Starten.cpp:25) pending.
    Function "C:/(die selben Ordner)" not defined.

    Sorry, ich weiß, das hier ist das allgemeine C++-Forum. Aber weiß vielleicht jemand, wieso mich der Debugger quasie ignoriert? Ohne Debugger werde ich glaube ich nie hinter das Problem kommen, weil ich schon jede Lösung ausprobiert habe. Außer, kann es vielleicht sein, dass ConfigLoad deshalb einzeln und nciht im Projekt funktioniert, weil fstream und SDL nciht kompatibel sind und irgendwelche Funktionen doppelt deklariert sind oder weiß der Kuckuck was? Hab jetzt dazu nichts entsprechendes bei Google gefunden, aber vielleicht weiß jemand was. Hier nochmal die ConfigLoader.cpp und ConfigLoader.h, falls es doch daran liegen sollte:

    #include <iostream>
    #include <fstream>
    #include <sstream>
    #include <string>
    #include <cctype>
    #include "ConfigLoader.h"
    
    ConfigLoad::ConfigLoad(const std::string& filename):
    konfiguration(filename.c_str())
    {
        if(!konfiguration)
            std::cerr << filename << " konnte nicht geoeffnet werden.\n";
    }
    
    bool ConfigLoad::ReadNextLine()
    {
        if(std::getline(konfiguration, puffer))
            return true;
        return false;
    }
    
    bool ConfigLoad::FoundString(const std::string& search) const
    {
        return puffer.find(search) != std::string::npos;
    }
    
    std::string::size_type ConfigLoad::StringPos(const std::string& search) const
    {
        return puffer.find(search);
    }
    
    int ConfigLoad::ReadInt(std::string::size_type nPosition) const
    {
        int ret_int(0);
        for(std::string::size_type beg(nPosition), end(puffer.size()); beg < end; ++beg) {
            if(!isdigit(puffer[beg]) || beg + 1 == end) {
                std::istringstream iss(puffer.substr(nPosition, beg + 1));
                iss >> ret_int;
                break;
            }
        }
        return ret_int;
    }
    
    double ConfigLoad::ReadDouble(std::string::size_type nPosition) const
    {
        double ret_double(0.0);
        for(std::string::size_type beg(nPosition), end(puffer.size()); beg < end; ++beg) {
            if((!isdigit(puffer[beg]) && puffer[beg] != '.') || beg + 1 == end) {
                std::istringstream iss(puffer.substr(nPosition, beg + 1));
                iss >> ret_double;
                break;
            }
        }
        return ret_double;
    }
    
    std::string ConfigLoad::ReadString(std::string::size_type nPosition) const
    {
        std::ostringstream oss;
        for(std::string::size_type beg(nPosition), end(puffer.size()); beg < end; ++beg) {
            if(isspace(puffer[beg]) || beg + 1 == end) {
                oss.str(puffer.substr(nPosition, beg + 1));
                break;
            }
        }
        return oss.str();
    }
    
    #ifndef CONFIGLOADER_H
    #define CONFIGLOADER_H
    
    #include <fstream>
    #include <string>
    
    class ConfigLoad
    {
    public:
        ConfigLoad(const std::string& filename);
        bool ReadNextLine();
        bool FoundString(const std::string& search) const;
        std::string::size_type StringPos(const std::string& search) const;
        int ReadInt(std::string::size_type nPosition) const;
        double ReadDouble(std::string::size_type nPosition) const;
        std::string ReadString(std::string::size_type nPosition) const;
    private:
        std::string puffer;
        std::ifstream konfiguration;
    };
    
    #endif // CONFIGLOADER_H
    

    Ich hoffe das funktioniert bald. 😞



  • So, jetzt habe ich Ergebnisse. Keine Ahnung, wieso der Debugger sienen dienst verweigert, aber über std::cerr kann ich auch ohne Konsole Variablen ausgeben. Also habe ich mir am Ende der Funktion Starten(...); mal alle Variablen aussprucken lassen und dann in der config.txt geändert. Und dann habe ich das Problem erkannt. Ich versuchs mal bildgrafisch zu erklären:

    C:/.../Projektordner/config.txt <-- ist dort für die abschließende Version
    C:/.../Projektordner/bin/Debug/NewPong.exe <-- ist die aktuelle .exe
    C:/.../Projektordner/bin/Debug/config.txt <-- ist die aktuelle Konfiguration

    Ich öffne mit fstream "config.txt" ohne irgendeinen Pfad. Eigneltich sollte es ja die config.txt im selben Ordner wie die .exe sein, aber da die Debugversion nicht einzeln, sondern über Code::Blocks läuft, öffnet dieses die config.txt im Projektordner. Mein programm öffnet quasie die falsche config.txt, was auch irgendwie verwirrend gemacht ist.

    Danke für's Kopfzerbrechen 😉


Anmelden zum Antworten