Frage

Eines der Dinge, ich arbeite hat jetzt einige Ähnlichkeiten zu einem Spiel. Zum Zweck der Darstellung werde ich mein Problem mit einem Beispiel aus einem fiktiven, hypothetische Spiel gezogen erklären.

Nennen wir es DeathBlaster 4: Die Deathening . In DB4, haben Sie eine Reihe von Ship Objekte, die periodisch und zufällig Phenomena begegnen, wie sie reisen. Eine gegebene Phenomenon kann null, ein oder mehrere auf einem Effects Ship, die es trifft. Zum Beispiel könnten wir vier Arten von Ships und drei Arten von Phenomena haben.

                              Phenomena
              ==========================================
Ships         GravityWell     BlackHole      NebulaField
------------  ------------------------------------------
RedShip       +20% speed      -50% power     -50% shield
BlueShip      no effect       invulnerable   death              Effects of Various
GreenShip     -20% speed      death          +50% shield        Phenomena on Ships
YellowShip    death           +50% power     no effect    

Zusätzlich Effects können miteinander in Wechselwirkung treten. Zum Beispiel kann ein GreenShip, die beide in einem GravityWell ist und ein NebulaField kann eine Art von Synergie zwischen der erzeugten SpeedEffect und ShieldEffect abzuleiten. In solchen Fällen ist der synergistische Effekt selbst ein Effect - zum Beispiel könnte es eine PowerLevelSynergyEffect sein, die aus dieser Interaktion führt. Keine andere Informationen als die Menge von Effects auf einem Ship wirkende erforderlich zu lösen, was das Endergebnis sein sollte.

Sie beginnen kann ein Problem zu sehen, zeichnet sich hier. Als naiver ersten Ansatz, entweder jedes Ship muss wissen, wie jedes Phenomenon zu handhaben, oder jede Phenomenon wird wissen müssen über jeden Ship. Dies ist natürlich nicht akzeptabel, so möchten wir diese Aufgaben an anderer Stelle bewegen. Offensichtlich gibt es mindestens eine externe Klasse hier, vielleicht ein Mediator oder Visitor irgendeine Art.

Aber was ist der beste Weg, das zu tun? Die ideale Lösung wird wahrscheinlich diese Eigenschaften haben:

  • Wie einfach, eine neue Ship hinzuzufügen, da es eine neue Phenomenon hinzuzufügen ist.
  • Wechselwirkungen, die keine Wirkung erzeugen, sind die Standard-und erfordern keine zusätzlichen Code zu repräsentieren. Konvention über Konfiguration.
  • Versteht, wie sie miteinander interagieren Effects und ist in der Lage, diese Interaktionen zu verwalten, zu entscheiden, was das Endergebnis sein wird.

Ich habe bereits entschieden, was mein Ansatz wird, denke ich, aber ich bin daran interessiert zu hören, was der beste-Design Konsens. Wo würden Sie anfangen? Welche Möglichkeiten würden Sie erkunden?



Follow-up-Update: Vielen Dank für Ihre Antworten, alle. Hier ist, was ich in Liquidation zu tun. Meine Haupt Beobachtung war, dass die Anzahl der verschiedenen Effects scheint klein im Verhältnis zu der Anzahl der möglichen Phenomena × Ships Wechselwirkungen zu sein. Das heißt, obwohl es viele mögliche Kombinationen von Interaktionen, die Anzahl der Arten von Ergebnissen dieser Wechselwirkungen ist eine kleinere Zahl.

Sie können sehen, dass, zum Beispiel, obwohl es 12 Interaktion Kombinationen in der Tabelle sind, gibt es nur fünf Art Effekte: Änderungen an Geschwindigkeit, Änderungen an der Macht, Änderungen zu schützen, Unverwundbarkeit, Tod.

Ich stellte eine dritte Klasse, die InteractionResolver, das Ergebnis von Wechselwirkungen zu bestimmen. Es enthält ein Wörterbuch, das Ship-Phenomenon Paare abbildet Effects (die im Grunde ein Delegierter sind, die die Wirkung und einige Metadaten führt). Jeder Ship Gabe eine EffectStack zum Effects entsprechenden es erlebt hat, wenn das Ergebnis einer Berechnung die Interaktion abgeschlossen ist.

Ships dann die EffectStack verwenden Sie das tatsächliche Ergebnis der Effects auf sie zu bestimmen, durch Modifikatoren, um ihre bestehenden Attribute und Eigenschaften hinzufügen.

Ich mag das, weil:

  1. Schiffe müssen nie über Phänomene kennen.
    • Die Komplexität des Schiffs Phenomena Beziehung in die abstrahiertteractionResolver.
    • Die Details, wie mehrere, möglicherweise komplexe Effekte zu lösen durch die InteractionResolver abstrahiert. Schiffe nur, um die Auswirkungen als notwendig gelten.
    • Dies ermöglicht zusätzliche nützliche Refactorings. Zum Beispiel kann der Weg in dem ein Schiff Effekte verarbeitet könnte, indem sie ein EffectProcessorStrategy unterschieden werden. Der Standard möglicherweise alle Effekte zu verarbeiten, sondern, sagen wir, ein BossShip geringe Effekte ignorieren könnte durch eine andere EffectProcessorStrategy haben.
War es hilfreich?

Lösung

Eine interessante potentielle Möglichkeit wäre, eine Variante der Besuchermuster zu verwenden.

Judith Bishop und R. Nigel Horspool schrieb ein Papier über Entwurfsmuster Effizienz , in dem sie verschiedene Varianten auf dem klassischen Besuchermuster mit C # 3 Funktionen erläutert.

Insbesondere würde ich einen Blick darauf, wie sie mit den Delegierten arbeiten, um das Besuchermuster zu behandeln. eine Liste oder ein Stapel von Delegierten verwenden, könnten Ihnen potentally eine interessante Art und Weise geben, um mehrere Effekte aus mehreren Objekten handhaben, und viel einfacher zu beiden Seiten der Klassenhierarchie zu erweitern (füge Schiffe oder Effekte hinzufügen) ohne große Bruch Code-Änderungen.

Andere Tipps

Nicht ganz ein Antwort, aber mir dies ziemlich schreit „Eigenschaften Muster“. Es gibt eine bekannte Yegge schimpfen über das, denke ich, es wird Ihnen ein paar anständige Zeiger bieten.

http://steve-yegge.blogspot.com /2008/10/universal-design-pattern.html

Das sieht aus wie das klassische OOP Polymorphismus / Besucher Dilemma. Jedoch Ihre Anforderungen erleichtern.

Im Grunde würde ich eine Basisklasse Ship erstellen, die alle konkreten Schiffe aus abzuleiten. Diese Klasse würde Methoden haben:

class Ship
{
  void encounterBlackHole() {}
  void encounterNebula() {}
  ... etc. ...
};

mit leeren Standardkörpern. Wenn Sie ein neues Phänomen, fügen Sie einfach neue Methode mit leeren Körper. (Die Verfahren Argumente haben können, wie Koordinaten oder das Gewicht des schwarzen Loches etc.)

Für die Effekte und deren Interaktion - ich denke, Sie sollten mehr Informationen über hinzufügen, wie Sie es wollen, zum Beispiel. die Wechselwirkungen selten oder üblich sind, sind sie in irgendeiner Art kumulativ, sind sie auf eine begrenzte Anzahl von Variablen beschränkt sie kontrollieren ...

Klingt wie ein klassisches mehr Dispatch Problem zu mir.

Interessante Frage

In einer Art und Weise oder einer anderen, wird ein Schiff haben zu wissen, welche Phänomene es und Phänomene beeinflussen können, welche Auswirkungen sie auf dem Schiff hat.

Dies in einer XML-Datei zur Laufzeit analysiert gespeichert werden.

Vielleicht könnten Sie die verwenden Dekorierermuster die Effekte berechnen . Sie erzeugen verschiedene Phänomene während der Laufzeit.

Angenommen, Ihre Schiffe, die eine Schnittstelle IShip implementieren und überall in Ihrem Code verwenden Sie IShips.

Nun nehmen wir alle Phänomene auch die Schnittstelle IShip (vom Dekorateur Entwurfsmuster erforderlich) implementieren.

IShip myShip = myShip.AddPhenomena(PhenomenaGeneratedByAFactoryForThisShip);

In den Phänomenen, die Methoden aus dem ursprünglichen Schiff wickeln, so dass Sie Änderungen an Eigenschaften und alle führen.

Auch wenn Sie die Strategie Muster jede Art von Erscheinungen erzeugen können Sie‘ d mögen.

ein Phänomen Entfernen, können zu Fuß den Stapel von dekorierten Schiffe verwendet werden, die Sie haben, und Umpackzentrums es, so sehe ich kein Problem da.

Wie für die Synergien, ich denke, ich eine leicht modifizierte Phänomene verwenden würde, das funktioniert nur, wenn das Zielschiff alle Phänomene auf sich hat.

  

entweder jedes Schiff muss wissen   wie jedes Phänomen zu handhaben, oder   Jedes Phänomen muss wissen   über jedes Schiff.

Ich denke, dies ist der Schlüssel zu Ihrem Problem ist, und es ist wahr, wenn jede Schiff-Phänomene Interaktion einzigartig ist. In der Tabelle, die Sie erstellt haben, dass der Fall, so dass für n Schiffe und m Phänomene zu sein scheint, müssen Sie n * m Interaktion spezifizieren. Sie haben Recht, ein Wartungsproblem zu riechen.

Der einzige Ausweg ist zu Schiff-Phänomenen Interaktionen nicht so einzigartig, indem sie die Wirkung von Phänomenen abhängig von den Eigenschaften des Schiffs zu machen. Zum Beispiel könnten wir nur Schiffe mit seltsamem-Aluminiumoxid gebaut sagen werden ein schwarzes Loch überleben.

Aber nur eine Eigenschaft, kaufen Sie nichts, könnte man genauso gut haben angegeben, die Schiffe, die von schwarzen Löchern betroffen sind. Der Schlüssel ist, dass mehrere Eigenschaften die gleiche kombinatorische Explosion zeigen.

So mit seltsamen-Aluminiumoxid gebaute Schiffe schwarze Löcher überleben wird, und ohne kann schneller gehen Schiffe gebaut. 1 Immobilien ermöglicht es Ihnen, zwei Dinge zu spezifizieren (1 Bit = 2 Möglichkeiten). Schiffe gebaut mit corbite Motoren gehen schneller in einer Kettenzone. Schiffe mit beiden corbite Motoren und seltsam-Aluminiumoxid wird in einem Nebel Feld 50% Schild gewinnen, etc.

Die Zugabe von Eigenschaften auf Schiffe können Ihnen die Angabe vermeiden, wie alle Phänomene, die mit jedem Schiff in Wechselwirkung treten, und doch hat noch alle Phänomene und jedes Schiff zeigt ein angemessenes Verhalten.

Wenn es M Schiffe sind, dann müssen Sie nur log2 (M) Eigenschaften jedes Schiff ein einzigartiges Verhalten geben.

Ich denke, die Antwort eines Problems auf wird davon abhängen, wie gut die Frage stellen.

ich glaube, die Art und Weise ist auf Design abhängen, was die Frage ist (oder wird die Frage geht in der Zukunft)

Sie eine Tabelle geben, dann denke ich, die Lösung ist eine Tabelle halten und Abfrage es.

Python-Code hier ein: (nicht getestet und zeigt nur ein Beispiel)

class Ship():
     def __init__(self,type):
         self.type=type
     def encounterPhenomena(self,type): # let Phenomena to process ship
         p = Phenomena(type)
         p.process(self)

class Phenomena():
     processTable = {}
     def __init__(self,type):
         self.type=type
     def process(self,ship):
         try:
             self.processTable[self.type](ship.type) #query the internal table to process ship
         except:
             pass #if Phenomena don't know this ship type then no process..
     def addType(type,processMethod):
         processTable[type]=processMethod #add new Phenomena, and add processMethod

def run():
    A = Ship(type = 'RedShip')
    A.encounterPhenomena(type='GravityWell');

Wenn Prozessmethode geändert, einfach den Prozess Methode in der Klasse Phenomena ändern.

Wenn Sie denken, Schiff müssen wissen, wie Phänomene zu verarbeiten, dann Prozess-Methode in die Schiffsklasse ändern.

oder Sie denken, es gibt andere Dinge nicht nur Phänomene müssen Status von Schiffs ändern (wie andere Schiffe, Schwarm rock), Sie brauchen eine Prozesstabelle in Schiffsklasse zu halten und machen Phenomena eines davon,

sprechen wieder, wie man Design auf die Frage seiner selbst ist abhängig sind.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top