Ich bin mir nicht sicher, ob Sie das noch lesen, aber ich habe lange mit solchen Problemen zu kämpfen.
Ich habe zahlreiche verschiedene Arten von Affektsystemen entworfen. Ich werde sie jetzt kurz durchgehen. Dies alles basiert auf meinen Erfahrungen. Ich behaupte nicht, alle Antworten zu kennen.
Statische Modifikatoren
Diese Art von System basiert hauptsächlich auf einfachen ganzen Zahlen, um Änderungen zu bestimmen. Zum Beispiel +100 bis max. HP, +10 für Angriffe und so weiter. Dieses System könnte auch Prozente handhaben. Sie müssen nur sicherstellen, dass das Stapeln nicht außer Kontrolle gerät.
Ich habe die generierten Werte für diese Art von System nie wirklich zwischengespeichert. Wenn ich zum Beispiel die maximale Gesundheit von etwas anzeigen möchte, würde ich den Wert sofort generieren. Dies verhinderte, dass die Dinge fehleranfällig und für alle Beteiligten einfacher zu verstehen waren.
(Ich arbeite in Java, daher ist das Folgende Java-basiert, aber es sollte mit einigen Änderungen für andere Sprachen funktionieren.) Dieses System kann leicht mit Aufzählungen für die Änderungstypen und dann mit ganzen Zahlen durchgeführt werden. Das Endergebnis kann in eine Sammlung gestellt werden, die nach Schlüsseln und Werten geordnete Paare enthält. Dies wird eine schnelle Suche und Berechnung sein, so dass die Leistung sehr gut ist.
Insgesamt funktioniert es sehr gut, wenn nur statische Modifikatoren verwendet werden. Code muss jedoch an den richtigen Stellen vorhanden sein, damit die Modifizierer verwendet werden können: getAttack, getMaxHP, getMeleeDamage usw.
Wo diese Methode (für mich) versagt, ist die Interaktion zwischen Buffs sehr komplex. Es gibt keinen wirklich einfachen Weg, um Interaktion zu haben, außer durch ein bisschen Ghetto. Es gibt einige einfache Interaktionsmöglichkeiten. Dazu müssen Sie die Art und Weise ändern, in der Sie die statischen Modifikatoren speichern. Anstatt eine Aufzählung als Schlüssel zu verwenden, verwenden Sie einen String. Diese Zeichenfolge ist der Name der Aufzählung + zusätzliche Variable. 9 Mal von 10 wird die zusätzliche Variable nicht verwendet, daher behalten Sie den Namen der Aufzählung als Schlüssel bei.
Lassen Sie uns ein kurzes Beispiel machen: Wenn Sie in der Lage sein möchten, Schaden an untoten Kreaturen zu ändern, könnten Sie ein geordnetes Paar wie das folgende haben: (DAMAGE_Undead, 10) DAMAGE ist die Aufzählung und Undead ist die zusätzliche Variable. Während Ihres Kampfes können Sie also Folgendes tun:
dam += attacker.getMod(Mod.DAMAGE + npc.getRaceFamily()); //in this case the race family would be undead
Wie auch immer, es funktioniert ziemlich gut und ist schnell. Aber es scheitert an komplexen Interaktionen und hat überall "speziellen" Code. Betrachten Sie zum Beispiel die Situation „25% Chance, sich beim Tod zu teleportieren“. Dies ist eine "ziemlich" komplexe. Das obige System kann damit umgehen, aber es ist nicht einfach, da Sie Folgendes benötigen:
- Bestimmen Sie, ob der Spieler diesen Mod hat.
- Haben Sie irgendwo Code, um die Teleportation auszuführen, wenn dies erfolgreich ist. Der Speicherort dieses Codes ist eine Diskussion für sich!
- Holen Sie sich die richtigen Daten aus der Mod-Map. Was bedeutet der Wert? Ist es der Raum, in den sie sich auch teleportieren? Was ist, wenn ein Spieler zwei Teleport-Mods hat? Werden die Beträge nicht addiert ?????? FEHLER!
Das bringt mich zu meinem nächsten:
Das ultimative komplexe Buff-System
Ich habe einmal versucht, ein 2D-MMORPG selbst zu schreiben. Das war ein schrecklicher Fehler, aber ich habe viel gelernt!
Ich habe das Affektsystem dreimal umgeschrieben. Die erste verwendete eine weniger mächtige Variante der obigen. Der zweite war, worüber ich sprechen werde.
Dieses System hatte eine Reihe von Klassen für jede Modifikation, also Dinge wie: ChangeHP, ChangeMaxHP, ChangeHPByPercent, ChangeMaxByPercent. Ich hatte eine Million dieser Leute - sogar Dinge wie TeleportOnDeath.
Meine Klassen hatten Dinge, die folgendes bewirken würden:
- applyAffect
- removeAffect
- checkForInteraction <--- wichtig
Anwenden und entfernen erklären sich von selbst (obwohl der Affekt bei Dingen wie Prozenten protokollieren würde, um wie viel die HP erhöht wurden, um sicherzustellen, dass der Affekt nachlässt und nur den hinzugefügten Betrag entfernt. Dies war fehlerhaft, lol und Ich habe lange gebraucht, um sicherzugehen, dass es richtig war. Ich habe immer noch kein gutes Gefühl dabei.).
Die checkForInteraction-Methode war ein schrecklich komplexer Code. In jeder der Affects-Klassen (dh ChangeHP) muss der Code festgelegt werden, ob dieser durch den Eingabeeffekt geändert werden soll. Also zum Beispiel, wenn Sie so etwas hatten ...
- Buff 1: Verursacht beim Angriff 10 Feuerschaden
- Buff 2: Erhöht jeglichen Feuerschaden um 25%.
- Buff 3: Erhöht jeglichen Feuerschaden um 15.
Die checkForInteraction-Methode würde alle diese Auswirkungen behandeln. Um dies zu tun, musste jeder Effekt auf ALLE Spieler in der Nähe überprüft werden !! Dies ist darauf zurückzuführen, dass ich über einen bestimmten Bereich hinweg mit mehreren Spielern zusammengearbeitet hatte. Dies bedeutet, dass der Code NIEMALS spezielle Aussagen wie oben hatte - "Wenn wir gerade gestorben sind, sollten wir nach Teleportern nach dem Tod suchen". Dieses System würde es automatisch zum richtigen Zeitpunkt richtig handhaben.
Der Versuch, dieses System zu schreiben, dauerte ungefähr 2 Monate und ließ den Kopf mehrmals explodieren. JEDOCH war es WIRKLICH mächtig und konnte unglaublich viel bewirken - besonders wenn man die folgenden zwei Fakten für die Fähigkeiten in meinem Spiel berücksichtigt: 1. Sie hatten Zielbereiche (dh: Single, Self, Group Only, PB AE Self , PB AE-Ziel, zielgerichtete AE und so weiter). 2. Fähigkeiten können mehr als einen Einfluss auf sie haben.
Wie ich oben erwähnte, war dies das 2. oder 3. Affektsystem für dieses Spiel. Warum bin ich davon weggezogen?
Dieses System hatte die schlechteste Leistung, die ich je gesehen habe! Es war furchtbar langsam, da es so viel Zeit in Anspruch nehmen musste, um alles zu überprüfen, was vor sich ging. Ich habe versucht, es zu verbessern, hielt es jedoch für gescheitert.
Also kommen wir zu meiner dritten Version (und einer anderen Art von Buff-System):
Komplexe Affektklasse mit Handlern
Das ist also so ziemlich eine Kombination der ersten beiden: Wir können statische Variablen in einer Affect-Klasse haben, die viele Funktionen und zusätzliche Daten enthält. Rufen Sie dann einfach Handler auf (für mich sind es eher statische Dienstprogrammmethoden als Unterklassen für bestimmte Aktionen. Aber ich bin sicher, Sie können auch Unterklassen für Aktionen verwenden, wenn Sie dies möchten), wenn wir etwas tun möchten.
Die Affekt-Klasse würde alle wichtigen Dinge enthalten, wie Zieltypen, Dauer, Anzahl der Verwendungen, Möglichkeit zur Ausführung und so weiter und so fort.
Wir müssten noch spezielle Codes hinzufügen, um mit den Situationen fertig zu werden, zum Beispiel beim Tod teleportieren. Wir müssten dies immer noch manuell im Kampfcode überprüfen, und wenn es existiert, würden wir eine Liste der Auswirkungen erhalten. Diese Liste der Effekte enthält alle aktuell auf den Spieler angewendeten Effekte, die sich mit dem Teleportieren nach dem Tod befasst haben. Dann schauten wir uns jeden einzelnen an und überprüften, ob er ausgeführt wurde und erfolgreich war (wir hörten beim ersten erfolgreichen auf). Wenn es erfolgreich war, haben wir einfach den Handler angerufen, um dies zu erledigen.
Interaktion kann gemacht werden, wenn Sie auch wollen. Es müsste nur der Code geschrieben werden, um nach bestimmten Stärkungen für die Spieler / etc. Zu suchen. Da es eine gute Leistung hat (siehe unten), sollte es ziemlich effizient sein, dies zu tun. Es würde einfach komplexere Handler und so weiter brauchen.
So hat es eine Menge der Leistung des ersten Systems und immer noch viel Komplexität wie das zweite (aber nicht so viel). Zumindest in Java können Sie einige knifflige Dinge tun, um in den meisten Fällen die Leistung von fast der ersten zu erreichen (z. B .: eine Aufzählungskarte ( http://docs.oracle.com/javase/6/docs/api/java) /util/EnumMap.html ) mit Enums als Schlüsseln und ArrayList von Affects als Werten: So können Sie schnell feststellen, ob Sie Affects haben (da die Liste 0 wäre oder die Map die Enumeration nicht hätte) und nicht Es macht mir nichts aus, über die Affektlisten der Spieler zu iterieren, wenn wir sie zu diesem Zeitpunkt benötigen. Ich optimiere sie später, wenn es zu einem Problem wird.
Ich öffne gerade mein MUD, das im Jahr 2005 endete, erneut (und schreibe das Spiel in Java anstatt in der FastROM-Codebasis, in der es ursprünglich enthalten war). Vor kurzem habe ich festgestellt, wie ich mein Buff-System implementieren möchte. Ich werde dieses System verwenden, weil es in meinem vorherigen fehlgeschlagenen Spiel gut funktioniert hat.
Hoffentlich findet jemand irgendwo ein paar dieser Erkenntnisse nützlich.