To zależy od zakresu twojej gry. Menedżer zasobów jest absolutnie niezbędny w przypadku większych tytułów, a mniej w przypadku mniejszych gier.
W przypadku większych tytułów musisz poradzić sobie z takimi problemami:
- Wspólne zasoby - czy ta tekstura cegły jest używana przez wiele modeli?
- Żywotność zasobu - czy zasób załadowany 15 minut temu nie jest już potrzebny? Odnośnik zliczający Twoje zasoby, aby upewnić się, że wiesz, kiedy coś jest zakończone itp
- W DirectX 9, jeśli niektóre typy zasobów są załadowane, a urządzenie graficzne „zgubiło się” (dzieje się tak, jeśli naciśniesz Ctrl + Alt + Del między innymi) - gra będzie musiała je odtworzyć
- Ładowanie zasobów przed ich potrzebą - bez tego nie można tworzyć dużych gier z otwartym światem
- Zbiorcze ładowanie zasobów - często pakujemy wiele zasobów w jeden plik, aby skrócić czas ładowania - wyszukiwanie wokół dysku jest bardzo czasochłonne
W przypadku mniejszych tytułów jest to mniejszy problem, frameworki takie jak XNA mają w sobie menedżerów zasobów - ponowne wymyślenie tego nie ma większego sensu.
Jeśli uważasz, że potrzebujesz menedżera zasobów, naprawdę nie ma jednego uniwersalnego rozwiązania, ale zauważyłem, że mapa hash z kluczem jako hash * nazwy pliku (obniżona, a separatory „naprawione”) działa dobrze dla projektów, nad którymi pracowałem.
Zazwyczaj nie zaleca się wpisywania nazw plików w kodzie na stałe, zwykle lepiej jest, aby inny format danych (np. Xml) przedstawiał nazwy plików jako „identyfikatory”.
- Jako zabawną notatkę dodatkową, zwykle dostajesz jedną kolizję skrótu na projekt.
(Próbuję uniknąć omawiania „nie używaj menedżera zasobów”, ponieważ uważam to za nietypowe.)
Mapa klucz / wartość jest bardzo użytecznym podejściem.
Mamy jedną implementację ResourceManager, w której można rejestrować fabryki dla różnych typów zasobów.
Metoda „getResource” używa szablonów, aby znaleźć poprawną Fabrykę dla pożądanego typu zasobu i zwraca określony ResourceHandle (ponownie używając szablonu do zwrócenia określonegoResourceHandle).
Zasoby są ponownie liczone przez ResourceManager (wewnątrz ResourceHandle) i zwalniane, gdy nie są już potrzebne.
Pierwszym dodatkiem, który napisaliśmy, była metoda „reload (XYZ)”, która pozwala nam zmieniać zasoby spoza działającego silnika bez zmiany kodu lub ponownego ładowania gry. (Jest to niezbędne, gdy artyści pracują na konsolach;))
W większości przypadków mamy tylko instancję menedżera zasobów, ale czasami tworzymy nową instancję tylko dla poziomu lub mapy. W ten sposób możemy po prostu wywołać „zamknięcie” na levelResourceManager i upewnić się, że nic nie wycieka.
(krótki) przykład
źródło
Dedykowane klasy menedżerskie prawie nigdy nie są odpowiednim narzędziem inżynieryjnym. Jeśli potrzebujesz zasobu tylko raz (jak tło lub mapa), powinieneś zażądać go tylko raz i pozwolić, aby umarł normalnie, gdy skończysz. Jeśli potrzebujesz buforować określony rodzaj obiektu, powinieneś użyć fabryki, która najpierw sprawdza pamięć podręczną, a w inny sposób ładuje coś, umieszcza ją w pamięci podręcznej, a następnie zwraca - i ta fabryka może być po prostu funkcją statyczną uzyskującą dostęp do zmiennej statycznej , nie jest rodzajem własnego.
Steve Yegge (pośród wielu, wielu innych) napisał dobrą historię o tym, jak ostatecznie bezużyteczne klasy menedżerskie, na podstawie singletonu, są. http://sites.google.com/site/steveyegge2/singleton-consanted-stupid
źródło
Zawsze uważałem, że dobry zarządca aktywów powinien mieć kilka trybów działania. Te tryby najprawdopodobniej będą oddzielnymi modułami źródłowymi przylegającymi do wspólnego interfejsu. Dwa podstawowe tryby działania to:
Potrzebujesz narzędzia, które może pobrać wszystkie assesty ze współużytkowanej bazy danych i utworzyć produkcyjny zestaw danych.
Przez lata jako programista nigdy nie widziałem czegoś takiego, chociaż pracowałem tylko dla kilku firm, więc mój pogląd nie jest tak naprawdę reprezentatywny.
Aktualizacja
OK, trochę głosów negatywnych. Rozwinę ten projekt.
Po pierwsze, tak naprawdę nie potrzebujesz klas fabrycznych, ponieważ jeśli masz:
znasz typ, więc po prostu:
ale potem próbowałem powiedzieć powyżej, że i tak nie używałbyś jawnych nazw plików, tekstura do załadowania byłaby określona przez model, na którym tekstura jest używana, więc tak naprawdę nie potrzebujesz czytelnej dla człowieka nazwy, może to być 32-bitowa wartość całkowita, co znacznie ułatwia obsługę procesora. Tak więc w konstruktorze TextHandle miałbyś:
AssetStream używa parametru resource_id do znalezienia lokalizacji danych. Sposób, w jaki to zrobił, byłby zależny od środowiska, w którym działasz:
W fazie rozwoju: strumień wyszukuje identyfikator w bazie danych (na przykład za pomocą SQL), aby uzyskać nazwę pliku, a następnie otwiera plik, plik może zostać buforowany lokalnie lub pobrany z serwera, jeśli plik lokalny nie istnieje lub jest przeterminowany.
W wersji: strumień wyszukuje identyfikator w tabeli klucz / wartość, aby uzyskać przesunięcie / rozmiar dużego, spakowanego pliku (takiego jak plik WAD Dooma).
źródło
To, co lubię robić dla zasobów, to skonfigurować menedżera brył . Zainspirowane silnikiem Doom, bryły to fragmenty danych, które zawierają zasoby, przechowywane w pliku bryły, który deklaruje nazwy brył, długości, typ (mapa bitowa, dźwięk, moduł cieniujący itp.) Oraz typ zawartości (plik, kolejna bryła, wewnątrz plik bryłowy). Po uruchomieniu te bryły są wprowadzane do drzewa binarnego, ale nie są jeszcze ładowane. Każda mapa (która jest również bryłą) ma listę zależności, które są po prostu nazwami brył, które musi działać mapa. Te grudki, o ile nie zostały już załadowane, są ładowane podczas ładowania mapy. Dodatkowo ładowane są sąsiednie mapy, nie tylko w tym samym czasie, ale z jakiegoś powodu, gdy silnik pracuje na biegu jałowym. Może to sprawić, że mapy będą płynne i nie będzie ekranu ładowania.
Moja metoda jest idealna do map w otwartym świecie, ale gra oparta na poziomie nie odniesie korzyści z płynności, jaką zapewnia ta metoda. Mam nadzieję że to pomoże!
źródło