C++ lernen, Beispiel: RPG (Console)
-
Nathan schrieb:
Komplett falscher Ansatz.
Du kannst nicht dynamisch das OS wechseln.Inwiefern?
Nathan schrieb:
Probiers mal mit _WIN32.
-
origami schrieb:
Nathan schrieb:
Komplett falscher Ansatz.
Du kannst nicht dynamisch das OS wechseln.Inwiefern?
Du willst ja irgendwo aus einer Datei die Einstellung laden.
Und dein clear-Code sieht dann so aus, richtig?void clear_screen(){ if (os == windows) system("CLS"); else system("clear"); }
In diesem Fall mag das ja noch funktionieren, aber nehmen wir mal an du machst das Löschen "richtig", nämlich über die API des OS:
void clear_screen() { if (os == windows) { // Code grad von StackOverflow kopiert, keine Garantie und so COORD topLeft = { 0, 0 }; HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO screen; DWORD written; GetConsoleScreenBufferInfo(console, &screen); FillConsoleOutputCharacterA( console, ' ', screen.dwSize.X * screen.dwSize.Y, topLeft, &written ); FillConsoleOutputAttribute( console, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE, screen.dwSize.X * screen.dwSize.Y, topLeft, &written ); SetConsoleCursorPosition(console, topLeft); } else { // Irgendwelche Linux-API Systemaufrufe, die ich nicht kenne } }
Wenn du nun versuchst, dein Programm unter Linux zu kompilieren, wird sich der Compiler beschweren, da die ganzen Funktionen etc. nicht bekannt sind. Und umgekehrt unter Windows. Die OS Entscheidung muss zur Compiletime ablaufen.
-
Nathan schrieb:
Wenn du nun versuchst, dein Programm unter Linux zu kompilieren, wird sich der Compiler beschweren, da die ganzen Funktionen etc. nicht bekannt sind. Und umgekehrt unter Windows. Die OS Entscheidung muss zur Compiletime ablaufen.
Achso, ja ab einem bestimmten Entwicklungsstand geht das nicht mehr, klar. Aber grafisch will ich erstmal garnichts machen, nichtmal WindowsAPI.
Farben wären zwar auch jetzt schon nett, aber farbiger Text bringt mir nichts, solange ich noch kein Spiel habe das Charaktere/Dateien erstellen/laden/verändern kann.Die "Beta" soll erstmal rein Konsolen-basiert sein. Auch die erste Version einer Karte soll rein ASCII-basiert sein, und auch von der bin ich noch weit entfernt.
Ich will erstmal nur die Basics von C++ verstehen. Es steht im Moment weniger ein "echtes Spiel" im Vordergrund, als das C++ lernen.
-
Wenn du erstmal nur C++ lernen möchtest, dann programmiere ruhig erstmal platformabhängig. Mach dir keine Sorgen, ob das Programm auch unter Linux oder auf deinem Toaster läuft, lern erstmal die Sprache vernünftig. Wenn du ein bisschen weiter bist wirst du von alleine sehen, dass alles was du bisher geschrieben hast sich noch viel besser schreiben lässt.
Und es ist eine sehr gute Idee dich erstmal auf die Konsole zu beschränken!
-
Biolunar schrieb:
Wenn du ein bisschen weiter bist wirst du von alleine sehen, dass alles was du bisher geschrieben hast sich noch viel besser schreiben lässt.
Vorschläge willkommen
-
Nun ja, Nathan hat insofern recht als dass es einfach üblich ist das OS zur Compilezeit zu unterscheiden. Was generell auch Sinn macht, weil du kannst eine für Windows kompilierte .exe eh nicht auf Linux ausführen. Was eine "Settings-Datei" angeht, da würde ich gar nicht erst versuchen irgendetwas in der Datei zu suchen, einfach komplett auslesen und am Ende wieder komplett überschreiben. Am besten so in der Art dass du eine Datei im Stil von
setting1=value1
setting2=value2etc. hast, dann liest du diese Key-Wert Paare einfach in eine std::map, und am Ende des Programms überschreibst du die Datei komplett mit neuen Key-Wert Paaren. (Damit alle Änderungen übernommen werden.) Ich gebe dir hier mal eine Klasse die ich irgendwann mal dafür benutzt habe, aber ich bin mir leider nicht sicher wie viel dir das hilft, denn du scheinst von Klassen und Templates noch nicht so viel Ahnung zu haben. Vielleicht lohnt es doch sich die Sprache noch ein bisschen weiter anzugucken.
#ifndef CONFIGURATION_CLASS_HPP #define CONFIGURATION_CLASS_HPP #include <cctype> #include <string> #include <map> #include <fstream> #include <sstream> class configuration { bool use_file_; std::string filename_; std::map<std::string, std::string> config_; public: configuration(std::string filename, bool use_file = true) : use_file_(use_file) , filename_(std::move(filename)) { if (use_file_) { std::ifstream infile(filename_); std::string key, value; while (std::getline(infile, key, '=') && std::getline(infile, value)) set(to_lower(key), to_lower(value)); } } configuration(const configuration&) = delete; configuration(configuration&& other) : use_file_(other.use_file_) , filename_(std::move(other.filename_)) , config_(std::move(config_)) {} ~configuration() { flush_to_file(); } void flush_to_file() const { if (use_file_) { std::ofstream outfile(filename_); for (auto& pr : config_) outfile << pr.first << "=" << pr.second << '\n'; } } bool contains(const std::string& value) const { return config_.find(value) != config_.end(); } bool get_string(std::string& value, const std::string& key) const { auto found = config_.find(to_lower(key)); if (found != config_.end()) { value = found->second; return true; } return false; } void set_string(const std::string& key, const std::string& value) { config_[to_lower(key)] = to_lower(value); } template <typename T> bool get(T& value, const std::string& key) const { std::string str_value; if (get_string(str_value, key)) { std::stringstream ss; ss << str_value; ss >> value; return ss.good(); } return false; } template <typename T> void set(const std::string& key, const T& value) { std::stringstream ss; ss << value; set_string(key, ss.str()); } template <typename T> bool get_or_set(T& value, const std::string& key) { if (!get(value, key)) { std::stringstream ss; ss << value; set(key, ss.str()); return false; } return true; } private: static std::string to_lower(std::string s) { for (auto& c : s) c = static_cast<char>(std::tolower(c)); return s; } }; #endif
#include <iostream> int main() { configuration cfg("config.cfg"); int difficulty = 2; double map_size = 1337.42; std::string player_name = "Bob"; cfg.get_or_set(difficulty, "difficulty"); cfg.get_or_set(map_size, "map_size"); cfg.get_or_set(player_name, "player_name"); std::cout << "difficulty: " << difficulty << '\n'; std::cout << "map_size: " << map_size << '\n'; std::cout << "player_name: " << player_name << '\n'; }
Ist natürlich noch endless erweiterbar mit Kategorien etc., aber wie gesagt ist relativ kurz gehalten. Hab ich damals nur aus der Not heraus gebaut schnell irgendwas zu haben was funktioniert. Hoffe ich habe bei ein paar Änderungen keine Bugs eingebaut.
-
cooky451 schrieb:
Was eine "Settings-Datei" angeht, da würde ich gar nicht erst versuchen irgendetwas in der Datei zu suchen, einfach komplett auslesen und am Ende wieder komplett überschreiben. Am besten so in der Art dass du eine Datei im Stil von
setting1=value1
setting2=value2etc. hast, dann liest du diese Key-Wert Paare einfach in eine std::map, und am Ende des Programms überschreibst du die Datei komplett mit neuen Key-Wert Paaren.
Beim Charakter, ein paar Monstern und NPCs, und den Settings kommt nicht viel zusammen, aber mein vorrangiges Ziel ist ja nicht, möglichst schnell auf schlechte Programmier-Art ein Spiel auf die Beine zu stellen, sondern es gleich von Anfang an richtig zu machen.
Mindestens bei der Map würde ich deshalb nur das Feld (+ vllt ein paar umliegende) in den Speicher laden, und die Tiles nur aufrufen, wenn der Charakter in die Nähe kommt.Das Programm müsste die Daten in einer bestimmten Zeile von/bis zu einem bestimmten Offset lesen.
Ich bin mir sicher, dass so etwas nicht schwer zu programmieren ist, ich kenne nur einfach die Befehle dafür nicht. Man braucht eigentlich nur:
- Datei öffnen (krieg ich hin)
- Zeile lesen (krieg ich auch hin)
- String auf eine bestimmte Zeichenfolge untersuchen (Settings)
- Zeile von/bis zu einem festgelegten Offset einlesen (Map)
- Daten innerhalb eines bestimmten Offset-Bereichs überschreiben
- Daten an einem bestimmten Offset zwischen vorhandene Zeichen einfügen, ohne zu überschreiben
- Datei schließen (krieg ich wieder hin)Bisher weiss ich zwar, wie ich in einer Zeile Zeichen einlesen kann, allerdings immer nur bis zum nächsten Whitespace.
cooky451 schrieb:
Ich gebe dir hier mal eine Klasse die ich irgendwann mal dafür benutzt habe, aber ich bin mir leider nicht sicher wie viel dir das hilft, denn du scheinst von Klassen und Templates noch nicht so viel Ahnung zu haben. Vielleicht lohnt es doch sich die Sprache noch ein bisschen weiter anzugucken.
Danke für den Code, ich werd mal versuchen, da durch zu steigen. Sieht auf den ersten Blick noch recht komplex aus.
-
Ich rede nur von einem config-file. Ein map-file ist etwas komplett anderes.
Da muss man sich dann erst mal überlegen wie man das aufbauen will, welche Daten man woher bekommt, welche Daten man überhaupt braucht etc. da gibt es unendlich viele Möglichkeiten das aufzuziehen. Mit seekg kannst du übrigens bestimmte Teile einer Datei lesen. http://en.cppreference.com/w/cpp/io/basic_ifstream
-
Jau, habs hinbekommen, mit seek/tellg/p, setw(), substr(), find().
Danke nochmal!Im Prinzip ist es also sinnvoll zu wissen, wie lang die Zeilen in einer Datei einmal sein werden, wenn man später an einzelnen Zeilen basteln will.
Mal eine generelle Frage: Gibt es eine Länge, nach der bei C++ automatisch ein '\n' erfolgt, oder könnte ich eine einzige Zeile mit 10.000 Zeichen schreiben?
-
Nein, Zeilenumbrüche sind oft nur eine Konzession an die Lesbarkeit. Du kannst beliebig große Textdateien erzeugen, die nur vom verfügbaren Speicherplatz begrenzt sind.
-
DocShoe schrieb:
_________________
Die fünf häufigsten Anzeichen für Faulheit:
1.Ich würde gerne eine "Sleep" Funktion aufrufen, aber keine der folgenden geht:
Sleep()
usleep()
sleep()
sleep_for()<chrono> <thread> <unisth.h> <ctime> und <windows.h> hab ich drin.
Weiss jemand Rat?
-
-
Biolunar schrieb:
Was heißt „geht nicht“?
Das heisst in diesem Fall die Meldung:
'sleep_for' undeclaredAusserdem bekomme ich:
chrono: No such file or directory
thread: No such file or directory
(obwohl ich beide #included habe)Versuche es gerade mit Dev-C++ 4.9.9.2 unter Windows.
-
origami schrieb:
Versuche es gerade mit Dev-C++ 4.9.9.2 unter Windows.
Diese IDE ist dermassen antik, da kannst du C++11 gleich vergessen.
Nimm Visual Studio 2013 Express oder eine neue Code::Blocks-Version.
-
Code::Blocks habe ich auch, allerdings bekomme ich da auch den Fehler:
'sleep_for' was not declared in this scope
-
Compilerflag
-std=c++11
-
Nexus schrieb:
Compilerflag
-std=c++11
Settings -> Compiler -> Häkchen bei
Have g++ follow the C++11 ISO C++ languale standard [-std=c++11]
Hab ich.
Muss ich das noch irgendwo setzen?
-
Hast du überprüft, ob deine g++-Version diese Features bereits unterstützt?
Und du machst nicht sonst einen unnötigen Fehler, wie z.B. Namensraum
std
vergessen? Zeig mal kompletten minimalen Code.
-
Nexus schrieb:
Hast du überprüft, ob deine g++-Version diese Features bereits unterstützt?
Wo seh ich meine g++ Version unter Windows?
Ich habe das aktuellste Code::Blocks mit MinGW installiert.Nexus schrieb:
Und du machst nicht sonst einen unnötigen Fehler, wie z.B. Namensraum
std
vergessen? Zeig mal kompletten minimalen Code.#include <iostream> #include <string> #include <cmath> #include <algorithm> #include <iomanip> #include <vector> #include <fstream> #include <cstdlib> #include <cstdio> #include <ctime> #include <conio.h> #include <unistd.h> #include <chrono> #include <thread> using namespace std; int main(){ sleep_for(1); return(0); }
-
Sollte eigentlich funktionieren, oder?