[SFML] Wczytywanie dużych poziomów (przewijana mapa)

Dzisiaj dowiesz się w jaki sposób można wczytywać poziomy zajmujące dużą ilość kafli jednak w bardziej oszczędny dla pamięci sposób, tak aby nie potrzebnych kafli po prostu nie wczytywać. W przykładzie poniżej korzystam z SFML’a w wersji 2.0, jednak kod powinien być łatwy w konwersji na inne biblioteki.

Tak jak wspomniałem zajmiemy się problemem wczytywania zbyt dużych poziomów, aby zmieściły się na ekranie oraz tak dużych że mogą spowolnić działanie gry, zobrazujmy sobie ten problem:

(kliknij aby powiększyć)

Przy wczytywaniu wszystkich kafli naraz (i rysowanej tablicy o tych samych rozmiarach) posiadamy jedynie 2 z 3 obszarów wyróżnionych na schemacie powyżej:

  • obszar niewidoczny dla użytkownika, na którym znajduje się cały wczytany poziom, tzn nawet te fragmenty, których nie widzimy
  • Scena gry, która wyświetla ten fragment poziomu na który zwrócona jest kamera.

Weźmy na ten przykład poziom który ma wymiary w kaflach 100 x 30, a ekran może wyświetlić 50×30 kafli. Tworzenie i wyświetlanie tablicy sprite’ów o tych samych rozmiarach co poziom jest bezużyteczne bo 49-50 kafli nie zostanie zobaczone przez gracza mimo że są rysowane. Olbrzymia strata pamięci dla komputera.

Rozwiązanie zbyt dużej ilości kafli na ekranie przychodzi za pomocą 3 pośredniej warstwy: obszar wczytywany do pamięci to obszar, który jest nieco większy niż scena (okno) gry o parę kafli więcej niż ekran po to aby przy ruchu gracza kamera mogła wyświetlić kafle dotychczas schowane za sceną.

Wracając do przykładu: jeżeli przy takich samych rozmiarach poziomu i ekranie mieszczących tyle samo kafli co wcześniej utworzymy tablicę do wyświetlania sprite’ów o nieco większych wymiarach (52 x 30) to zaoszczędzimy bardzo dużo pamięci, bo nie będziemy wczytywać całego poziomu lecz potrzebny nam fragment, w poziomie wczytujemy kafli nieco więcej bo musimy być gotowi do wyświetlenia kolejnych kafli gdyby gracz poszedł w prawo albo lewo (kamera nie musi obejmować całych kafli lecz np. połowę tego co wcześniej w całości za sceną).

Poniżej zamieszczam przykładową implementację takiego wczytywania poziomu jedynie fragmentami, zapraszam do samodzielnej implementacji, a w razie problemów, sugestii, wątpliwości zapraszam do systemu komentarzy (pamiętajmy że wszelkie komentarze zawsze są miło widziane).

Ostrzegam, że minimapa się przycina z tego powodu, że poruszamy się tam o 4 piksele, stąd to złudzenie (trzeba by odpowiednio prędkość gracza dopasować do delta time, wtedy powinno wszystko być ok).

Kod jest również dostępny w wersji na GitHub:

Zobacz kod na GitHub


  • Arkadiusz Kozioł

    no dobra. A jak ja jestem osobą niewidomą i chcę sobie zrobić gre audio gdzie oczywiście najważniejszą rolę odgrywają dźwięki i mowa, którą sobie zaimplementuje sam, to po co mi te wszystkie wyświetlanie tych kafli itd? Oczywiscie systemu samej mapy nie zmieniam, No a jak już je usunę, to w jaki sposób mam sobie rozwiązać te wszystkie problemy? np tworze plik tekstowy z tą mapą poziomową, co była podana w którymś z przykładów i usuwam wszystko co związane z wyświetlaniem, to co mam tam wstawić żeby to działało poprawnie dla mnie? bo jakoś nie mam pomysłów.

    • Nie rozumiem do końca o co ci chodzi. Ten wpis dotyczy (zgodnie z jego pierwszym zdaniem) przewijanej mapy używającej kafli. Wszelkie inne mapy (czy też poziomy) nie miały być i nie są tematem tego wpisu.

  • Arkadiusz Kozioł

    no to przecież nie mam niczego innego na myśli. Tylko chodzi mi o to, ze jeśli nie używam pozycji sprite’ów itd. to czy wystarczy jak sobie po prostu stworze zmienne odpowiadające odpowiednio za pozycje x i y i to też będzie działało jak to odpowiednio oprogramuje. Chodzi mi o to, ze jeśli nie chce, żeby to było wyświetlane, bo mi to nie jest potrzebne, i wiem, ze niczego innego tu być nie miało, bo raczej nikt czegoś takiego nie robi, a chcę, żeby gracz mógł się nadal poruszać na tej mapię w pliku tekstowym, to czy to się da w jakiś sposób ogarnąć bez tych sprite’ów itd?

    • O ile dobrze zrozumiałem to: tak. Tobie chodzi o działanie tego na poziomie czysto matematycznym.

  • Arkadiusz Kozioł

    zgadza się.

  • Arkadiusz Kozioł

    a mógłbym prosić o jakiś przykłąd tego? Np zmiane pozycji gracza na mapie? tam wszędzie jest shape itd. a chyba raczej zwykłymi intami tego nie rozwiąże. A i wgl kod od 1 do 3 lekcji nie chce się kompilować, a robię wszystko dobrze, tak jak to zostalo opisane. Oczywiście z pominięciem metod graficznych.

    • Kod z „Piszemy grę w SFML’u” był wrzucany na bloga dopiero po jego wcześniejszej kompilacji (kompilacja pod VS 2010, SFML 2.0), więc zdanie „kod mi się nie kompiluje” nic mi nie mówi. Prosisz o przykład do kodu bazującego na klasie, której nie widziałem na oczy, więc nieco pseudo-kodowe ustawienie nowej pozycji: http://pastebin.com/qf1WfDvZ

  • Arkadiusz Kozioł

    i to będzie działało z mapą?

    • Jak napisałem wcześniej, nie mam pojęcia jak ty to napisałeś a podałem ci jedynie pseudokod, jeżeli zamiast obiektu sprite’a podstawimy zmienne reprezentujące pozycję x i y to tak, to na ej zasadzie wyglądałoby przepisanie kodu bez sprite’ów.