Mam platformówkę 2D, która obecnie obsługuje porcje po 100 na 100 kafelków, przy czym współrzędne porcji są przechowywane jako długie, więc jest to jedyny limit map (maxlong * maxlong). Wszystkie pozycje podmiotów itp. Itp. Są istotne, więc nie ma tam limitu.
Mam problem z tym, jak przechowywać te fragmenty i uzyskiwać do nich dostęp bez posiadania tysięcy plików. Jakieś pomysły na najlepiej szybki i tani format archiwum HD, w którym nie trzeba otwierać wszystkiego naraz?
long
który jest 64-bitowy (więc maxlong jestInt64.MaxValue
).Odpowiedzi:
Utwórz niestandardowy format mapy dla swojej gry. To łatwiejsze niż myślisz. Wystarczy użyć klasy BinaryWriter. Najpierw napisz nagłówek w kilku ints lub uintach. Informacje, które należy uwzględnić w nagłówku:
a także (i tutaj pojawia się część krytyczna pod względem wydajności
Za pomocą powyższej metody możesz (i powinieneś) utworzyć indeks zawartości swoich plików, zawierający pewien opis (nazwę określoną przez użytkownika dla regionu / porcji lub tylko współrzędne) i jako drugą wartość pozycję w pliku.
Następnie, gdy chcesz załadować konkretną porcję, musisz po prostu przeszukać indeks. Po otrzymaniu pozycji ustaw fileStream.Position = PositionOfChunkFromIndex i możesz ją załadować.
Chodzi przede wszystkim o projekt formatu pliku z nagłówkiem opisującym zawartość pliku w najbardziej efektywny sposób.
Po prostu zapisz pliki z niestandardowym rozszerzeniem, które utworzyłeś i gotowe.
BONUS: Dodaj kompresję BZip2 do określonych regionów pliku / całej zawartości (nie nagłówka !!), abyś mógł rozpakować określone fragmenty z pliku, aby uzyskać bardzo mały rozmiar pamięci.
źródło
Zetknąłem się z podobnym problemem i postanowiłem stworzyć własną strukturę do obsługi danych. Opiera się luźno na poczwórnym drzewie, ale ma nieskończoną (przynajmniej tak dużą jak Int) rozszerzalność we wszystkich kierunkach. Został zaprojektowany do obsługi danych opartych na siatce, które rozszerzyły się z centralnego punktu, podobnie jak teraz Minecraft. Zajmuje mało miejsca w pamięci i jest bardzo szybki.
Możesz określić minimalną jasność dla każdego węzła (wielkość 7 wynosiłaby 128 x 128), a gdy dowolny węzeł ma określony procent wypełnienia swoich podwęzłów, automatycznie spłaszcza się do dwuwymiarowej tablicy. Oznacza to, że bardzo gęsto zaludniona część (np. Całkowicie zbadany kontynent) będzie miała wydajność tablicy (bardzo szybko), ale słabo zaludniona część (np. Linia brzegowa, którą ktoś wędrował w górę i w dół, ale nie eksplorował w głąb lądu), będzie mają dobrą wydajność i niskie zużycie pamięci.
Mój kod można znaleźć tutaj . Kod jest kompletny, przetestowany (testy jednostkowe i obciążenia) i dość zoptymalizowany. Jednak wewnętrzne działania nie są jeszcze zbyt dobrze udokumentowane, ale wszystkie publiczne metody są, więc powinno być możliwe do wykorzystania. Jeśli ktoś zdecyduje się go wypróbować, skontaktuj się ze mną z pytaniami lub komentarzami.
Nie użyłem go jeszcze do przechowywania danych w pliku, ale jest to interesujący problem i mogę go rozwiązać w następnej kolejności.
źródło
Zamiast tego możesz użyć bazy danych - PostgreSQL ma pewne specjalne możliwości indeksowania zoptymalizowane dla tego typu danych, które są zlokalizowane za pomocą współrzędnych X i Y. Możesz również określić, że zwracane dane mieszczą się w określonym promieniu, a nie w obszarze o kształcie kwadratu lub podłużnego.
PostgreSQL (darmowy i open source)
http://www.postgresql.org/
Istnieją również inne bazy danych, a po stronie klienta może się okazać, że niektóre typy będą lepiej do tego dostosowane, ponieważ mogą one działać autonomicznie (inicjowane przez aplikację klienta gry) lub mogą być włączone jako część biblioteki kodów którego możesz „po prostu użyć”. Zaletą jest to, że nie trzeba projektować schematu indeksowania, ponieważ większość silników baz danych SQL już to robi całkiem dobrze.
Zaletą podejścia opartego na bazie danych jest to, że możesz zmniejszyć swoje fragmenty (lub całkowicie się ich pozbyć i po prostu bezpośrednio użyć kafelków, ale użycie co najmniej małych fragmentów / grup wielu kafelków może być bardziej wydajne w zależności od projektu), a następnie użyj zapytania SQL, aby wprowadzić większy obszar niż jest widoczny. Kafelki można przygotować wcześniej, ładując wstępnie tak, aby zachodziły na nie widoczne obszary gracz poruszy swoją postacią, co zapewni lepszą (miejmy nadzieję płynniejszą) rozgrywkę.
Zauważyłem, że niektóre gry przechowują „pamięć podręczną” danych mapy na lokalnym dysku twardym po ich uzyskaniu za pierwszym razem (niewątpliwie ma to na celu zmniejszenie liczby operacji we / wy w sieci), takich jak Ashen Empires:
Ashen Empires (darmowa gra, piękna implementacja 2D)
http://www.ashenempires.com/
Pomocne będzie również śledzenie znaczników czasu „ostatniej aktualizacji” dla każdego fragmentu / kafelka, ponieważ tam, gdzie dostępne są lokalnie przechowywane dane, zapytanie SQL może zawierać dodatkową klauzulę „GDZIE kolumna znacznika czasu> $ local_timestamp”, dzięki czemu tylko zaktualizowane fragmenty / kafelki otrzymają pobrane (dwie zalety oszczędzania przepustowości, takie jak to, to niższe koszty łączności i mniejsze opóźnienie dla graczy, co stanie się bardziej oczywiste, gdy twoja gra stanie się popularna).
Zrzut ekranu z Ashen Empires (kilka postaci znajduje się w lokalnym banku, a po wyglądzie tych kości na podłodze wygląda na to, że kilka szkieletowych potworów musiało wejść i prawdopodobnie zostało zabitych przez strażników miejscowego miasta):
źródło
Nie przechowuj do nich dostępu, przechowuj tylko niezbędne losowe nasiona, a także zmiany gracza na mapie. Następnie wygeneruj wymagane porcje w czasie wykonywania (uruchom algorytm generowania, a następnie zastosuj zmiany odtwarzacza). Przy prawidłowej i spójnej procedurze generowania wynikowa mapa będzie zawsze taka sama dla tego samego początkowego materiału siewnego.
Teoretycznie możesz zrobić dosłownie nieskończoną mapę, która zapisze w ten sposób bardzo mały plik.
źródło
Czy jest jakiś sposób na podzielenie fragmentów (jakiś rodzaj „subkontynentów / krajów” w waszym świecie)? Być może możesz mieć jakieś pliki indeksów, które pozwalają szybko znaleźć, który podplik / część większego pliku należy załadować, aby mieć fragment pamięci ...
źródło
Możesz wziąć pomysł z Minecraft. Pierwotnie mieli plik na porcję. Teraz używają formatu MCRegion, który grupuje porcje w obszary 32 x 32 i przechowuje jeden z nich na plik.
źródło