FileManager

0

Cześć! Próbuje zaimplementować filemanager do mojego projektu.

void FileManager::LoadFromFile(const std::string &filePath, std::vector<float> &data)
	{
		std::ifstream file(filePath.c_str());

		data.clear();

		if (file.is_open())
		{
			while (file.eof())
			{
				std::string line;
				std::getline(file, line);

				std::vector<float> tempData;
				
				std::stringstream str(line);
				while (str)
				{
					std::getline(str, line, ' ');

					tempData.push_back(atof(line.c_str()));
				}

				if (tempData.size() > 0)
				{
					data = tempData;
				}
			}
		}

		file.clear();
		file.close();
	}

Chce wgrać dane z pliku do drugiego argumentu std::vector<float> &data;

w klasie w której potrzebuje filemanagera mam prywatny wektor, ten do którego akurat potrzebuje wpisać dane i próbuje te dane wpisać w metodzie draw

Class::Class()
{
	fileManager.LoadFromFile("Files/testowy.txt", dane);
}

void Class::Draw()
{
	for(int i = 0; i < dane.size(); i++)
	{
		std::cout<<dane[i]<<std::endl;
	}
}

Moim zdaniem powinno działać patrząc na to, że do mapy mam w podobnym typie file manager

void File::LoadFromFile(std::string fileName, std::vector<std::vector<std::string>>& map)
{
	fileName = "Files/Config/" + fileName + ".cfg";
	std::ifstream openFile(fileName);

	map.clear();

	if (openFile.is_open())
	{
		while (!openFile.eof())
		{
			std::string line;
			std::getline(openFile, line);

			std::vector<std::string> tempVector;

			if (line.find("[map]") != std::string::npos)
			{
				state = MAP;
				tempVector.clear();
				continue;
			}

			std::stringstream str(line);

			while (str)
			{
				std::getline(str, line, ' ');

				if (line != "")
				{
					if (state == MAP)
					{
						tempVector.push_back(line);
					}
				}
			}

			if (state == MAP)
			{
				map.push_back(tempVector);
			}
		}
	}

	openFile.clear();
	openFile.close();
}

I nie ma najmniejszego problemu z takim odczytem danych, za to w tym powyżej albo sie wysypuje program albo nic nie jest wypisywane na ekranie. Rozwiązaniem mogłoby być ustawienie zamist voida std::vector<zmienna> jako metoda i zwrócenie wektora z danymi ale jestem ciekawe dlaczego pierwszy sposób nie działa kiedy ten z mapą działa bardzo dobrze.

0

Zamiast takich wygibasów przy wczytywaniu możesz użyć bardziej cywilizowanych metod ;)

bool LoadFromFile( const std::string& file_path, std::vector< float >& out_data )
{
  bool result = false;
  std::ifstream file( file_path );
  if ( file.is_open() ) {
    std::copy( std::istream_iterator< float >( file ), std::istream_iterator< float >(), std::back_inserter( out_data ) );
    if ( !out_data.empty() ) {
      result = true;
    }
  }
  return result;
}

No i nie wiem czy naprawdę potrzebujesz jakiegoś FileManagera. Lepiej chyba machnąć jakąś fabryczkę, która w zależności od formatu pliku tworzyłaby odpowiedni loader wczytujący dane. I wywoływać to wszystko w metodzie typu Deserialize.
Poza tym FileManager kojarzy mi się bardziej z obsługą (tworzenie/kasowanie/zarządzanie) strukturą plików niż gmyraniem w środku :P

0

Nie jestem jakimś zaawansowanym programistą więc nie wiem co to znaczy machnąć fabryczknę :D. Pewnie ci chodzi o to, żeby pobrać pliki zrobione już przez kogoś, ale chciałbym się czegoś nauczyć zamiast korzystać już z gotowych kodów. Dzięki za odpowiedź, zaraz sprawdzę co znaczą te metody.

0

Aaa, czyli coś takiego jakby na przykład klasa Entity oraz np. potwór1, który dziedziczy z entity; potwór2, który dziedziczy z entity; potwór3, który dziedziczy z entity i klasa EntityManager, która zawiera std::vector<Entity*> entity i metodę void AddEntity(Entity* instance)?

0

Odwrotnie.
Klasa EntityManager na podstawie podanych parametrów tworzy instancję jednej z klas dziedziczących po Entity i zwraca wskaźnik typu Entity*, więc po utworzeniu tak naprawdę nie wiesz jaki konkretny typ kryje się pod tym wskaźnikiem.

Czyli np. interfejs class IDataLoader, który jest implementowany przez klasy class DataLoader_Txt, class DataLoader_Binary, '`class DataLoader_Xml' etc. Klasa która chce wczytać dane operuje wyłącznie na interfejsie nie wiedząc tak naprawdę z jakiego formatu dane pochodzą.
Coś w tym stylu:

void MyClass::LoadData( const std::string& file_path )
{
  MyClassDataLoaderFactory factory;
  IDataLoader* loader = factory.CreateLoader( file_path );  // fabryka wybiera odpowiednią implementację
  if ( loader ) {  // klasa operuje na interfejsie
    std::vector< Data > loaded_data;
    if ( loader->Read( &loaded_data ) ) {
      this->mydata = std::move( loaded_data );
    }
  }
}
0

Teraz to już w ogóle tak średnio rozumiem co się dzieje. Sprawdzę sobie, pewnie na yt będzie dużo tego.

0

Chyba już trochę wiem o co chodzi.
W moim przykładzie z entity manager nie zwracamy konkretnej klasy, tzn. jak mamy np. klasę
Zombie : public Entity

I w klasie Game zrobimy sobie EntityManager entityManager taki obiekt i metodą void EntityManager::AddEntity(Entity* newEntity) dodamy sobie naszego zombie w taki sposób

entityManager.AddEntity(new Zombie(posX, posY, velX, velY, ... )

to jeśli w klasie Game chcielibyśmy dostać np. wartość posX na której jest zombie to nie możemy tego dostać, bo nasz manager tak naprawdę nie wie z jakiej entity klasy korzystamy. A dzięki fabryce wiemy. Dobrze myślę?

Obejrzałem

i troche dużo tego kodu. Do każdego gówienka musze robic tyle klas.

1 użytkowników online, w tym zalogowanych: 0, gości: 1