Arbeite mit Charakterstatus. Einheitsexperimente

Bei der Entwicklung eines Spiels auf Unity stieß ich auf eine interessante Aufgabe: Wie kann man eine erweiterbare Aktionszeit mit negativen oder positiven Auswirkungen auf einen Charakter gestalten?

Kurz gesagt, ich habe einen Charakter, auf den bestimmte Effekte angewendet werden können, wie z. B. Schwächung, Verstärkung, Geschwindigkeitssteigerung, Geschwindigkeitsabnahme und andere. Um den Spieler über den Effekt eines Effekts zu informieren, bietet das Spiel eine Statuszeile.

Die ersten Versionen dieser Zeile enthielten abgedunkelte Symbole aller Status, und als der Effekt auftrat, leuchtete das gewünschte auf.

Bild

Jeder Status hatte Corutin, das den Effekt nach einer bestimmten Zeit aufhob.
Diese Entscheidung enthält ein ziemlich wichtiges Minus. Wenn aufgrund bestimmter Ereignisse im Spiel derselbe Effekt nach einer kürzeren Zeit als die Dauer des vorherigen ähnlichen Effekts auf den Charakter angewendet wird, kann es zwei Versionen der Ereignisse geben.

  1. Ganz falsch: Parallel zum ersten wird ein zweites Corutin gestartet. Wenn der erste abgeschlossen ist, kehrt er zu seinen ursprünglichen Werten zurück, dh der Effekt wird entfernt, bevor die zweite Coroutine die Arbeit beendet hat.

    Bild
  2. Auch falsch, aber in einigen Fällen akzeptabel: Brechen Sie die erste Coroutine ab und führen Sie die zweite aus. In diesem Fall entspricht die Dauer des Effekts der Dauer des ersten Effekts, bis die Coroutine aufgehoben wird, + der Dauer der zweiten Coroutine.

    Bild

Beide Methoden sind für meine Aufgabe nicht akzeptabel, da ich die Dauer des Effekts verlängern muss, damit ich die Summe der Dauer jedes Effekts erhalte, unabhängig davon, wie oft der Effekt angewendet wird.

Wenn der Charakter auf die Stacheln tritt, ist sein Bein bedingt beschädigt und er kann sich nicht mit der gleichen Geschwindigkeit weiterbewegen. Angenommen, die Geschwindigkeit nimmt um 5 Sekunden ab. Wenn der Charakter nach 3 Sekunden auf andere Stacheln tritt, sollte die Geschwindigkeit um weitere 5 Sekunden verringert werden. Das heißt, 3 Sekunden sind vergangen, 2 + 5 Sekunden von den neuen Spitzen übrig. Die Dauer des Effekts sollte ab dem Moment des Angriffs auf die zweiten Stacheln weitere 7 Sekunden betragen (insgesamt 10).

Und mit Hilfe von Coroutine habe ich keine Lösung für das Problem gefunden, da es unmöglich ist, die verbleibende Zeit bis zur Fertigstellung der Coroutine herauszufinden, um sie der neuen Coroutine hinzuzufügen.

Die Lösung, die ich für dieses Problem gefunden habe, ist die Verwendung eines Wörterbuchs. Der Vorteil gegenüber List besteht darin, dass das Wörterbuch einen Schlüssel und einen Wert hat, was bedeutet, dass ich über einen Schlüssel auf jeden Wert zugreifen kann. Außerdem können Sie mit dieser Lösung die permanenten Statussymbole in der Zeile entfernen und die erforderlichen nach Bedarf einfügen und sie in der Reihenfolge, in der sie auftreten, an Positionen in der Zeile festlegen.

Dictionary<string, float> statusTime = new Dictionary<string, float>(); 

Das Wörterbuch ist in diesem Fall vorteilhafter als die Verwendung der Warteschlange, da die Warteschlange nach den Prinzipien von First In First Out arbeitet, die Dauer der Effekte jedoch unterschiedlich ist. Dies bedeutet, dass der Status, der entfernt werden muss, möglicherweise nicht der erste in der Warteschlange ist.

Dazu habe ich drei Methoden hinzugefügt.

Addstatus

Fügen Sie dem Wörterbuch den gewünschten Status hinzu. Wenn ein solcher Status bereits im Wörterbuch vorhanden ist, fügen Sie die Dauer hinzu. Wenn es keinen Status gibt, berechnen wir die Endzeit und fügen sie dem Wörterbuch hinzu.

 private void AddStatus(string status, float duration) { if (statusTime.ContainsKey(status)) { statusTime[status] += duration; } else { float endTime = Time.timeSinceLevelLoad + duration; statusTime.Add(status, endTime); } } 

RemoveStatus

Wir löschen den Status aus dem Wörterbuch und stellen die ursprünglichen Werte wieder her.

 private void RemoveStatus(string status) { statusTime.Remove(status); RestoreStats(status); } 

Checkstatus

Wenn das Wörterbuch Status enthält, überprüfen wir, ob deren Zeit abgelaufen ist.

Wenn abgelaufen, löschen Sie den Status aus dem Wörterbuch. Da das Ändern des Wörterbuchs in der Schleife es unmöglich macht, die Werte des Wörterbuchs zu synchronisieren, werfen wir die Schlüssel des Wörterbuchs hier in eine reguläre Liste.

 private void CheckStatuses() { if (statusTime.Count > 0) { float currTime = Time.timeSinceLevelLoad; List<string> statuses = new List<string>(statusTime.Keys);  foreach (string stat in statuses) { if (currTime > statusTime[stat]) { RemoveStatus(stat); } } } } 

Von den Pluspunkten ist dies offensichtlich eine erweiterbare Wirkungsdauer. Das heißt, das Problem ist gelöst.
Hier ist jedoch ein ziemlich signifikantes Minus vorhanden. Die Überprüfung auf Status erfolgt unter Aktualisieren jedes Frames. In meinem Spiel gibt es maximal 4 Spieler, was bedeutet, dass diese Methode jeden Frame 4 Mal parallel ausgeführt wird. Bei 4 Zeichen ist dies meiner Meinung nach nicht kritisch, aber ich bin mir sicher, dass dies bei mehr Zeichen zu Leistungsproblemen führen kann. Es ist auch erwähnenswert, dass die Methode geschützt wird, indem überprüft wird, ob Elemente im Wörterbuch vorhanden sind. Bei einem leeren Wörterbuch sollte die Last reduziert werden.

Mit Blick auf die Zukunft (die für dieses Spiel noch völlig neblig ist) bin ich auch im Online-Modus von dieser Entscheidung überzeugt, da eine Überprüfung des Spielerstatus nur für den aktuellen lokalen Spieler und nicht für alle instanziierten Spieler erfolgt.

Source: https://habr.com/ru/post/de426305/


All Articles