UWAGA: Poprosiłem o to na Przepełnienie stosu kilka dni temu, ale miałem bardzo mało wyświetleń i brak odpowiedzi. Pomyślałem, że zamiast tego powinienem zapytać na gamdev.stackexchange.
Jest to ogólne pytanie / prośba o poradę w sprawie utrzymania systemu generowania procedur poprzez wiele aktualizacji po wydaniu, bez niszczenia wcześniej wygenerowanej treści.
Staram się znaleźć informacje i techniki pozwalające uniknąć problemów z efektem motyla podczas tworzenia treści proceduralnych do gier. Podczas korzystania z generatora liczb losowych zaszczepionych można użyć powtarzającej się sekwencji liczb losowych w celu stworzenia odtwarzalnego świata. Podczas gdy niektóre gry po prostu zapisują wygenerowany świat na dysku po wygenerowaniu, jedną z potężnych funkcji generowania procedur jest fakt, że można polegać na odtwarzalności sekwencji numerów w celu wielokrotnego odtworzenia regionu w ten sam sposób, eliminując potrzebę trwałość. Ze względu na ograniczenia związane z moją szczególną sytuacją muszę zminimalizować wytrwałość i w jak największym stopniu polegać na czysto zaszczepionej koncentracji.
Głównym niebezpieczeństwem tego podejścia jest to, że nawet najmniejsza zmiana w proceduralnym systemie generowania może spowodować efekt motyla, który zmienia cały świat. Utrudnia to aktualizację gry bez niszczenia światów eksplorowanych przez graczy.
Główną techniką, której użyłem, aby uniknąć tego problemu, jest zaprojektowanie generowania proceduralnego w wielu fazach, z których każda ma swój własny generator liczb losowych. Oznacza to, że każdy podsystem jest samowystarczalny, a jeśli coś się zepsuje, nie wpłynie to na wszystko na świecie. Wydaje się jednak, że wciąż ma duży potencjał do „złamania”, nawet jeśli jest to odizolowana część gry.
Innym możliwym sposobem radzenia sobie z tym problemem może być utrzymanie kompletnych wersji generatorów w kodzie i używanie odpowiedniego generatora dla danej instancji świata. Wydaje mi się to jednak koszmarem konserwacyjnym i jestem ciekawy, czy ktoś to robi.
Tak więc moje pytanie jest tak naprawdę prośbą o ogólne porady, techniki i wzorce projektowe dotyczące radzenia sobie z tym problemem efektu motyla, szczególnie w kontekście aktualizacji po wydaniu gry. (Mam nadzieję, że nie jest to zbyt szerokie pytanie).
Obecnie pracuję w Unity3D / C #, chociaż jest to pytanie agnostyczne z języka.
AKTUALIZACJA:
Dziękuję za odpowiedzi.
Coraz bardziej przypomina to, że dane statyczne są najlepszym i najbezpieczniejszym podejściem, a także, że podczas przechowywania dużej ilości danych statycznych nie ma opcji, długa kampania w wygenerowanym świecie wymagałaby ścisłej wersji używanych generatorów. Powodem tego ograniczenia jest w moim przypadku potrzeba zapisywania / synchronizacji w chmurze opartej na urządzeniach mobilnych. Moim rozwiązaniem może być znalezienie sposobu przechowywania niewielkich ilości zwartych danych o istotnych sprawach.
Uważam, że koncepcja „klatek” Stormwind jest szczególnie użytecznym sposobem myślenia o rzeczach. Klatka jest w zasadzie punktem ponownie wysuniętym, zapobiegającym efektowi niewielkich zmian, np. Umieszczaniu w klatce motyla.
Odpowiedzi:
Myślę, że omówiłeś tutaj podstawy:
Używanie wielu generatorów lub ponowne rozsiewanie w odstępach czasu (np. Przy użyciu skrótów przestrzennych), aby ograniczyć efekt uboczny zmian. Prawdopodobnie działa to w przypadku treści kosmetycznych, ale jak zauważysz, wciąż może powodować uszkodzenie zawarte w jednej sekcji.
Śledzenie wersji generatora użytej w zbiorze składowania i odpowiednie reagowanie. Co oznacza „właściwe”, może być ...
n
wersje generatora w pliku wykonywalnym. Jeśli plik składowania używa jednej z tych ostatnich wersji, (zaoferuj) zaktualizuj plik składowania do najnowszej wersji. Używa odpowiedniego generatora, aby rozpakować dowolny nieaktualny stan do literałów (lub do delt z danych wyjściowych nowego generatora na tym samym ziarnie, jeśli są bardzo podobne). Odtąd każdy nowy stan pochodzi z najnowszych generatorów. Gracze, którzy nie grają przez długi czas, mogą jednak pozostać w tyle. A w najgorszym przypadku zapisujesz cały stan gry w dosłownej formie, w którym to przypadku możesz równie dobrze ...Jeśli spodziewasz się często zmieniać logikę generowania i nie chcesz naruszać kompatybilności z poprzednimi wersjami, nie polegaj na determinizmie generatora: zapisz cały swój stan w pliku zapisu. (tj. „Nuke to z orbity. To jedyny sposób, aby się upewnić”)
źródło
Podstawowym źródłem takiego efektu motyla jest prawdopodobnie nie generowanie liczb - co powinno być na tyle łatwe, aby utrzymać deterministyczność w jednym generatorze liczb - ale raczej użycie tych liczb przez kod klienta. Zmiany w kodzie są prawdziwym wyzwaniem dla utrzymania stabilności.
Kod: Testy jednostkowe Najlepszym sposobem upewnienia się, że drobne zmiany gdzieś się nie zamanifestują gdzie indziej, jest włączenie dokładnych testów jednostkowych dla każdego generatywnego aspektu w twojej kompilacji. Dotyczy to każdego kompaktowego kodu, w którym zmiana jednej rzeczy może wpłynąć na wiele innych - potrzebujesz testów dla wszystkich, aby zobaczyć na jednej kompilacji, co zostało zmienione.
Liczby: okresowe sekwencje / sloty Załóżmy, że masz jeden generator liczb, który służy do wszystkiego. Nie przypisuje znaczenia, po prostu wyrzuca liczby w sekwencji - jak każdy PRNG. Biorąc pod uwagę to samo ziarno w dwóch przebiegach, otrzymujemy te same sekwencje, tak? Teraz zastanowisz się nad tym i zdecydujesz, że może być 30 aspektów twojej gry, które będą musiały być regularnie dostarczane z losową wartością. Tutaj przypisujemy sekwencję cykliczną złożoną z 30 miejsc, np. Każda pierwsza liczba w sekwencji to nierówny układ terenu, co druga liczba to zaburzenia terenu ... itd. ... co 10 liczba dodaje pewien błąd do stanu AI dla realizmu. Twój okres wynosi 30 lat.
Po 10 masz 20 automatów do wykorzystania w innych aspektach w miarę rozwoju projektu. Kosztem jest oczywiście to, że musisz wygenerować liczby dla miejsc 11-30, nawet jeśli nie są one aktualnie używane , tj. Ukończyć okres, aby wrócić do następnej sekwencji 1-10. Ma to koszt procesora, choć powinien być niewielki (w zależności od liczby wolnych gniazd). Drugą wadą jest to, że musisz mieć pewność, że twój ostateczny projekt może zostać uwzględniony w liczbie miejsc, które udostępniłeś na samym początku procesu programowania ... a im więcej przypisujesz na początku, tym więcej „pustych” miejsc potencjalnie musisz przejść przez każdy z nich, aby wszystko działało.
Skutki tego są:
Oczywiście upłynie długi okres, w którym twoja gra nie będzie publicznie dostępna - w wersji alfa, że tak powiem - abyś mógł zmniejszyć z powiedzmy 30 do 20 aspektów bez wpływu na graczy, tylko na ciebie, jeśli zdasz sobie sprawę, że trzeba było przypisane sposób zbyt wiele szczelin na początku. To oczywiście uratuje niektóre cykle procesora. Pamiętaj jednak, że dobra funkcja skrótu (którą możesz sam napisać) powinna być błyskawiczna. Dlatego uruchomienie dodatkowych miejsc nie powinno być kosztowne.
źródło
Jeśli chcesz wytrwałości w PCG, sugeruję, aby traktować sam kod PCG jako dane . Podobnie jak utrwaliłbyś dane w różnych wersjach z normalną treścią, z wygenerowaną treścią, jeśli chcesz zachować je w różnych wersjach, musisz utrwalić generator.
Oczywiście, jak już wspomniałeś, najpopularniejszym podejściem jest konwersja wygenerowanych danych na dane statyczne.
Nie znam przykładów gier, które trzymają się wielu wersji generatora, ponieważ trwałość jest niezwykła w grach PCG - dlatego permadeath często idzie w parze z PCG. Istnieje jednak wiele przykładów wielu PCG, nawet tego samego typu, w tej samej grze. Na przykład Unangband ma wiele oddzielnych generatorów dla pomieszczeń lochów, a gdy dodawane są nowe, stare nadal działają tak samo. To, czy będzie to możliwe do utrzymania, zależy od twojej implementacji. Jednym ze sposobów utrzymania go w utrzymaniu jest użycie skryptów do implementacji generatorów, utrzymując je w izolacji z resztą kodu gry.
źródło
Utrzymuję powierzchnię około 30000 kilometrów kwadratowych, mieszczącą około 1 miliona budynków i innych obiektów, a także losowe rozmieszczenie różnych rzeczy. Symulacja na zewnątrz ofc. Przechowywane dane to około 4 GB. Mam szczęście, że mam miejsce do przechowywania, ale nie jest nieograniczone.
Losowe jest losowe, niekontrolowane. Ale można to trochę uwięzić:
O to chodzi. Niestety klatki również zużywają dane.
W języku fińskim jest powiedzenie Hajota ja hallitse. Przekłada się na Dziel i podbijaj .
Szybko porzuciłem pomysł precyzyjnego definiowania najmniejszych szczegółów. Random chce wolności, więc ma wolność. Pozwól motylowi latać - w jego klatce. Zamiast tego skupiłem się na bogatym sposobie definiowania (i utrzymywania !!) klatek. Nie ma znaczenia, jakie to samochody, o ile są niebieskie lub ciemnoniebieskie (nudny pracodawca powiedział kiedyś :-)). „Niebieski lub ciemnoniebieski” jest tutaj (bardzo małą) klatką, wzdłuż wymiaru koloru.
Co jest możliwe do zarządzania, do kontrolowania i zarządzania przestrzeniami numerycznymi?
Jeśli chodzi o konserwację i kompatybilność wersji ... mamy
: jeśli wersja = n, to
: elseif wersja = m, to ...
Tak, baza kodu rośnie :-).
Znane rzeczy. Waszym właściwym sposobem na kontynuację byłoby zdefiniowanie bogatej metody dzielenia i podbijania oraz poświęcenia niektórych danych na ten temat. Następnie, o ile to możliwe, daj swobodę (lokalną) randomizacji, w przypadku której nie jest konieczne jej kontrolowanie.
Nie do końca nie do pogodzenia ze śmiesznym „nuke it fom orbit” zaproponowanym przez DMGregory, ale może używasz małych i dokładnych broni nuklearnych? :-)
źródło