Jak skutecznie przechowywać i wyświetlać mapę kafelków w Internecie?

9

O

To właściwie dwa pytania w jednym. Przede wszystkim szukam sposobu na wydajne przechowywanie dużych ilości danych kafelkowych. Drugi aspekt dotyczy odpytywania zestawu danych i wyświetlania kafelków. Pozwól, że najpierw dam ci trochę tła.

Tworzymy wieloosobową grę opartą na przeglądarce, używając biblioteki CraftyJS do renderowania na kanwie. W tle GUI uruchamiamy Yii Framework na PHP i wszystko to łączy się z generatorem losowych map Python i silnikiem gry.

Tak wygląda pierwsze renderowanie przybliżonej mapy: http://i.imgur.com/khAXtl.png

Przechowywanie danych mapy

Świat gry jest generowany losowo przy każdym uruchomieniu gry. Rozmiar to 100 x 100 sześciokątnych płytek dla każdego gracza. Oznacza to, że w grze trzyosobowej utworzono 90 000 płytek. Obecnie po prostu tworzę tablicę JavaScript, z której renderuję mapę.

Działa to dobrze w przypadku renderowania, ale dla każdego rodzaju interakcji z mapą musimy zapamiętać, który gracz jest właścicielem kafelka, jaka struktura jest na nim zbudowana, jaka jest jego aktualna cena i tak dalej. Początkowo, przynajmniej w przypadku prototypu, chcieliśmy używać MySQL, ale po kilku testach nie jest on tak szybki, jak bym chciał. Być może magazyn obiektów, taki jak MongoDB, lepiej nadaje się do przechowywania danych kafelków zamiast tabeli SQL. A może coś innego?

Wyświetlanie mapy

Innym problemem, który widzę, jest poruszanie się po mapie. Obecnie tworzę Podstępne byty dla każdego kafelka, nawet jeśli nie ma go w okienku ekranu. Jest to powolne, ponieważ chociaż Podstępny renderuje tylko te w okienku ekranu, przechowuje i ewentualnie iteruje wszystkie kafelki każdego zdarzenia renderowania. To, co aktualnie mam, to narysowana mapa, która bardzo wolno się ładuje i zacina się podczas poruszania, teraz chciałbym, aby można ją było odtwarzać.

Moim pierwszym pomysłem było załadowanie wyświetlanego podzbioru kafelków znajdujących się w rzutni. Ale gdy gracz przesunął obszar wyświetlania do pustego obszaru, musiałbym przesłać zapytanie do serwera i poczekać na odpowiedź, tylko wtedy mapa może zostać zrenderowana. Byłoby dobrze w natywnej aplikacji, ale jest opóźniona w grze internetowej.

Sposobem na uzyskanie płynnej wydajności z mapy może być wstępne załadowanie większego zestawu płytek do tablicy javascript i użycie go jako pamięci podręcznej. Gracz miałby kilka ekranów „buforowanych”, a kiedy poruszałby się rzutnią, ładowałbym więcej kafelków do „bufora” JS.

Czy zmierzam w dobrym kierunku? Chciałbym uzyskać więcej informacji od kogoś, kto zrobił coś podobnego. Jestem nowy w tworzeniu gier, ale przeszukiwałem wiele źródeł w ciągu ostatnich kilku tygodni.

element
źródło
1
Dziwi mnie, że zidentyfikowałeś MySQL jako wąskie gardło. Co przetestowałeś, aby dojść do wniosku, że spowalnia to wszystko?
bummzack
@bummzack Jeśli ma rząd na kafelek, ledwo widzę, jak to może być wolne.
aaaaaaaaaaaa
1
@eBusiness Zapytanie o kilka tysięcy wierszy z bazy danych nie powinno stanowić problemu. Powinno to nadal mieścić się w zakresie kilku milisekund. Nie byłoby też 90 000 wierszy, a raczej 30 000 wierszy dla 3 graczy (100 x 100 na gracza).
bummzack
Przepraszam za mylącą matematykę, oprócz strefy gracza jest także dwa razy więcej miejsca między graczami, dzięki czemu są oni w równej odległości od siebie, co daje 90k. Zapytanie nie stanowi problemu. Wybór 90k płytek i zbudowanie mapy to. Ale to nie jest dobry sposób, aby to zrobić. Dokonam serializacji danych mapy i użyję zapytania o kafelki w bazie danych, gdy wymagane będą szczegółowe informacje.
element

Odpowiedzi:

2

Rozgrywka
Przede wszystkim chciałbym cię zapytać, czy naprawdę potrzebujesz 10000 płytek na gracza? Chociaż nie wiem, jaką grę tworzysz, ogólnie prawdą jest, że duże mapy tworzą długie gry. Największa mapa w Civilization 5 to 10240 kafelków, a to tylko działa, ponieważ nie musisz grać na więcej niż ułamku.

Baza danych
Nie powinieneś próbować uruchamiać takiej gry z bazy danych, musisz przechowywać dane w pamięci aplikacji. Możesz użyć bazy danych do wykonania kopii zapasowej gry. Aby uzyskać pełną kopię zapasową, należy zapisać serializację danych gry, a następnie można ją zwiększyć, zapisując podane zamówienia, a następnie ponownie je wykonać, jeśli kopia zapasowa musi zostać użyta.

Przechowywanie JavaScript
Jeśli chodzi o klienta, powiedziałbym, że lepiej ładuj całą mapę, przynajmniej jeśli trzymasz się kafelków gazillionów, mając to wszystko w ładnym drzewie obiektów, może to być trochę za dużo, więc prawdopodobnie powinieneś zachować dane w formacie „semi-binarnym”. Ciągi działają doskonale dla tego rodzaju rzeczy, alternatywnie, możesz bezpiecznie przechowywać niepodpisane liczby całkowite do 53 bitów w 64-bitowej liczbie zmiennoprzecinkowej, umieścić wiele z nich w tablicy i myślę, że zobaczysz dość skromny ślad pamięci.

Wizualizacja JavaScript
Chociaż nie powiem, że niekoniecznie powinieneś używać płótna, tak naprawdę nie potrzebujesz go do takich rzeczy. Skonfiguruj to jako grupę elementów img i zmień właściwość src, aby wyświetlać różne części mapy.

Wskazówka Pro
Nawiasem mówiąc, czasem łatwiej jest udostępnić ziarno użyte do jego wygenerowania niż udostępnić całą mapę.

aaaaaaaaaaaa
źródło
+1, ale niestety aplikacja internetowa napisana w PHP zwykle nie ma środków na utrzymanie stanu gry w pamięci.
bummzack
@bummzack, Ahh, racja, myślę, że jakoś pominąłem słowo PHP i po prostu przeczytałem Python. Wtedy zmiana struktury zaplecza może być w porządku. Node.js może być opcją.
aaaaaaaaaaaa
Buduję konkurencyjnego potentata transportowego, pomyśl o OpenTTD, mapa wielkości 512x512 (262 tys.) Nie jest tak duża dla kilku graczy. Zdaję sobie sprawę, że jest ambitny, ale jeśli mapa nie jest tak duża, gra skończyłaby się zbyt wcześnie. Ponieważ jest to gra wieloosobowa, muszę zsynchronizować zmiany na mapie między graczami. Moim pierwszym instynktem było użycie pojęć, które znam z tworzenia stron internetowych i skorzystanie z bazy danych. Nie musi być super czasie rzeczywistym. Idę z wizualizacją JS, ponieważ chciałbym mieć dynamiczne rzeczy na mapie.
element
Rozważ moją odpowiedź jako kilka wskazówek, w końcu będziesz musiał sam opracować wydajność, to poważny problem i być może będziesz musiał pójść na kompromis.
aaaaaaaaaaaa
Zgadzam się, twoja odpowiedź dała mi do myślenia. Spróbuję znaleźć sposób na zachowanie w pamięci danych mapy serializowanej i zachowanie bazy danych jako kopii zapasowej. Ale potem muszę wymyślić, jak dzielić się zmianami między graczami. Wrócę z tym, co wymyślę po kilku dalszych testach.
element
1

MySQL nie jest wolny. Najprawdopodobniej wykonujesz zapytania naiwne lub masz nieoptymalne wskaźniki. Podejścia NoSQL, takie jak MongoDB, mogą być szybsze, a może nie. Najważniejszy jest tutaj wzór dostępu i wybór zapytania. Można udzielić porady, jak poprawić wydajność, ale nie bez obejrzenia tego, co już robisz.

Sposobem na uzyskanie płynnej wydajności z mapy może być wstępne załadowanie większego zestawu płytek do tablicy javascript i użycie go jako pamięci podręcznej.

Tak oczywiście. Nie ma tu wiele do dodania - klient prosi o kafelki z serwera, więc musisz tylko upewnić się, że te, o które prosisz, obejmują obszar większy niż ekran.

Uzupełnienie:

korzystamy z Yii Framework na PHP i wszystko łączy się z generatorem losowych map i silnikiem gry w Pythonie.

Jeśli znasz się na Pythonie, radzę porzucić pośrednika PHP. Jeśli uruchomisz grę jako proces w języku Python, możesz znacznie łatwiej przechowywać dane kafelków w pamięci i znacznie ograniczyć dostęp do MySQL. Pomaga to, że Python jest również znacznie zdrowszym językiem niż PHP.

Kylotan
źródło