Variable Werte von zB Waffen

C

Cage Hunter

Gast
Schönen guten Morgen!
Ich sitze nun seit ca einen Jahr an einem Klon von Masters of Orion 2, natürlich in schönerer Optik und mehr Features. Es soll eigentlich ein würdigerer Nachfolger des 2. Teils sein, als es der 3. war (wer beide kennt wird es verstehen^^)

Ich brüte nun schon seit Wochen an einem Problem wobei ihr mir hoffentlich helfen könnt. Da ich den Fachbegriff -sofern es einen dafür gibt- nicht kenne, konnte Google mir leider nicht viel helfen.
Wie die Überschrift vermuten lässt, habe ich ein Problem mit der Veränderbarkeit von Objekten was ich euch nun anhand von den Waffen erläutern möchte :

Eine Waffe hat eine Zielgenauigkeit, Streuwinkel, Schaden, Explosionsradius, Schussfrequenz, Größe etc.
Wie bei MoO II möchte ich, dass der Spieler die Waffe erweitern kann.
zB soll es 3 verschiedene Größen jeder Waffe geben "point defense", "normal", "heavy mount", diese Größen haben Einfluss auf die Schussfrequenz, Reichweite, Schaden und Gewicht
Jede einzelne Waffe kann jedoch auch über individuelle Zusatzfeatures verfügen (meinetwegen bei einer Laserkanone, kann auf "Panzerbrechend" gestellt werden).
Ein Raumschiff kann jedoch wiederum zB mit einem Zielcomputer ausgerüstet werden, der die Zielgenauigkeit aller verbauten Waffen beeinflusst.

Ich hatte schon mehrfach Lösungen zur Hand, leider fand ich die alle nicht so toll.
Sicher könnte ich einfach die Erweiterungen fest ins Programm einbauen mit z.B. Enums oder Integerwerten die dann in einer monströsen if oder switch-Abfrage durchlaufen -> das finde ich unschön^^
Ich hatte auch mal alle betreffenden Klassen weitervererbt und so zB die WeaponExtension-Klasse erzeugt. Das Problem daran ist meiner Meinung nach der Overhead, denn zB die Fähigkeit "Panzerbrechend" soll sich nur auf den Schaden auswirken, beinhaltet aber auch alle anderen Eigenschaften.
Ein Zielcomputer würde sogar noch mehr Probleme machen, denn er würde in der Schiffserweiterung bis runter zu den Waffenerweiterungen durchgereicht werden müssen...

Meine Frage an euch ist nun : Gibt es eine Möglichkeit sowas ohne großen Overhead hinzubekommen? Ich dachte bspw an Reflections und/oder einen Formelparser, also, dass ich eine Extensionklasse habe die z.B. nur die Formel beinhaltet und das Programm einfach nur rumrechnen muss. Allerdings ist das vermutlich auch nicht die effizienteste Lösung...Reflections oder Strings zu parsen ist sicher unperformant...

Hilfe!?
 

Tharsonius

Bekanntes Mitglied
Ich weiss nicht obs so praktikabel ist aber meine Idee wäre folgende:

Ich würde eine Klasse Schiff erstellen, die alle Features enthält. Da sind dann alle Waffen oder Erweiterungen als Variablen hinterlegt. Die entsprechenden verschiedenen Schiffe sind dann Objekte dieser Klasse und haben halt unterschiedliche Werte.

Die Schiffsklasse berechnet dann abhängig von den entsprechenden Erweiterungen die jeweilige Schussfrequenz, Trefferchance und Schaden etc. Und diese Werte kannst dann halt abfragen. Schussfrequenz brauchst ja nur einmal holen, für die Animation. Die ändert sich ja im Kampf wahrscheinlich nicht.

Im Kampf brauchst dann nur noch sowas wie getHit() aufrufen, und Du bekommst ein Objekt zurück, wo die Trefferchance und Schaden zurückgeliefert wird, fertig modifiziert je nach Ausrüstungsstand.

Dieses Hit Objekt gibst Du dann direkt an das andere Schiffsobjekt weiter und das wiederum entscheidet abhängig von seinen Ausweichwerten und Panzerung, wie viel Schaden am Ende ankommt.


Die entsprechenden Erweiterungen wie beispielsweise Zielcomputer sind im Schiff als Variable vorhanden und modifizieren dann die verschiedenen Berechnungen. Was die Schiffstypen und Waffentypen und dergleichen angeht, da würde ich wirklich Enums verwenden, aber nur um zu bestimmen was im Schiff verbaut ist. Das wäre ja nur interessant, wenn Du dem Spieler das anzeigen willst. Dies ist eine oben offene Liste und kann von Version zu Version recht leicht erweitert werden. Den Schaden und die Schussfrequenz wiederum würde ich im Schiff unterbringen.

Wenn die Waffen wiederum extremst unterschiedlich sind oder verschiedene Waffen in Kombination vorhanden sind, dann würde sicher ein Waffenobjekt Sinn machen, davon sind dann im Schiff verschiedene Objekte integriert. Das Schiff würde aber dann noch immer den Schaden und die Schussfrequenz und dergleichen ermitteln, nur dass dann halt die Waffenobjekt abgefragt würden und daraus dann ein Gesamtwert berechnet würde.
 

Evil-Devil

Top Contributor
Wie wärs wenn du für die Items eine Factory erstellt, die je nach Erweiterung das Objekt erzeugen kann mit samt benötigter Berechnung in Abhängigkeit der Erweiterung. Das würde allerdings voraussetzen das zb. die Formel für den Waffenschaden im Grundsatz immer gleich ist und sich nur durch die einzelnen Parameter unterscheidet. Dann hättest du jedenfalls den Aufwand nur bei der jeweiligen ersten Konstruktion.
 

Empire Phoenix

Top Contributor
Also in meinem GAme löse ich das so:

Jedes Raumschiff hat Krams dran der daran geparentet ist. (bei 2d sollte ne ArrayList es auch tun ^^)
Das Schiff hat Methoden mit denen man zb alle Panzerplatten finden kann.
Jede Schiffkomponente hat die Methode reset und initialize
Jetzt werden fertige Schiffe sozusagen statisch vorberechnet.
Alles wird Resettet.
jetzt wird die initialize aufgerufen von jedem object:
Jede Waffe sucht nach allen bekannten Waffenverbesserungen und fügt deren Effecten sich selber hinzu. (siehe unten der descriptor)
Jedes Schild sucht nach Schildgeneratoren ect.
---
Am ende kann noch zur einfacheren Anzeige eine grobe Gesamtabschätzung gemacht werde, aka alle DPS werden zusammen gerechnet alle Hitpoints der einzelnen Module und so.


Hierbei wird nur noch ein Einheitlicher Descriptor für jeweils jeden Typen benötigt.
(Waffe: Schussfrequenz,Damagetype,Damage,Flugtypenum(Rakete ect))
Wichtig ist das der alle Werte für alle Eigenschaften halten kann, auch wenn eine Waffe diese nicht braucht. (Sonst haste wieder deine IfElse pampe, die Waffen sollten schon selber wissen welche werte sie brauchen und dann halt nur diese benutzen)

Netter Vorteil ist, das das ganze Netzwerktechnisch gut zu realisieren ist, weil man nur noch, schiffsklasse, und die Zusammenfassung schicken muss.

Alternativ je nach Komplexität kann man die Schiffsklasse gleich mit einem kompletten Schiffsdescriptor kombinieren.
 
C

Cage Hunter

Gast
Oh das ging ja schnell^^
Danke für die vielen schnellen Antworten ;)

Ich glaub ich hab mein Problem nicht gut genug beschrieben oder verstehe die Antworten nicht richtig^^

Global sind alle Waffen, Panzerungen, Schilde, Antriebe, Verbesserungen etc bekannt (die werden dann nur irgendwann durch den Researchtree gefiltert)

Ein Spieler baut sich nun ein Schiff zusammen, gibt ihm nen Namen etc und baut 10 große panzerbrechende Laser und 5 kleine schildbrechende Laser. Beide Arten weichen vom "Standardmodell" ab und genau das ist mein Problem. Ich könnte hier auch einen Kopienkonstruktor feuern und die entsprechenden Einstellungen ändern (also Schildbrechung im Schaden einstellen und die Größe ändern etc).
Wenn ich eine Waffe zusammenklicke und ein Reichweitenupgrade drin haben will, dann soll in das neue Waffenobjekt ein Objekt "Extension" gepackt werden, in dem nur drinsteht, wie es heisst (name), was es macht (Beschreibung), und die Werte (also Reichweite +15%, Größe +25%, Kosten +20%). Das Problem ist eben, dass ich das generisch haben will. Es soll keine Klasse "Reichweitenupgrade" geben, sondern nur die Klasse Extension die jede Schiffskomponente verbessern kann ohne eine riesige Memberliste haben zu müssen die größtenteils auf null stehen.
 

Evil-Devil

Top Contributor
Aber das funktioniert doch mit der von Empire Phoenix beschriebenen Methode. Du müsstest lediglich für jede Extension die einzelnen Inhalte sammeln und dann den jeweiligen Endwert für die Extension berechnen.

Angenommen Schiff A ist mit einem non Ex Schild und einer Ex Waffe A und B ausgestattet. Die Waffe A hat Panzerbrechende Munition wodurch sich ihr Schaden erhöht. Die Waffe B ist ein Laser und hat einen Accelerator der es ihr erlaubt häufiger zu schießen.
Man muss nun lediglich beim bauen über die Ausstattung iterieren und die Werte berechnen.

Ein Zielcomputer im Schiff wird vermutlich lediglich auf die Genauigkeit der Waffensysteme auswirken, von daher könntest du dessen Zielwert beim Bau eines neuen Ex Objektes berücksichtigen und entsprechend die Werte einfließen lassen.
 

Empire Phoenix

Top Contributor
Yep genau das ist der Sinn er methode, das ich die komplexität vor dem programminterface und dem user etwas verbergen kann. Hat btw den Vorteil das du wenn du einen Schiffseditor benutzt, das ganze statisch vorberechnen kannst, und wenn neue resarchs sind halt nur alle blaupausen(Descriptoren) updaten musst. Spart dynamische berechnung für jedes schiff für alle werte (die können zb per referenz auf den aktuell gültigen verweisen).
 
C

Cage Hunter

Gast
Also ich hab's jetzt folgendermaßen gelöst :
(Dazu sei gesagt, ich bin ein Freund von Vektoren^^)

Jede Schiffskomponente besitzt einen Vector von Erweiterungen und einen Vector von enum's die den Typen des Objektes darstellen (z.B. Strahlenwaffe, Direktschadenwaffe, Energiewaffe)
Eine Erweiterung besteht jeweils selbst aus einem enum-Typen (z.B. nur kompatibel mit Strahlenwaffen) und 2 Vectoren (einmal enum-Keys und einmal double-Werte)

Ich habe fast alle Member jeder Klasse in eine eigene enum gepackt, welche die Keys für die Erweiterungen darstellen.
Wie Empire Phoenix habe ich für jede Schiffskomponente eine Init-Methode gebastelt die alle im Erweiterungs-Vector enthaltenen Erweiterungen durchgeht und mit dem Objekt verrechnet. Das sind dann 2 for-Schleifen und ein switch der die enum's zu den passenden Formeln "routet".

Wenn nun jemand ein neues Schiff baut und alles mögliche einbaut werden die jeweiligen Kopienkonstruktoren der Komponenten gefeuert, damit die "Basispläne" nicht verändert werden. Bei Veränderung der Komponente wird die init ausgeführt...
Unschön bei der Sache sind noch die Reset-Methoden, da ich, um einen Reset durchführen zu können, immer den original "Bauplan" kennen muss, weil ich ja Kopien der Originale anfertige und keinen Pointer auf's Original will.
Die Resetmethode müsste dann wie der Kopienkonstruktor die Werte rüberziehen, also reset(Original)
Oder ich lasse eine Rückrechnung durchführen, aber da hab ich noch nicht drüber nachgedacht, ob ich einfach das Gegenteil der init durchführen lassen kann...

Danke für Eure Hilfe, ich bin mir zwar nicht sicher, ob Ihr das so gemeint habt wie ich's jetzt gelöst hab, aber mir gefällt diese Lösung auf jeden Fall besser als tausende von Kopien von einer Komponente zu haben, wie es vorher der Fall war :)
 

Marco13

Top Contributor
Hab' jetzt nicht alles gelesen, aber so vom ersten Post her könntest du auch mal einen Blick auf das "Decorator-Pattern" werfen... (kann aber auch sein, dass ich was falsch verstanden habe, und das für deinen Fall unpassend ist...)
 
C

Cage Hunter

Gast
Ja genau, sowas hätte ich gesucht, jedoch hätte diese Art von Umsetzung eine enorme Performancelast zur Folge -jedenfalls so wie ich das verstehe^^-
Da gefällt mir die andere Lösung noch besser, aber vielleicht gibts ja noch mehr Ideen :)
 

Empire Phoenix

Top Contributor
mehr oder weniger so wars gedacht :)
Bis auf das ich keine enums benutze sonder tatsächliche object(die auch in 3d sichtbar sind) als erweiterungen in meinem game.
Typ zum zurückrechnen, erstell dir eine base version auf die nicht verrechnet ist, oder rufe rekursiv über alles was verbaut sit reset auf. (Kopieren, alles resetten komplett neu berechnen, statt imcrementel)
 

Cage Hunter

Aktives Mitglied
Ja ich denke so werde ich das machen :)
Hab mich mal zwischendurch angemeldet, ihr seid alle so nett und hilfsbereit, evtl kann ich anderen ja auch mal was Gutes tun :)
Bin zwar erst am Anfang des 5. Semesters der angewandten Informatik, habe mir aber schon das Eine oder Andere ganz gut angeeignet :rtfm:

Ich kann das Thema leider nicht als erledigt markieren, würde das bitte ein Mod übernehmen? Danke :)
 

Ähnliche Java Themen

Neue Themen


Oben