130 likes | 252 Views
Programowanie gier komputerowych Tomasz Martyn. Wykład 3. Zarządzanie zasobami. Zarządzanie zasobami oparte na zwykłych wskaźnikach na ogół nie jest bezpieczne.
E N D
Programowanie gier komputerowychTomasz Martyn Wykład 3. Zarządzanie zasobami
Zarządzanie zasobami oparte na zwykłych wskaźnikach na ogół nie jest bezpieczne. • Na przykład jeden z podsystemów silnika gry może zażądać od zarządcy zasobów usunięcia zasobu wskazywanego przez wskaźnik; jeżeli żądanie takie zostanie spełnione, wówczas wszystkie pozostałe wskaźniki na ten zasób istniejące w systemie są nieważne (ale korzystające z nich podsystemy o tym nie wiedzą). • Zapisywanie (np. na dysk) aktualnego stanu systemu wykorzystujące wartości wskaźników w celu ponownego odtworzenia stanu systemu jest na ogół niepoprawne. • Ma to istotne znaczenie w przypadku zapisów bieżących stanów gry, ponieważ przy ponownym wczytaniu gry układ danych w pamięci prawdopodobnie będzie inny. • Proces defragmentacji pamięci w oczywisty sposób powoduje unieważnienie wskaźników. Uchwyty (1)Po co? Jednym ze sposobów rozwiązania powyższych problemów jest wprowadzenie dodatkowej warstwy abstrakcji pomiędzy zwykłymi wskaźnikami a systemem w postaci uchwytów.
(patrz np.: S. Bilas: Ogólny system zarządzania zasobami oparty na uchwytach, w: Perełki programowania gier 1) Uchwyty (2)Przykład klasy szablonowej ogólnego uchwytu
Uchwyty (4)Zarządca uchwytów (2) Generowanie i zwalnianie uchwytu
Gry komputerowe i wideo wymagają obsługi dużej ilości różnorodnych danych multimedialnych (geometria, tekstury, materiały, animacje, efekty dźwiękowe, ...), które na ogół zajmują dużo miejsca w rozumieniu kosztów pamięciowych. • Manipulowanie tak dużą ilością danych w czasie rzeczywistym przy ograniczonym budżecie pamięciowych wymaga odpowiedniego zarządzania tymi danymi. • Zadania ogólnego zarządcy zasobów: • zapewnia, że w danej chwili w pamięci każdy zasób przechowywany jest tylko w jednej kopii (zasób może być współdzielony np. przez kilka modeli) • zarządza wykorzystaniem pamięci przez załadowane zasoby, w szczególności może dbać o to, żeby zasób został umieszczony w odpowiedniej pamięci (np. tekstura w pamięci tekstur; szczególnie w przypadku konsol posiadających pamięci różnego rodzaju) • wspomaga zarządzanie czasem życia każdego zasobu, ładuje zasoby potrzebne (najlepiej z odpowiednim wyprzedzeniem) i usuwa zasoby, które nie są już potrzebne • wspomaga ładowanie zasobów złożonych (np. model 3D może składać się z: siatki trójkątów, materiałów, tekstur, szkieletu, animacji...) • często umożliwia asynchroniczne ładowanie zasobów Zarządca zasobów (1)
Często zarządca zasobów udostępnia jednolity interfejs umożliwiający zarządzanie zasobami różnych typów. Na przykład w Ogre3D realizowane jest to poprzez zdefiniowanie abstrakcyjnej klasy Resource oraz ogólnej klasy ResourceManager, po której dziedziczą (singletonowe) klasy zarządców konkretnych typów zasobów. Rolę zarządcy zasobów (w opisywanym wyżej sensie) w Ogre3D pełni singletonowa klasa ResourceGroupManager - odwołuje się do poszczególnych zarządców za pośrednictwem przechowywanych przez nią wskaźników. Zarządca zasobów (2)
(S. Bilas: Ogólny system zarządzania zasobami oparty na uchwytach, w: Perełki programowania gier 1) Zarządca zasobów (3)Przykład prostego zarządcy tekstur (1)
Łańcuchy znaków są wszechobecne w silniku gry. W szczególności wykorzystywane są jako unikatowe identyfikatory poszczególnych zasobów gry, które są przyjazne dla projektanta (w odróżnieniu np. od unikalnych identyfikatorów liczbowych - GUID). • Jednakże dokonywanie działań na łańcuchach znaków (w szczególności porównań i kopiowania) jest o wiele bardziej czasochłonnymi operacjami niż analogiczne operacje dokonywane na liczbach. W rezultacie, nieodpowiednie podejście do przetwarzania łańcuchów znaków w czasie wykonania może wpłynąć na (nawet znaczne) obniżenie wydajności działania silnika. • Powszechnym rozwiązaniem tego problemu stosowanym w silnikach gier jest wykorzystanie podejścia polegającego na reprezentowaniu łańcuchów znaków w postaci liczb (zwykle 32-bitowych) otrzymanych za pomocą odpowiedniej funkcji mieszającej (hashfunction)– tzw. internowanie stringów (interningstrings) • Często w roli funkcji mieszającej stosowany jest tutaj algorytm bazujący na cyklicznym kodzie nadmiarowym CRC-16 lub CRC-32. • Zamiast łańcuchów znaków w kodzie gry wykorzystywane są ich id liczbowe, zaś same łańcuchy przechowywane są w tablicy mieszającej (indeksem jest id łańcucha) w celu odzyskania właściwego łańcucha na podstawie id (np. aby wyświetlać stosowane informacje o zasobach w konsoli deweloperskiej). Zarządca zasobów (5)Problem łańcuchów znaków
Czas życia zasobu definiowany jest jako okres czasu pomiędzy załadowaniem zasobu do pamięci, a zwolnieniem tej pamięci dla innych celów. Jednym z zadań zarządcy zasobów jest zarządzanie czasem życia zasobów - albo automatyczne, albo poprzez dostarczanie odpowiednich funkcji, które umożliwią określanie życia zasobów z zewnątrz (np. z kodu rozgrywki). Zasoby pod względem życia można podzielić na: • zasoby pozostające w pamięci przez cały okres gry (load-and-stay-resident – LSR); np. zasoby związane z postacią sterowaną przez gracza, zasoby interfejsu ekranowego (HUD) • zasoby pozostające w pamięci przez cały poziom gry; zasób musi być w pamięci gdy gracz widzi poziom po raz pierwszy oraz zasób jest usuwany gdy gracz definitywnie opuszcza poziom • zasoby o czasie życia krótszym niż trwanie poziomu gry (np. krótkie przerywniki filmowe „wtrącone” do rozgrywki poziomu albo zasoby związane z poziomem, ale aktualnie niepotrzebne i usuwane ze względu ograniczonego budżetu pamięciowego • zasoby streamowane (np. muzyka, przerywniki filmowe o stosunkowo dużych „gabarytach”) Zarządca zasobów (6)Czas życia zasobów (1)
Zagadnienie dotyczące momentu ładowania zasobu do pamięci jest stosunkowo proste, bowiem moment ten musi poprzedzać czas, w którym gracz (na ogół po raz pierwszy) widzi lub słyszy zasób. Często o wiele trudniejsze jest zagadnienie dotyczące zwalniania pamięci zajmowanej przez zasób. • Po pierwsze, zasób może być współdzielony przez wiele poziomów gry. W takim przypadku rozwiązanie może polegać na zliczaniu odwołań do zasobu i usuwaniu tych zasobów, których licznik jest zerowy. • Po drugie, wszystkie zasoby związane z poziomem gry mogą nie mieścić się w pamięci (np. w zw. z mocno ograniczonym budżetem pamięciowym konsoli lub otwartym światem gry). W takim przypadku jedno z rozwiązań automatycznego usuwania zasobów bazuje na sortowaniu zasobów przez zarządcę zasobów w trakcie czasu wykonania względem nadanego priorytetu ważności, czasu ostatniego dostępu do zasobu, rozmiaru zasobu; zasoby znajdujące się na końcu posortowanej listy usuwane są z pamięci i na ich miejsce ładowane są zasoby aktualnie wymagane (por. np. J. Boer: Zarządzanie zasobami i pamięcią, w: Perełki programowania gier 1). Zarządca zasobów (7)Czas życia zasobów (2)