Ich entwickle eine einfache Spiel-Engine (in C #, wenn es darauf ankommt), und mir fällt kein angemessener Weg ein, Skripte in Bezug auf die Architektur zu implementieren.
Es ist eine einfache rundenbasierte Strategie mit benutzerdefinierten, logikunabhängigen Animationen für Schlachten. Es verfügt über eine globale Architekturschicht für System- / Low-Level-Inhalte und vor allem über zwei Hauptmodule - Logik und Game-View-Ding -, die über einen Event-Manager kommunizieren.
Und die Sache ist, ich möchte wirklich, dass die Skripte sowohl Dinge beeinflussen, die mit der Spiellogik zusammenhängen (Ändern von Einheitenparametern usw.), als auch Dinge, die mit der Spielansicht zusammenhängen, wie spezielle Animationen / Dialoge für Schlachten, die von a abhängen könnten bestimmter Skript-Trigger.
(Um ehrlich zu sein, ich möchte im Idealfall, dass das Skript den Spielfluss steuert und nur die Hauptmechanik / -grafik der Logik / -ansicht überlässt, aber ich bin neu in diesem Bereich, daher bin ich mir nicht sicher, ob ich das jetzt tun kann.)
Ich habe über drei Optionen nachgedacht:
Lassen Sie das Scripting einfach in der Logik leben, aber informieren Sie es über die grafische Seite des Spiels. Aber das würde die Logik / Sicht-Aufteilung sehr vage machen, nicht wahr?
Machen Sie das Scripting zu einem separaten Modul, das Ereignisse mit dem gleichen Ereignis-Manager mit den anderen austauscht. Aber das würde erfordern, sehr vorsichtig mit der Ereignissynchronisation umzugehen, denke ich ... und dem Manager eine ganze Menge Ereignistypen hinzuzufügen. (Immer noch persönlicher Favorit)
Machen Sie das Scripting vor allem zu einem Modul, damit es Funktionen der Logik / Sicht direkt beeinflussen / aufrufen kann. Dies ermöglicht eine von Natur aus breitere Funktionalität, die es kostet, das gesamte Ereignisaustauschschema zu durchkreuzen und zu befürchten, dass das Skript Dinge kaputt machen kann, selbst wenn dies eigentlich nicht der Fall sein sollte.
Daher kann ich mich weder für eine dieser Optionen entscheiden noch mir eine bessere Methode zum Einfügen des Skriptmoduls vorstellen ... Irgendwelche Vorschläge oder nützliche Links?
Vielen Dank!
Ps danke für die Migration der Frage, wusste nicht, dass es einen speziellen Bereich für gamedev gibt
quelle
Antworten:
Ich glaube, Sie möchten die dritte Option, aber Sie werden feststellen, dass Sie zu Recht der Meinung sind, dass es eine schlechte Sache ist, wenn logische Ereignisse an möglicherweise zwei Orten stattfinden. Sie werden feststellen, dass das Logikmodul der Engine ein Update-Tick sein soll, der zwei Fragen stellt: "Was mache ich jetzt?" und 'Wie mache ich das?' an die Sie dann Skripte binden können, um diese Fragen zu beantworten.
Kombinieren Sie dies damit, dass Sie die Objekte, die die Daten und eine API enthalten, verfügbar machen, um auf die erforderlichen Logikkomponenten zuzugreifen binde es in das Modul ein und füge es dann der API hinzu, die für die Skriptsprache verfügbar ist?). Dies sollte Ihnen die Zugänglichkeit sowie die klar definierten Orte ermöglichen, an denen Dinge geschehen.
Nochmals, ich weise dies mit der gleichen Aussage zurück, die ich immer mache. Ein fertiges Arbeitsprodukt ist immer wertvoller als eine gute Theorie in der Programmierung :)
Hoffe das hilft!
quelle
Viele neigen dazu, die Mächtigen dynamischer Sprachen zu unterschätzen, die glauben, dass eine solche Flexibilität zu Lasten der Geschwindigkeit geht. Dies ist wahr, aber oft sind die Kosten einfach vernachlässigbar.
Persönlich neige ich dazu, so viel wie möglich mit dynamischen Sprachen zu entwickeln, die die Ausdruckskraft ausnutzen, und dann profiliere ich den Prototyp, um zu verstehen, wo und ob Optimierung erforderlich ist.
In Ihrem Fall bedeutet dies, dass Sie versuchen sollten, zur dritten Option überzugehen und den "höheren" Teil mit einer geeigneten dynamischen Sprache zu entwickeln, die Sie auch als Skriptsprache verwenden können.
Nachdem Sie die Dynamik in die richtige Tiefe gebracht haben, können viele Muster verwendet werden. Ihre benutzerdefinierten Skripte können als Rückrufsystem in ein ereignisbasiertes System integriert werden. Wenn der Kern zurückruft, kann er eine geeignete Umgebung bereitstellen, damit das Skript den globalen Status oder nur den Status einer Teilmenge des gesamten Systems ändern kann.
Sie können die Schnittstelle, mit der Ihr Skript interagieren kann, mithilfe des Fassadenmusters kapseln. In den Fassaden Methoden können Sie die Logik setzen , die definieren , wie , wann , wenn das Skript eine Funktionalität und abstrahiert die Skript Interaktion von der Kern Implementierung verwenden kann.
Ihre Skriptschnittstelle sollte die entsprechenden Factory-Methoden bereitstellen, damit das Skript Elemente generieren kann, ohne sie direkt zu instanziieren. Diese Instanzen können Wrapper für die realen Objekte sein, sodass eine weitere Steuerzugriffslogik implementiert werden kann.
quelle
Das Skriptobjekt muss Zugriff auf die anderen Objekte haben, für die es Daten bereitstellt. Übergeben Sie diese anderen Objekte nicht direkt an das Skriptobjekt. Dadurch entsteht eine spröde Schnittstelle. Möglicherweise möchten Sie eine Mediator-Klasse haben, die diese Objektreferenzen verwaltet und den Datenzugriff auf das Skriptobjekt ermöglicht.
quelle
Lua ist eine beliebte Wahl für eine Allzweck-Skriptsprache. Sie können Ihre eigene Skriptsprache mit Lex und Yacc erstellen (siehe den Artikel in Game Programming Gems 3), aber ich würde sagen, dass die meisten Ihrer Bedürfnisse mit Lua erledigt werden können, egal wie groß oder klein sie sind.
quelle