Ich bin ein unerfahrener Programmierer , der mit Python ein "roguelartiges" Spiel im Stil von FTL erstellt (noch kein PyGame, da ich mich immer noch nur mit Text befasse).
Mein Spiel wird eine große Anzahl von Waffen enthalten (ungefähr 50 für Anfänger), die einzigartige Fähigkeiten ergeben. Ich habe Mühe zu verstehen, wie man den Objektcode so strukturiert, dass er sowohl leistungsfähig (so dass Waffen völlig andere Effekte haben) als auch erweiterbar ist (so dass ich später problemlos weitere Waffen hinzufügen kann, indem ich sie z. B. in einen Ordner lege ).
Mein erster Instinkt war, eine BasicWeapon-Klasse zu haben und verschiedene Waffen von dieser Klasse zu erben. Dies scheint mir jedoch problematisch zu sein: Entweder muss ich die BasicWeapon-Klasse so machen, dass sie im Grunde genommen unbrauchbar ist (die einzigen Merkmale, die alle Waffen gemeinsam haben, sind Name und Typ (Pistole, Axt usw.)), oder ich muss jeden voraussagen Ein einzigartiger Effekt, den ich mir jemals ausgedacht und in BasicWeapon codiert habe.
Letzteres ist eindeutig unmöglich, Ersteres kann jedoch weiter bearbeitet werden. Das lässt mich jedoch bei der Frage zurück: Wo lege ich den Code für einzelne Waffen ab?
Erstelle ich plasmarifle.py, rocketlauncher.py, swarmofbees.py usw. usw. und lege sie alle in einem Ordner ab, aus dem das Spiel sie importieren kann?
Oder gibt es eine Möglichkeit, eine Datei im Stil einer Datenbank (möglicherweise so einfach wie eine Excel-Tabelle) zu haben, die irgendwie einen eindeutigen Code für jede Waffe enthält - ohne auf eval / exec zurückgreifen zu müssen?
In Bezug auf die letztere Lösung (Datenbank) denke ich, dass das grundlegende Problem, mit dem ich zu kämpfen habe, darin besteht, dass ich zwar verstehe, dass es wünschenswert ist, die Trennung zwischen Code und Daten beizubehalten, ich aber das Gefühl habe, dass die Waffen die Grenze zwischen "Code" verwischen. und "Daten" ein wenig; Sie repräsentieren die große Vielfalt ähnlicher Dinge, die im Spiel zu finden sind. In diesem Sinne sind sie wie Daten, aber für die meisten von ihnen ist mindestens ein eindeutiger Code erforderlich, der mit keinem anderen Element geteilt wird. In diesem Sinne sind sie natürlich Code.
Eine Teillösung, die ich an anderer Stelle auf dieser Site gefunden habe, schlägt vor, der BasicWeapon-Klasse eine Reihe leerer Methoden zuzuweisen - on_round_start (), on_attack (), on_move () usw. - und diese Methoden dann für jede Waffe zu überschreiben. In der relevanten Phase des Kampfzyklus ruft das Spiel die geeignete Methode für die Waffe jedes Charakters auf, und nur diejenigen, für die Methoden definiert wurden, tun tatsächlich etwas. Dies hilft, aber es sagt mir immer noch nicht, wo ich den Code und / oder die Daten für jede Waffe ablegen muss.
Gibt es eine andere Sprache oder ein anderes Tool, das ich als Halbdaten-, Halbcode-Chimäre verwenden kann? Mache ich mich an die gute Programmierpraxis?
Mein Verständnis von OOP ist bestenfalls lückenhaft, daher würde ich Antworten begrüßen, die nicht zu Informatik sind.
EDIT: Vaughan Hilts hat in seinem Beitrag unten klargestellt, dass ich im Wesentlichen von datengesteuerter Programmierung spreche. Die Essenz meiner Frage lautet: Wie kann ich ein datengesteuertes Design so implementieren, dass die Daten Skripte enthalten können, sodass neue Waffen neue Dinge tun können, ohne den Hauptprogrammcode zu ändern?
quelle
Antworten:
Sie möchten mit ziemlicher Sicherheit einen datengetriebenen Ansatz, es sei denn, Ihr Spiel wird völlig unerwartet und / oder prozedural bis in den Kern generiert.
Dies umfasst im Wesentlichen das Speichern von Informationen zu Ihren Waffen in einer Auszeichnungssprache oder einem Dateiformat Ihrer Wahl. XML und JSON sind beide gute, lesbare Optionen, mit denen sich das Bearbeiten relativ einfach gestalten lässt, ohne dass komplizierte Editoren erforderlich sind, wenn Sie nur einen schnellen Einstieg benötigen. ( Und Python kann XML auch ziemlich einfach analysieren! ) Sie würden Attribute wie "Macht", "Verteidigung", "Kosten" und "Statistiken" festlegen, die alle relevant sind. Die Art und Weise, wie Sie Ihre Daten strukturieren, liegt bei Ihnen.
Wenn eine Waffe einen Statuseffekt hinzufügen muss, weisen Sie ihr einen Statuseffektknoten zu und geben Sie dann die Auswirkungen eines Statuseffekts über ein anderes datengesteuertes Objekt an. Dies macht Ihren Code weniger abhängig von dem jeweiligen Spiel und macht das Bearbeiten und Testen Ihres Spiels trivial. Es ist auch ein Bonus, nicht ständig neu kompilieren zu müssen.
Eine ergänzende Lektüre finden Sie unten:
quelle
(Es tut mir leid, die Antwort anstelle eines Kommentars zu übermitteln, aber ich habe noch keinen Repräsentanten.)
Vaughans Antwort ist großartig, aber ich möchte meine zwei Cent hinzufügen.
Einer der Hauptgründe, warum Sie XML oder JSON verwenden und zur Laufzeit analysieren möchten, ist das Ändern und Experimentieren mit neuen Werten, ohne den Code neu kompilieren zu müssen. Da Python interpretiert wird und meiner Meinung nach ziemlich lesbar ist, könnten Sie die Rohdaten in einer Datei mit einem Wörterbuch und allem, was organisiert ist, haben:
Auf diese Weise importieren Sie einfach die Datei / das Modul und verwenden es als normales Wörterbuch.
Wenn Sie Skripte hinzufügen möchten, können Sie die dynamische Natur von Python- und 1st-Class-Funktionen nutzen. Sie könnten so etwas tun:
Obwohl ich glaube, dass das gegen datengetriebenes Design wäre. Um 100% DDD zu sein, hätten Sie Informationen (Daten), die spezifizieren, welche Funktionen und welcher Code für eine bestimmte Waffe verwendet würden. Auf diese Weise wird DDD nicht beschädigt, da Daten nicht mit Funktionen gemischt werden.
quelle
Datengetriebenes Design
Ich habe so etwas wie diese Frage zur Codeüberprüfung eingereicht kürzlich .
Nach einigen Vorschlägen und Verbesserungen war das Ergebnis ein einfacher Code, der eine relative Flexibilität bei der Waffenerstellung basierend auf einem Wörterbuch (oder JSON) ermöglichen würde. Die Daten werden zur Laufzeit interpretiert und einfache Überprüfungen werden von der
Weapon
Klasse selbst durchgeführt, ohne dass ein vollständiger Skriptinterpreter erforderlich ist.Datengesteuertes Design, obwohl Python eine interpretierte Sprache ist (sowohl Quell- als auch Datendateien können bearbeitet werden, ohne dass sie neu kompiliert werden müssen), scheint in Fällen wie dem von Ihnen vorgestellten die richtige Vorgehensweise zu sein. Diese Frage geht näher auf das Konzept, seine Vor- und Nachteile ein. Es gibt auch eine schöne Präsentation über die Cornell University .
Im Vergleich zu anderen Sprachen, wie C ++, die wahrscheinlich eine Skriptsprache (wie LUA) verwenden würden, um die Interaktion mit der Daten-Engine und Skripts im Allgemeinen zu verarbeiten, und ein bestimmtes Datenformat (wie XML), um die Daten zu speichern, kann Python dies tatsächlich tun alles für sich allein (unter Berücksichtigung des Standards,
dict
aber auchweakref
letzterer speziell für das Laden und Zwischenspeichern von Ressourcen).Ein unabhängiger Entwickler kann den datengetriebenen Ansatz jedoch möglicherweise nicht bis zum Äußersten verfolgen, wie in diesem Artikel vorgeschlagen :
Vielleicht könnte man mit Python vom besten objektorientierten und datengetriebenen Ansatz profitieren, der sowohl auf Produktivität als auch auf Erweiterbarkeit abzielt.
Einfache Probenaufbereitung
In dem speziellen Fall, der bei der Codeüberprüfung erörtert wurde, werden in einem Wörterbuch sowohl die "statischen Attribute" als auch die zu interpretierende Logik gespeichert, falls die Waffe ein bedingtes Verhalten aufweist.
In dem folgenden Beispiel sollte ein Schwert einige Fähigkeiten und Werte in den Händen von Charakteren der Klasse 'Antipaladin' und keine Effekte haben, mit niedrigeren Werten, wenn sie von anderen Charakteren verwendet werden.
Zu Testzwecken habe ich einfache
Player
undWeapon
Klassen erstellt: die erste, die die Waffe hält / ausrüstet (und damit die bedingte Einstellung on_equip aufruft) und die letztere als einzelne Klasse, die die Daten aus dem Wörterbuch basierend auf dem als übergebenen Objektnamen abruft Argument während derWeapon
Initialisierung. Sie spiegeln nicht das richtige Design der Spielklassen wider, können aber dennoch nützlich sein, um die Daten zu testen:Mit einigen zukünftigen Verbesserungen hoffe ich, dass ich eines Tages sogar ein dynamisches Handwerkssystem haben kann, das Waffenkomponenten statt ganzer Waffen verarbeitet ...
Prüfung
So was:
Es sollte drucken:
Für einen Barden
Für ein Antipaladin
quelle