Menadzer zasobów

0

Witajcie, pracuje sobie ostatnio na pewną grą.
Postanowiłem napisać do niej menadzer zasobów lecz nie wiem jak sie za to zabrać.
Pracuje na systemie Windows 7, używam SFML 2.3
Kod w tym poście nie był kompilowany bo chwilowo nie mam takiej możliwości, więc ten kod ponizej to tak bardziej pseudo kod.
Myślałem nad czymś takim:
1)

 

template<typename ResourceType>
class CResource
{
    public:
    void loadFrommFile(std::sting path)
    {
         m_PointerToResource = new ResourceType;
         m_PointerToResource->loadFromFile(path);
    }
    private:
    ResourceType * m_PointerToResource;
};


/*ResoureceManager
{
  public:
  void loadResourece(int ID,std::string pathToFile)
  {
  ////	......any code;
  }
  private:
  std::map<int,CResource> m_resourceMap;
  protected:

};*/

Moj menadżer będzie przechowywał zasoby w kontenerze std::map i stąd moje pytaie czy moge wstawić nowy element do tej mapy w taki sposób:

 
///Example using
void use()
{
   std::map<int,CResource> m_resourceMap;

  m_resourceMap.insert(std::pair<int,CResource>(1,CResource<sf::Sprite>));
  m_resourceMap.insert(std::pair<int,CResource>(2,CResource<sf::Music>));
}
0
kacper546 napisał(a):
 
///Example using
void use()
{
   std::map<int,CResource> m_resourceMap;

  m_resourceMap.insert(std::pair<int,CResource>(1,CResource<sf::Sprite>));
  m_resourceMap.insert(std::pair<int,CResource>(2,CResource<sf::Music>));
}
  1. Nie wiem czy wiesz, ale tworzysz lokalną mapę
  2. prościej chyba będzie
 
///Example using
void use()
{
   std::map<int,CResource> m_resourceMap;

  m_resourceMap[1] = CResource<sf::Sprite>;
...
}
  1. Ja bym użył jakiegoś enuma zamiast inta

To to co mi przychodzi do głowy

0
  1. Wiem wiem naturalnie to miało tylko obrazować użycie tej mapy
    2)Thx za odpowiedź chciałem wiedzieć czy taka konstrukcja jest możliwa.
    3)Czy takie rozwiązanie jest wydajne czy można to zrobić prościej (prościej zrobić menadżera zasobów który przechowuje zasoby różnych typów w jednej mapie) ?
0

Tak teraz na to patrzę i wydaję mi się, że kompilator tego nie puści.

std::map<int,CResource> m_resourceMap;

Tu będzie krzyczał, że nie ma argumentu szablonu CResource.

Żeby trzymać wszystko w jednej mapie CRecource by musiało być klasą bazową i z niej poszczególne klasy opakowujące np sf::Sprite musiały by dziedziczyć

0

@stryku @Krolik
Ewentualnie mógłbym zrobić kilka map jedna ze sprite-ami druga z dźwiękami itp.
A co myślicie o ogólnej koncepcji ze w klasie CResource umieściłfoo bym wskaźnik typu void i zmienną mówiącą jaki typ danych ten wskaźnik pokazuje (by uniknąć przypisania zasobu dźwiękowego do sprite np).
Czy może kombinuje jak koń pod górkę i jest jakiś wypracowany sposób w jaki powinno się pisać wszelkiej maści menadżery ?

0

Piszesz w C++ to pisz w C++ :p To nowe rozwiązanie nadawało by się do C.
C++ daje Ci obiektowość, wykorzystuj ją (:

0

Tylko nie za bardzo kuman np o co chodzi np z tym zdaniem :CRecource by musiało być klasą bazową i z niej poszczególne klasy opakowujące np sf::Sprite musiały by dziedziczyć

Wiesz korzystam z klas ale ni tak bardziej zaawansowanego i teraz nie wiem jak to w ogóle zacząć.

1

Ogólnie chodzi o wykorzystanie polimorfizmu. Prosty przykład do tego co napisałem.

#include <iostream>
#include <map>
using namespace std;

namespace sf
{
	class Sprite
	{
	public:
		void introduceYourself() const
		{
			cout<<"Sprite\n";
		}
	};
	
	class Sound
	{
	public:
		void introduceYourself() const
		{
			cout<<"Sound\n";
		}
	};
}

class CResource
{
public:
	virtual ~CResource() {}
	virtual void doSomething() const = 0;
};

class CSound : public CResource
{
public:
	void doSomething() const
	{
		sound.introduceYourself();
	}
	
private:
	sf::Sound sound;
};

class CSprite : public CResource
{
public:
	void doSomething() const
	{
		sprite.introduceYourself();
	}
	
private:
	sf::Sprite sprite;
};

class CResourceManager
{
public:
	CResourceManager()
	{
		resourcesMap[0] = new CSprite;
		resourcesMap[1] = new CSprite;
		resourcesMap[2] = new CSound;
		resourcesMap[3] = new CSound;
		resourcesMap[4] = new CSprite;
	}
	~CResourceManager()
	{
		for( const auto &res : resourcesMap )
			delete res.second;
	}
	
	void printResources()
	{
		for( const auto &res : resourcesMap )
			res.second->doSomething();
	}
	
private:
	map<int, CResource*> resourcesMap;
	
};

int main() {
	CResourceManager resMngr;
	
	resMngr.printResources();
	return 0;
}

http://ideone.com/B9B3S1

Lecz to na nic się zda w Twoim projekcie bo sf::Sprite i sf::Music są dwoma zupełnie różnymi klasami.

Więc lepsze będą różne mapy do różnych zasobów. Czyli tak jak pisałeś wcześniej. Wtedy w menadżerze byś miał metody getSprite, getMusic itd.
Unikniesz też przymusu tworzenia wrapperów na to.

0

@stryku

Ok dzięki przeanalizuje to co napisałeś i zaraz coś popełnię jak coś to przyjdę na forum :) Idę popełniać....

0

Warto się zastanowić, czy wiele homogenicznych menadżerów nie będzie lepszym pomysłem. Koniec koniec końców i tak musisz to sprowadzić do konkretnych typów, bo "tekstura", "model" i "muzyka" nie mają za wiele wspólnego :) Czyli i tak polimorfizm szlag trafi.

Można byłoby się jeszcze pokusić o rejestrację takich menadżerów, żeby sprowadzić to do jakiejś fasady.

Jeżeli jednak wymagana byłaby zabawa w runtime (nie wiem, chociażby jakieś dlle), to stawiałbym na kontener ze zobojętnionymi danymi, przechowującymi tylko ich szczątkowe dane (może jakieś typeid do asercji). Takiemu kontenerowi wystarczyłoby zapewnić tylko zbiór akcji (ładowanie, odładowywanie, współdzielony dostęp)

0

@spartanPAGE
Mam pytanie czy powinienem wskazywać pliki do załadowania w kodzie programu czy nie lepszy był by do tego jakaś moja klasa "czytacz plików konfiguracyjnych" ?

0

Pojedynczy menadżerowie zasobów nie muszą nic wiedzieć, niech żądają prostych ścieżek.

Te proste ścieżki niech porozsyła fasada, która wydobędzie je w jakiś sposób z konfiguracji.

0

Szybkie pytanie: czy obiekt klasy CResource powinna liczyć ilość odwołań do zasobu czy przerzucić liczenie użyć zasobu na menadżera ? a może w ogóle nie liczyć ile obiektów używa aktualnie zasobu ?

1

Dodaj zliczanie, kiedy będzie ono naprawdę potrzebne. Zazwyczaj nie jest

0

Mam problem założmy zę mamy coś takieg: 3 klasy

class Bazowa
{
   public:
   protected: 
   Bazowa(){}
   ~Bazowa(){}
   private:
}

template<typename Type>
class Pochodna
{
   public:
   protected: 
   Pochodna(){}
   ~Pochodna(){}
   virtual void doSomething(){}
   private:
}

class Klasa
{
  Bazowa * m_pointer;

  Klasa()
 {
   m_pointer = new Pochodna<Type>;
   m_pointer->doSomething(); ////Nie mozna tego zrobic bo wskzanik pokazuje na klase Bazowa ktora nie posaida tej metody.
 }
 ~Klasa
 {
   delete m_pointer;
 }
}

Moje pytanie czy można zrobić tak żeby wskaźnik wskazywał na obiekt typu Pochodna i pozwalał użyć jej metod jednoczenie będąc typu bazowa ?
Próbowałem konwersji wskaźnika za pomocą dynamic_cast i przychodzi mi już do głowy tylko to by zamineic to:
Bazowa * m_pointer;
na
Pochodna<Type> * m_pointer;

0

Dwa wyjścia:

  • Skorzystać z metod wirtualnych;
  • Castować do góry;

1.:

 
class Bazowa
{
   public:
   protected: 
   Bazowa(){}
   ~Bazowa(){}
   virtual void doSomething(){}
   private:
}
 
template<typename Type>
class Pochodna
{
   public:
   protected: 
   Pochodna(){}
   ~Pochodna(){}
   virtual void doSomething(){}
   private:
}
 
class Klasa
{
  Bazowa * m_pointer;
 
  Klasa()
 {
   m_pointer = new Pochodna<Type>;
   m_pointer->doSomething();
 }
 ~Klasa
 {
   delete m_pointer;
 }
}

2.:

 
class Bazowa
{
   public:
   protected: 
   Bazowa(){}
   ~Bazowa(){}
   private:
}
 
template<typename Type>
class Pochodna
{
   public:
   protected: 
   Pochodna(){}
   ~Pochodna(){}
   virtual void doSomething(){}
   private:
}
 
class Klasa
{
  Bazowa * m_pointer;
 
  Klasa()
 {
   m_pointer = new Pochodna<Type>;
   Pochodna *pochodna = dynamic_cast<Pochodna *>(m_pointer);
   pochodna->doSomething(); // zakładamy, że pochodna != nullptr
 }
 ~Klasa
 {
   delete m_pointer;
 }
}
0

Cześć ! Jak wiecie pisze sobie prosty menadżer zasobów.
Mam powiedzmy menadżera tekstur i dźwięków.
Mam teraz kłopot z wymyśleniem w jaki sposób ładować pliki - pojedynczy menadżer będzie żądać ścieżek do pliku (ewentualnie ID zasobu)ale
nie mam pojęcia skąd powinienem pobrać te ścieżki.

Myślałem nad kilkoma rozwiązaniami

  • W kodzie mam pełną ścieżkę do pliku który mnie interesuje. (najprostsze)
  • Mam menadżera który wyszukuje pliki w katalogu - przypisuje im ID i można się go spytać jakie ID ma plik o tej ścieżce - potem posługuje się tylko ID od danego zasobu.
  • Menadżer ma ustalone w pewnym pliku konfiguracyjnym ID zasobu i ścieżkę do jego pliku.

Nie wiem na które rozwiązanie się zdecydować, czy ewentualnie jakaś wariacja 3 powyższych idei.

0

@spartanPAGE
@stryku

Pomyślałem ze za wcześnie zabieram się za optymalizację mojego menadżera.
Czy dobrym pomysłem będzie odwoływanie się do zasobu za pomocą ścieżek?

0

Jeżeli twój menadżer ma być wydajny, stosuj jedynie indeksowane klucze.
Jeżeli chcesz mieć -przy okazji- ścieżki, to napisz owijkę mapującą ścieżki z kluczami. Po drodze mógłbyś użyć np. ścieżek hashowanych w czasie kompilacji, to by dodatkowo pomogło.

0

Dzieki za szybka odpowiedz - na razie napisze wyszukiwanie za pomocą ścieżek później się pomyśli nad optymalizacją - po prostu czuje że utknąłem z tym menadżerem :(

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