Erlauben Sie mir zunächst, mich zu entschuldigen, da dies ein ziemlich langer Beitrag sein wird. Ich habe viel über dieses Thema nachgedacht und sogar mit Konzepten und früheren Implementierungen experimentiert .
Wenn ich mir einen Beutetisch vorstelle, denke ich immer an etwas Ähnliches wie World of Warcraft. Hier ist ein Bildbeispiel:
Verwenden Sie jetzt nur visuelle Hinweise, um die Funktionsweise des Beutesystems zu analysieren, aber lassen Sie uns auch einige Wowhead-Statistiken verwenden, um ein besseres Verständnis für das zu erlangen, womit wir es zu tun haben. Hier ist ein kurzes Modell:
Wie Sie sehen können, ist das Beutesystem, das World of Warcraft verwendet, ziemlich dynamisch. Es ist nicht gerade ein Roulette, kann aber auf seiner Basisebene in gewisser Weise einem ähneln. Bei meiner ersten Implementierung eines Beutetisches wurde das Konzept eines Roulettes und sogar eines Wiegemechanikers vermieden (wodurch bestimmte Gegenstände mit größerer Wahrscheinlichkeit vom Tisch genommen werden und andere verlassen werden). Die Idee, Gegenstände dieser Art zu wiegen, gefiel mir nicht. Also habe ich so etwas gemacht:
Diese Beutetabelle war eher eine "Liste". Grundsätzlich würde ich jedes Element durchlaufen, seine Wahrscheinlichkeit testen und wenn es erfolgreich wäre, würde ich es einer Liste von Tropfen hinzufügen. Theoretisch hat das gut funktioniert, aber ich habe schnell einen schwerwiegenden Fehler im System bemerkt.
Betrachten Sie diese Ausgabe:
Ore_Copper x1
Nugget_Copper x2
Gem_Diamond x1
Gem_Emerald x1
Gem_Topaz x1
Das ist übertrieben, aber wenn man sich die Grundstruktur ansieht, ist das durchaus möglich ... aber was ist, wenn wir nicht 4 Arten von Edelsteinen fallen lassen wollten? Aufgrund der kollektiven Wahrscheinlichkeit der Edelsteine erhalten Sie praktisch garantiert mindestens einen, da Sie eine Chance von 10% * 5 haben, einen zu erhalten. Nun, das mag für ein Spiel in Ordnung sein, aber es ist nicht das, was ich beabsichtigt hatte. Ich wollte die Fähigkeit, Edelsteine fallen zu lassen, aber mit nur einer Chance. Ich wollte, dass die Wahrscheinlichkeit, einen Edelstein zu erhalten, genau 10% beträgt. Also ... wie beheben wir das? Folgendes habe ich mir ausgedacht:
Also, was passiert jetzt? Wir haben im Wesentlichen ein Roulette-System gebaut. Anstelle einer direkten Sammlung von LootTableItem
s verschieben wir jetzt Elemente in unabhängige Sammlungen. LootTableList
s. Jede Liste hat ihre eigene Wahrscheinlichkeit, ähnlich wie mein Original LootTable
, aber jetzt können wir Elemente erfolgreich in einem eigenen "Pool" in einem einzigen organisieren LootTable
. Wenn ein Element weniger selten sein soll als ein anderes, fügen wir dem gewünschten Element einfach zusätzliche Instanzen hinzu LootTableList
. Wenn mein LootTable
Algorithmus ausgeführt wird, wählt er ein Element aus dem aus LootTableList
. Das ist großartig, hat aber auch ein anderes Problem aufgeworfen. Was wäre, wenn ich wollte, dass alle Gegenstände in einem LootTableList
fallen gelassen werden oder eine Chance haben, fallen gelassen zu werden? Nun, ich ging voran und fügte ein zusätzliches Feld hinzu, genanntCollectAll
. Wenn dieses Feld aktiviert ist, wird vermieden, dass ein Element ausgewählt wird, und stattdessen werden alle Elemente im Feld ausgewählt LootTableList
.
Nachdem ich das alles geplant und meine Hausaufgaben zu diesem Thema gemacht hatte, kam ich dazu, diese Art von LootTable zu erstellen. Ich bin mir auch ziemlich sicher, dass dies auch die Art von LootTable ist, die World of Warcraft verwendet, oder zumindest konzeptionell sind sie sehr nahe beieinander. Hier ist der Code:
using System;
using System.Collections.Generic;
using System.Linq;
using GrimoireDevelopmentKit.Framework.Interfaces;
using GrimoireDevelopmentKit.Framework.Maths;
using GrimoireDevelopmentKit.Framework.Utilities;
namespace GrimoireDevelopmentKit.Framework.Collections
{
[Serializable]
public class LootTable : Dictionary<string, LootTableList>, ICopy<LootTable>
{
public string Identifier { get; set; }
public AdvancedRandom Random { get; set; }
public int TotalItems
{
get
{
int total = 0;
foreach (LootTableList list in this.Values)
{
total += list.Values.Count;
}
return total;
}
}
public LootTable(string identifier = null)
: this(identifier, new AdvancedRandom())
{
}
public LootTable(string identifier, AdvancedRandom random)
{
Identifier = identifier;
Random = random;
}
public void Add(LootTableList list)
{
if (!Contains(list))
{
Add(list.Identifier, list);
}
else
{
throw new ArgumentException("Key: '" + list.Identifier + "' already exists!");
}
}
public bool Remove(LootTableList list)
{
return Remove(list.Identifier);
}
public bool Contains(string listIdentifier)
{
return ContainsKey(listIdentifier);
}
public bool Contains(LootTableList list)
{
return Contains(list.Identifier);
}
public List<LootTableResult> Next()
{
Range probabilityScope = new Range(0, 100);
List<LootTableResult> drops = new List<LootTableResult>(TotalItems);
foreach (LootTableList list in Values)
{
bool success = Random.NextRange(probabilityScope) <= list.Probability;
if (success)
{
if (list.CollectAll)
{
foreach (LootTableItem item in list.Values)
{
int quantity = Random.NextRange(item.Quantity);
if(quantity > 0)
{
drops.Add(new LootTableResult(item.Identifier, quantity));
}
}
}
else
{
LootTableItem item = list.ElementAt(Random.NextInteger(0, list.Count)).Value;
int quantity = Random.NextRange(item.Quantity);
if(quantity > 0)
{
drops.Add(new LootTableResult(item.Identifier,quantity));
}
}
}
}
return drops;
}
public void Copy(LootTable other)
{
this.Clear();
this.Identifier = other.Identifier;
this.Random = other.Random;
foreach (LootTableList list in other.Values)
{
this.Add(list.MakeCopy());
}
}
public LootTable MakeCopy()
{
LootTable copy = new LootTable();
copy.Copy(this);
return copy;
}
}
}
Meine Frage:
Gibt es eine bessere und modernere konzeptionelle Grundlage, auf der ich diese Art von Beutetisch erreichen könnte?
Gibt es auf dieser Website Spieleentwickler, die Beutetabellen dieser Art erstellt haben? Ich möchte nur wissen, ob ich mein Konzept verbessern kann, nicht nur den Code , sondern das Konzept selbst. Ich bin sicher, dass noch mehr getan werden kann, um meine Arbeit zu verbessern. Ich suche nur Rat von Leuten, die Erfahrung in diesem Thema haben.
Ich kann meine Implementierung auch in einem separaten Projekt veröffentlichen, wenn dies den Leuten helfen würde, mir zu helfen . Tatsächlich denke ich, dass ich jetzt tatsächlich daran arbeiten werde.
BEARBEITEN
Ich habe gerade festgestellt, dass ich vergessen habe, die Anzahl der Mengen in den LootTableLists zu codieren. Wenn diese codiert werden, kann eine LootTableList während desselben Ablegens mehrmals erfasst werden.
quelle
Antworten:
Du bist auf dem richtigen Weg. Hier würde ich anfangen. Alle Ihre Komponenten teilen sich die Kennung und Menge. Es ist sinnvoll, eine Zufallseigenschaft hinzuzufügen und ein zusammengesetztes Muster zu verwenden .
Sie können dann Ihre Erweiterungstabelle für die Beutetabelle erstellen
Droppable
.Sie benötigen auch Ihre Artikelklasse, die sich ebenfalls erweitern würde
Droppable
Hinweis
CompositeItem
enthält Verweise auf andereDroppable
Komponenten. Das heißt, Sie können sie dann so oft weiterleiten, wie Sie möchten, z.Alle diese Szenarien sind dann möglich, ohne den Abhängigkeitsbaum zu stark zu ändern. Das einzige, woran Sie sich erinnern müssen, ist offensichtlich die Randomisierung zu implementieren und zu beachten, dass die Summe der Chancen verschachtelter Droppables der Einfachheit halber 1 (100%) betragen sollte.
Ein weiterer großer Vorteil der Verwendung von zusammengesetzten Mustern ist die Möglichkeit, diese Implementierung später für Daten zu verwenden, die Sie dynamisch aus statischen XML- (oder JSON-) Dateien lesen können.
quelle