(RPG) Projekt tabeli zrzutu

18

Myślę, że to pytanie dotyczy bardziej gier typu MMO i gier podobnych do Diablo.

Jakie są typowe projekty wdrażania tabeli upuszczania, w której potwór może upuszczać różnego rodzaju przedmioty w zależności od procentu? Wydaje mi się, że najprostszym sposobem jest stworzenie słownika „procentowej wagi” dla typów przedmiotów, ale trudno to rozszerzyć, jeśli chcemy wprowadzić nowe typy przedmiotów (na przykład, gdy rozszerzenie D2 obejmuje runy i przedmioty nowej klasy)

Extrakun
źródło
4
Dlaczego podczas dodawania nowych elementów trudno jest rozszerzać słowniki procentowe? Mam na myśli, że jeśli nie musisz mieć wszystkich wartości procentowych, aby uzyskać sumę 100% (i jest tak tylko w przypadku, gdy chcesz, aby potwór zawsze upuszczał pojedynczy przedmiot, co jest dla mnie dość dziwne), nie widzę problem.
n0rd
1
Powiedz Orc => {„sztylet”, „miecz” „zbroja”}, a ja mam nowy typ przedmiotu, na przykład runa; Będę musiał zaktualizować wszystkie słowniki związane z każdym typem potwora bezpośrednio. Oczywiście nie jest to nic, czego kolejna warstwa pośrednictwa nie może rozwiązać. Pytanie brzmi, jak wygląda ta warstwa?
Extrakun
Nie jestem pewien, dlaczego uważasz, że aktualizacja słownika jest trudna. W Pythonie rozszerzenie jednego słownika o nowe wartości odbywa się na przykład za pomocą jednej metody. Czy możesz wyjaśnić, gdzie według ciebie jest trudność?
Kylotan
2
Extrakun, jeśli spojrzysz na moją odpowiedź poniżej, znajdziesz odpowiedź na twoje pytanie „kolejnej warstwy pośredniej”. Zamiast traktować krople jak płaski stół, możesz zbudować je z zagnieżdżonych wyrażeń. Jeśli zezwolisz na nazwane makra (tj. Funkcje), możesz ponownie wykorzystać fragmenty tabeli upuszczania w różnych jednostkach.
wspaniałomyślny
2
Właśnie natknąłeś się na „haczyk” związany z tworzeniem gier. Oczywiście, możesz stworzyć grę w ciągu dwóch dni, ale potem nadejdzie pięć lat dodawania treści. A dodawanie treści jest miażdżące. SZLIFOWANIE.
Tor Valamo,

Odpowiedzi:

22

Dla roguelike, nad którym pracowałem, zaimplementowałem dość elastyczny system danych do generowania zrzutów. Udokumentowałem to tutaj . Zasadniczo jest to trochę DSL do wybierania wielu losowo wybranych pozycji.

Prosta kropla wygląda następująco:

1-10 copper coin

Po prostu mówi, aby upuścić losową liczbę monet miedzianych od 1 do 10. Rzeczy stają się bardziej elastyczne po dodaniu oddziałów:

one of
    turquoise stone (50%)
    onyx stone (25%)
    malachite stone (15%)
    jade stone (10%)

„Jeden z” wybiera jedną ze swoich gałęzi potomnych na podstawie podanych prawdopodobieństw, a następnie ocenia to. Krople mogą upuścić więcej niż jeden przedmiot:

any of
    turquoise stone (50%)
    onyx stone (25%)
    malachite stone (15%)
    jade stone (10%)

Spowoduje to ocenę wszystkich podgałęzi i upuści je, jeśli przejdzie ich prawdopodobieństwo. Istnieją również inne gałęzie do wybierania przedmiotów na podstawie lochów i poziomu gracza.

Ponieważ mogą się one skomplikować, pozwala także definiować nazwane makra, zasadniczo funkcje, które rozwijają wyrażenie gałęzi i mogą być ponownie użyte w wielu kroplach. W ten sposób, jeśli na przykład wszystkie krasnoludy upuszczą ten sam rodzaj łupów, możesz dla tego zrobić jedno makro i użyć go we wszystkich typach potworów zamiast kopiować i wklejać ogromne tabele dropów.

Przykład upuszczenia jednego potwora :

:: ancient dragon
    glyph   = D
    groups  = dragon
    drops
        (coins)
        2-3(1:8) one of
            (any-weapon)
            (any-armor)

Tutaj (coins), (any-weapon)i (any-armor)są wszystkie połączenia makro:

(any-armor)
    one of
        (shield)
        (helm)
        (boots)
        (gloves)
        (cloak)
        (robe)
        (soft-armor)
        (hard-armor)

co z kolei wywołuje takie rzeczy jak:

(cloak)
    one near level
        cloak (10)
        velvet cloak (20)
        fur-lined cloak (50)

Możesz zagnieżdżać wyrażenia upuszczania dowolnie głęboko jak prawdziwy język programowania. Daje to możliwość komponowania, której nie da proste podejście oparte na tabeli.

Jak wszystkie systemy oparte na danych, możesz się przytłoczyć, budując nieprzenikalnie skomplikowane upuszczenia, ale to spełnia moje cele:

  1. Być w stanie określić, jakie rzeczy są całkowicie usuwane poza kodem.
  2. Prosta implementacja systemu podstawowego w kodzie.
  3. Bądź w stanie dostroić to, co upuszczają określone potwory, aby gracz mógł przeprowadzić eksplorację zorientowaną na cel. („Potrzebuję naszyjnika. Będę szukać krasnoludów, ponieważ mają tendencję do upuszczania.”)

Kod C #, który to implementuje, znajduje się tutaj .

hojny
źródło
To jedno wdrożenie, którego wcześniej nie widziałem. Dzięki!
Extrakun,
12

W Stendhal nasze tabele łupów są listami. Każdy wpis zawiera nazwę towaru, minimalną i maksymalną ilość oraz prawdopodobieństwo. Struktura wewnętrzna jest bardzo podobna do tego, co wyświetlamy na stronie stworzenia .

Jest dla nas ważne, aby projektanci gier, którzy mają dużą wiedzę o świecie, mogli zdefiniować takie rzeczy. Oznacza to, że bez zrozumienia złożonej logiki na poziomie kodu programu. Więc nie mamy definicji stworzeń i przedmiotów w kodzie programu, ale przenieśliśmy je do plików .xml, takich jak elves.xml lub club.xml . Mamy dla nich edytor GUI, ale większość projektantów gier bezpośrednio modyfikuje plik .xml.

W celu ułatwienia rozbudowy stworów i przedmiotów używamy systemu bloków konstrukcyjnych: Nie ma klasy programu dla „elfa” lub „łucznika elfa”. Ale istnieje wiele klas związanych z zachowaniem, takich jak „tchórz”, „patrol”, „agresywny”, „łucznik”, „uzdrowiciel”. Projektanci mogą definiować nowe stworzenia wybierając te zachowania bez pisania kodu programu: Na przykład, aby stworzyć „łucznika elfa”, narysuj duszka elfa łukiem i zdefiniuj go jako „ofensywny”, „łucznik”. Następnie zdefiniuj poziom i podobne atrybuty i dodaj kilka elfich przedmiotów do tabeli łupów.

W przypadku przedmiotów mamy podobne podejście, ale obecnie jest ono ograniczone do jednego zachowania: Projektant może dodać nowy przedmiot i zdefiniować takie zachowanie, jak „ConsumableItem”, „KeyItem” lub „AttackItem”, „Zaklęcie”, „Przewiń” bez konieczność programowania logiki.

Hendrik Brummermann
źródło
8

W grach stołowych D&D istnieje koncepcja rodzajów łupów. Większość potworów spadnie z jednego lub więcej stołów, a te stoły byłyby tym, co zaktualizowałbyś w swoim rozszerzeniu. Potwory nadal upuszczałyby „65% pospolitych, 10% klejnotów, 15% dzieł sztuki, 10% narzędzi”, ale aktualizowałbyś zawartość każdej z tych tabel.

np. Klejnoty zawierają miejsca z losowymi zakresami, które zwracają „1 klejnot (25%) 2 klejnoty (50%) 5 klejnotów (75%) 100 klejnotów”. a jeśli chcesz dodać specjalne klejnoty runiczne, zaktualizuj tabelę do „1 klejnot (25%) 2 klejnoty (50%) 5 klejnotów (75%) 100 klejnotów (95%) 1 runegem”.

Ale z drugiej strony, jeśli masz już ważenie procentowe, dlaczego nie zaktualizować wszystkich tabel potworów w twoim rozszerzeniu? Z pewnością takie tabele mają niewielką ładowność w porównaniu do tekstur i siatek. Nie musisz też utrzymywać sumowania wartości procentowych nawet do 100, to tylko założenie, które na początku założyłeś i możesz zsumować rzeczywistą sumę przed wygenerowaniem swojej losowej wartości. Jeśli wagi sumują się do 120, to po prostu wygeneruj wartość z 1-120 zamiast z 1-100.

Richard Fabian
źródło
3

Na powierzchni wydaje się to takie samo, jak problem „ważonej losowej selekcji”.

Algorytm określania zdarzeń losowych

Przydziel względne prawdopodobieństwa każdemu zdarzeniu, dodaj je, a następnie wybierz losową liczbę z tego zakresu, aby zdecydować, które zdarzenie chcesz.

Nawet jeśli wolisz używać wartości procentowych - czyli tego samego systemu, skalowanego do 100 - przeceniasz, jak trudno jest dodawać różne elementy. Jeśli masz 100%, a następnie dodajesz 20% w rozwinięciu, po prostu podziel wszystkie wartości przez (120/100) i wrócisz do 100%.

Kylotan
źródło