Datenstruktur für Einheiten-Effekte

Design Patterns, Erklärungen zu Algorithmen, Optimierung, Softwarearchitektur
Forumsregeln
Wenn das Problem mit einer Programmiersprache direkt zusammenhängt, bitte HIER posten.
Antworten
mtorc1
Beiträge: 9
Registriert: 20.02.2021, 17:24

Datenstruktur für Einheiten-Effekte

Beitrag von mtorc1 »

Hallo,

ich arbeite derzeit an einem kleinen 2D-MOBA für den Browser (HTML5 + TypeScript). Wie für das Genre üblich, sollen auf Einheiten alle möglichen Effekte wirken können. Damit meine ich einerseits simple Statusänderungen wie "+5 Schaden", "+20 Rüstung" etc. aber auch Effekte wie "Einheit ist festgefroren", "Einheit verursacht +25% Schaden, wenn sie einen Gegner von hinten trifft", "bei Treffer werden x% Schaden zurückgeworfen".

Ich überlege mir aktuell, wie ich die am Besten implementieren soll. Die naheliegendste Überlegung ist, dass jede Einheit eine Liste an Effekten hat, die jeweils auf entsprechende Events warten. Events haben eine entsprechende Payload, die durch den Effekt als Event Listener manipuliert werden kann. Für Effekte, die sich klar auf eine Einheit beziehen ist das auch so weit so gut. Beispiel: 50% "Dornenschaden"-Effekt:

Code: Alles auswählen

class ThrowbackDamageEffect extends BaseEffect {
  // ...

  public constructor(...) {
    // ...
    // Register callback "this.onDamage" for events of type "EventTypes.damage" sent to entity "this.entityId".
    this.listenerId = manager.addListener(EventTypes.damage, this.entityId, this.onDamage);
  }

  public onDamage(dmgInfo: DamageEvent): void {
    if(dmgInfo.causedByEffect) return;
    manager.broadcast({
      type: EventTypes.damage,
      dealer: this.entityId,
      causedByEffect: true,
      damage: dmgInfo.damage * 0.5
    });
  }

  public onDelete(): void {
    manager.removeLilstener(this.listenerId);
  }
}
So weit, so einfach. Der nächste Schritt wären dann jedoch Dinge wie "Talente" (im Sinne eines WoW oder Diablo) oder "Verbesserungen", die (1) auch nach dem Spielertod bestehen bleiben und (2) auch NPC-Mobs des Spielers betreffen können ("Deine (Unter-)Einheiten verursachen +10 Blitzschaden"). Jetzt wird es schwierig mit oben beschriebenen Modell, weil die Effekte ja beim Spielercharakter gespeichtert sind.

Mein erster Gedanke war dann, sie statt beim Spielercharacter ("Hero") beim Spieler selbst ("Player") zu speichern. Dann kann ein Effekt nicht nur den Spielertod überdauern sondern es ist auch semantisch schöner. Es fühlt sich ja schon etwas schmutzig an, wenn ein Hero-Effekt unmittelbar darauf Einfluss nimmt, wenn zwei NPC sich gegenseitig attackieren. Mit den Effekten beim Player stimmt diese Zuordnung ja, weil die NPCs selber auch zum Player gehören. Dann müssen die Events nur noch speichern, von wem und an wen es geht; und die Effekte müssen noch speichern, auf wen sie jetzt genau alles wirken sollen.

Dann bin ich aber an dem Punkt, dass eigentlich komplett egal ist, wo der Effekt jetzt gespeichert wird, weil er mit seinen Meta-Informationen komplett autark von seinem "Holder" ist. Warum es sich also nicht einfach machen und die Effekte in einem globalen Array speichern, ganz gleich auf wen sie wirken. Daraus ergäbe sich nur ein potenzielles Performance-Problem, weil alle Events stets alle Effekte im ganzen Spiel durchlaufen. Es wäre aber trivial einfach.

Eine Alternative wäre es zu sagen, dass Events in einem Baum auf- und absteigen. Bei folgendem Baum:

Code: Alles auswählen

- World
  - Player 1
    - Hero
    - NPC 1
    - NPC 2
  - Player 2
    - Hero
    - NPC 3
... würde ein Schaden von NPC1 and NPC 3 folgenden Weg nach Effekten abklappern: Flag "Capture" auf true -> NPC1 -> Player1 -> World -> Flag "Capture" auf false -> World -> Player 2 -> NPC3

Letztlich führen beide Wege nach Rom, ich wollte aber gerne fragen, ob jemand hier schon einmal an dieser Stelle stand und welche Erfahrungen er letztlich damit gemacht hat.

Liebe Grüße
Benutzeravatar
Jonathan
Establishment
Beiträge: 1639
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: Datenstruktur für Einheiten-Effekte

Beitrag von Jonathan »

Hi,

prinzipiell hören sich die Überlegungen alle ok an, finde ich. Was jetzt insgesamt die beste Lösung ist und in allen Fällen und auch in der Zukunft am schönsten zu benutzen sein wird, ist vermutlich schwer zu sagen.
Aber eine Anregung hätte ich noch: Wieso nicht Dinge, die komplett unterschiedlich funktionieren, auch unterschiedlich im Code behandeln? In einem Rollenspiel in dem der Spieler kleine Geschütze aufstellen kann, würde man ja auch nicht mit aller Gewalt versuchen, die durch die gleiche Klasse abzudecken wie das Schwert des Spielercharakters, bloß weil beides Schaden verursacht. Gegebenenfalls kann man ja trotzdem Teile der Klassenhierarchie wiederverwenden, aber das bedeutet ja nicht zwangsweise, dass man alle Arten von Effekten an der selben Stelle speichern muss.
Lieber dumm fragen, als dumm bleiben!
Antworten