SFML и C++ Уроки \ Разработка игр › Форумы › Логика игр › ввод переменных из файла
В этой теме 6 ответов, 3 участника, последнее обновление Serob 6 года/лет, 2 мес. назад.
-
АвторСообщения
-
добрый день!
появилось немного свободного времени решил поработать над игрушкой. задача следующая есть текстовый “text.txt” в нём содержаться данные пример “speed = 10 time = 5 monstr = 20″. этим файлом устанавливаю количество монстров, их скорость и время атаки. тоесть ети параметры можно задавать из внешнего источника не пересобирая всю игру.
как можно из файла передать числовые значения соответствующим переменным в программе? всё что я смог это getline() но читается вся строка и чё с ней дальше делать не понимаю. посоветовали использовать следующую схемуC++1234567891011121314151617181920212223#include <iostream>#include<map>#include<cstdio>int main(){int Level,Count,Target,Speed,Time;std::map<std::string,int*> vars{{"Level",&Level},{"Count",&Count},{"Target",&Target},{"Speed",&Speed},{"Time",&Time}};FILE*file=fopen("test.txt","r");char name[128];int value;while(fscanf(file," %127[a-zA-Z] = %d",&name,&value)==2)*vars[name]=value;for(auto&pair:vars)std::cout<<pair.first<<" "<<*pair.second<<std::endl;return 0;}но fscanf не типичная функция и на моём VS 2017 матом ругается и запускаться не хочет (Ошибка C4996).
Ну на скорую руку могу только предоставить менеджер локализации написаный много времени назад, но новая студия вроде как спокойно “съела” код, для твоих целей он в принципе подойдёт
Но если тебе нужна только загрузка с файла тебе понадобится только этот кусок кода где localeBuffer будет полностью вмещать содержимое файла. И да, не забывай о том что потребуется приведение к типам из строки к числу – для этого есть std::stoi, std::stof, std::stod, std::stol, std::stoul и т.д. Перевод перевод делай желательно sf::String::toWideString() ибо мы работаем с юникодом при использовании строки sfmlC++12345678910111213141516171819202122232425262728293031323334353637sf::String curLocale = "ru_RU";std::string curDir = "";sf::String defaultLang = "en_UK";std::ifstream curLocaleFile;std::ifstream defaultLocaleFile;sf::String localeBuffer;if (localeBuffer.isEmpty()){curLocaleFile.open(std::string(curDir + curLocale + ".lang"), std::ios_base::in);char S;int count = 0;if (curLocaleFile.is_open()){while (!curLocaleFile.eof())//count simbols{curLocaleFile.get(S);count++;}curLocaleFile.close();curLocaleFile.open(std::string(curDir + curLocale + ".lang")); //open the file againint i = 0; //iterwhile (!curLocaleFile.eof()) //while not end of file{char buf;curLocaleFile.get(buf);localeBuffer += buf; //add simboli++; //move iter next}curLocaleFile.close();}else{//LOG("LocalisationManager::getLocalisation: Failed to open file(" + curDir + curLocale + ".lang" + ")", Logger::Info);}}C++1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283//LocalisationManager.h#pragma once//#include "SFGE\LabelButton.h"//#include <SFGE\SFGE.h>#include <fstream>#include <SFML\System\String.hpp>//#include <Windows.h>//#include <atlwin.h>#define lm sfge::LocalisationManager::instance()namespace sfge{/// \brief A localisation manager that give licalised names and descriptions in selected locale.////// In order not to let calling the class get verbose, a MACRO is defined.\n/// @code #define lm sfge::LocalisationManager::instance() @endcode/// This makes calling the localisation manager elsewere as this:/// @code/// #include <SFGE/LocalisationManager.h>/// lm->getLocalisation("block.dirt.name");/// @endcode/// And resulted string ben a localised string, or return input if localisation not existclass LocalisationManager{public:static LocalisationManager* instance();~LocalisationManager(){}/// \brief Set localisation (and filename) as main source of licalised names/// @param sf::String - locale in style en_UK, ru_RU, etc.void setLocale(sf::String locale){curLocale = locale;}/// \brief Set lang folder/// \@param string Dir rootvoid setDir(std::string root){curDir = root;}/// \brief Get localisation from .lang file/// @param sf::String Unlocalised Name/// @return sf::String resultsf::String getLocalisation(sf::String unlocalisedName);protected:LocalisationManager(){//curLocale = "ru_RU";}private:static LocalisationManager* lcr;sf::String curLocale = "ru_RU";std::string curDir = "";sf::String defaultLang = "en_UK";std::ifstream curLocaleFile;std::ifstream defaultLocaleFile;/// \brief Locale buffer is containing all chars from file/// and we no more need to load file in to memory again, and again, and again....sf::String localeBuffer;};//end LocalisationManager}// end namespace sfgeC++123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147//LocalisationManager.cpp//#include "Block.h"//#include <SFGE\Block.h>//#include "gamestate.h"#include "LocalisationManager.h"sfge::LocalisationManager* sfge::LocalisationManager::lcr = 0;namespace sfge{LocalisationManager* LocalisationManager::instance(){//setlocale(LC_CTYPE, "rus");//We cant get <Windows.h> any moreif (lcr == NULL)lcr = new LocalisationManager;return lcr;}sf::String LocalisationManager::getLocalisation(sf::String unlocalisedName){sf::String temp;sf::String result;if (localeBuffer.isEmpty()){curLocaleFile.open(std::string(curDir + curLocale + ".lang"), std::ios_base::in);char S;int count = 0;if (curLocaleFile.is_open()){while (!curLocaleFile.eof())//count simbols{curLocaleFile.get(S);count++;}curLocaleFile.close();curLocaleFile.open(std::string(curDir + curLocale + ".lang")); //open the file againint i = 0; //iterwhile (!curLocaleFile.eof()) //while not end of file{char buf;curLocaleFile.get(buf);localeBuffer += buf; //add simboli++; //move iter next}curLocaleFile.close();}else{//LOG("LocalisationManager::getLocalisation: Failed to open file(" + curDir + curLocale + ".lang" + ")", Logger::Info);}}sf::String c1;auto c1it = localeBuffer.find(".");c1it = localeBuffer.find(".", c1it + 1);c1 = localeBuffer.substring(c1it + 1, 4);if (c1 == "name")//Here we determinate -> we search name or description{if (unlocalisedName == "block..name" || unlocalisedName == "item..name" || unlocalisedName == "entity..name"){//LOG("LocalisationManager::getLocalisation: Failed. Unlocalised name is missing", Logger::Error);return "missingNo.name";}int checkCode = 0;//if (localeBuffer.find(unlocalisedName))//{auto it = localeBuffer.find(unlocalisedName + "=");it += std::string(unlocalisedName + "=").size();if (localeBuffer.find("\n", it) != sf::String::InvalidPos)//We found \n or get end of string?checkCode = 1;else checkCode = -1;auto itE = localeBuffer.find("\n", it);if (checkCode == 1)//If we found \n we use it positionwhile (it < itE){//std::cout << std::to_string(it) << " " << std::to_string(itE) << std::endl;result += localeBuffer[it];it++;}else if (checkCode == -1)//Else use end of string position;while (it < localeBuffer.getSize() - 1){//std::cout << std::to_string(it) << " " << std::to_string(localeBuffer.getSize()) << std::endl;result += localeBuffer[it];it++;}//LOG("LocalisationManager::getLocalisation:(" + unlocalisedName + ") = " + result, Logger::Info);return result;}else if (c1 == "desc"){auto c2c = unlocalisedName.substring(0, unlocalisedName.find("."));if (c2c == "" || c2c == "."){//LOG("LocalisationManager::getLocalisation: Failed. Unlocalised name is missing", Logger::Error);return "missingNo.desc";}int checkCode = 0;auto it = localeBuffer.find(unlocalisedName + "=");it += std::string(unlocalisedName + "=").size();//if (localeBuffer.find("#enddesc", it) != sf::String::InvalidPos)//We found \n or get end of string?// checkCode = 1;//else checkCode = -1;auto itE = localeBuffer.find("#enddesc", it);if (itE != sf::String::InvalidPos)while (it < itE){//std::cout << std::to_string(it) << " " << std::to_string(itE) << std::endl;result += localeBuffer[it];it++;}else{//LOG("LocalisationManager::getLocalisation: Failed(" + unlocalisedName + "): #enddesc not found", Logger::Error);return "missingNo.desc.notEnded";}}//}//else//{//LOG("LocalisationManager::getLocalisation: Failed(" + unlocalisedName + ")", Logger::Warning);//LOG("LocalisationManager::getLocalisation: localeBuffer(\n" + localeBuffer + ")", Logger::Warning);return unlocalisedName;//}}}C++1234//ru_Ru.lang - exampleblock.dirt.name=Земляblock.cobble.name=Булыжникblock.grass.name=Травана сколько понимаю в твоем примере ведётся работа со всем буфером. алгоритм решения моей задачи я представляю следующий:
1. в моей программе есть переменные speed, time и т.д
2. в файле *.txt есть запись ( speed = 50 time = 10)
3. при помощи метода я могу считать весь фаил в переменную, массив или ещё что то..
4. затем нужно взять переменную из программы и сопоставить со считанным из файла, если нашлось совпадение например “speed = 50″ и “speed” тогда значение “50” записать в переменную в программе.
вот пункт 4 я не понимаю как можно сравнить по сути разное и если в них хоть что то совпадает, то взять часть.
в моём примере fscanf делал нужное ” %127[a-zA-Z] = %d” маска записанного в фаиле, что сразу заносилось в переменные &name,&value
плохо что это си функция
то что с++ мозговыжигатель согласен. тружусь на jave там вроде попрощеСобственно файл буфферизируется единожды при первом обращении к файлу. Дальше все считывается из строки.
Здесь запись конечно не сортируется как ключ – значение, но никто не мешает тебе пропустить весь буффер через регулярные выражения (Regex) получив std::map<std::string, std::string>, проходится по нему итерациеq и присваивать значение если ключ совпадает с искомым. Это уже не твои проблемы если юзверь поковырялся и нагадил в конфигах поставив заместо числа строку, так что смело конвертируй где нужно число через функции std::stoi, std::stof.С регулярными совсем тяжело, пока в процессе освоения. В общем получилось так.
C++123456789101112131415161718192021222324252627#include <iostream>#include <fstream>#include <unordered_map>#include <string>#include <regex>using namespace std;int main() {//открываем фаилifstream ff("test.txt");// проходимся по открытому файлуstring txt{ istreambuf_iterator<char>(ff),istreambuf_iterator<char>() }; x.second x.first << " " <<unordered_map<string, double>m;// регулярка для считывания текста в файлеregex e("(\\w+)\\s*\\=\\s*(\\d+\\.?\\d*)");// считанное разделяем на str(1) и str(2). в str(1) храним наименование переменной в str(2) значениеfor (auto it = sregex_iterator(txt.begin(), txt.end(), e); it != sregex_iterator(); ++it) {m.emplace(it->str(1), stod(it->str(2)));}// заполняем мар мfor (const auto&x : m) {cout << x.second << endl;}system("pause");return 0;}осталось добавить сравнение с переменными в файле и программами.
А не лучше ли использовать ini файл? Вот готовое решение.
ini проще, но в целях обучения был выбран именно txt фаил.
-
АвторСообщения
Для ответа в этой теме необходимо авторизоваться.