Ich versuche derzeit, ein komponentenbasiertes Entitätssystem zu implementieren, bei dem eine Entität im Grunde nur eine ID und einige Hilfsmethoden sind, die eine Reihe von Komponenten zu einem Spielobjekt zusammenbinden. Einige Ziele davon sind:
- Komponenten enthalten nur Status (z. B. Position, Gesundheit, Munitionszahl) => Logik geht in "Systeme", die diese Komponenten und ihren Status verarbeiten (z. B. PhysicsSystem, RenderSystem usw.).
- Ich möchte Komponenten und Systeme sowohl in reinem C # als auch durch Scripting (Lua) implementieren. Grundsätzlich möchte ich in der Lage sein, völlig neue Komponenten und Systeme direkt in Lua zu definieren, ohne meine C # -Quelle neu kompilieren zu müssen.
Jetzt suche ich nach Ideen, wie ich effizient und konsistent damit umgehen kann, damit ich beispielsweise keine andere Syntax verwenden muss, um auf C # -Komponenten oder Lua-Komponenten zuzugreifen.
Mein aktueller Ansatz wäre die Implementierung von C # -Komponenten mithilfe regulärer öffentlicher Eigenschaften, die wahrscheinlich mit einigen Attributen versehen sind, die dem Editor Informationen zu Standardwerten und anderen Elementen geben. Dann hätte ich eine C # -Klasse "ScriptComponent", die nur eine Lua-Tabelle intern umschließt, wobei diese Tabelle von einem Skript erstellt wird und den gesamten Status dieses bestimmten Komponententyps enthält. Ich möchte von der C # -Seite nicht wirklich auf diesen Status zugreifen, da ich zum Zeitpunkt der Kompilierung nicht wissen würde, welche ScriptComponents mit welchen Eigenschaften mir zur Verfügung stehen würden. Der Editor muss zwar darauf zugreifen, aber eine einfache Oberfläche wie die folgende sollte ausreichen:
public ScriptComponent : IComponent
{
public T GetProperty<T>(string propertyName) {..}
public void SetProperty<T>(string propertyName, T value) {..}
}
Dies würde einfach auf die Lua-Tabelle zugreifen und diese Eigenschaften von Lua festlegen und abrufen, und es könnte leicht auch in den reinen C # -Komponenten enthalten sein (aber dann die regulären C # -Eigenschaften durch Reflexion oder so etwas verwenden). Dies wird nur im Editor verwendet, nicht im regulären Spielcode, daher ist die Leistung hier nicht so wichtig. Es würde es notwendig machen, einige Komponentenbeschreibungen zu generieren oder handschriftlich zu schreiben, die dokumentieren, welche Eigenschaften ein bestimmter Komponententyp tatsächlich bietet, aber das wäre kein großes Problem und könnte ausreichend automatisiert werden.
Wie kann man jedoch von der Lua-Seite auf Komponenten zugreifen? Wenn ich so etwas getComponentsFromEntity(ENTITY_ID)
anrufe, bekomme ich wahrscheinlich nur ein paar native C # -Komponenten, einschließlich "ScriptComponent", als Benutzerdaten. Der Zugriff auf die Werte aus der umschlossenen Lua-Tabelle würde dazu führen, dass ich die GetProperty<T>(..)
Methode aufrufe, anstatt wie bei den anderen C # -Komponenten direkt auf die Eigenschaften zuzugreifen.
Schreiben Sie möglicherweise eine spezielle getComponentsFromEntity()
Methode, die nur von Lua aufgerufen werden soll. Sie gibt alle nativen C # -Komponenten als Benutzerdaten zurück, mit Ausnahme von "ScriptComponent", wo stattdessen die umschlossene Tabelle zurückgegeben wird. Es wird aber auch andere komponentenbezogene Methoden geben, und ich möchte nicht alle diese Methoden duplizieren, um sie sowohl aus dem C # -Code als auch aus dem Lua-Skript aufzurufen.
Das ultimative Ziel wäre es, alle Arten von Komponenten gleich zu behandeln, ohne dass eine spezielle Fallsyntax zwischen nativen Komponenten und Lua-Komponenten unterscheidet - insbesondere von der Lua-Seite. Zum Beispiel möchte ich in der Lage sein, ein solches Lua-Skript zu schreiben:
entity = getEntity(1);
nativeComponent = getComponent(entity, "SomeNativeComponent")
scriptComponent = getComponent(entity, "SomeScriptComponent")
nativeComponent.NativeProperty = 5
scriptComponent.ScriptedProperty = 3
Das Skript sollte sich nicht darum kümmern, welche Art von Komponente es tatsächlich hat, und ich möchte dieselben Methoden verwenden, die ich von der C # -Seite zum Abrufen, Hinzufügen oder Entfernen von Komponenten verwenden würde.
Vielleicht gibt es einige Beispielimplementierungen für die Integration von Skripten in solche Entitätssysteme?
Antworten:
Eine logische Folge von FXIII Antwort ist , dass man alles entwerfen soll (das wäre modifizierbar sein) in der Skriptsprache zuerst (ein sehr anständiger Teil davon oder zumindest) , um sicherzustellen , dass Ihre Integrationslogik tatsächlich Bestimmungen für modding. Wenn Sie sicher sind, dass Ihre Skriptintegration vielseitig genug ist, schreiben Sie die erforderlichen Bits in C # neu.
Ich persönlich hasse die
dynamic
Funktion in C # 4.0 (ich bin ein Junkie in statischer Sprache) - aber dies ist ohne Zweifel ein Szenario, in dem sie verwendet werden sollte und in dem sie wirklich glänzt. Ihre C # -Komponenten wären einfach starke / expando-Verhaltensobjekte .Ihre Lua-Komponenten wären vollständig dynamisch (der gleiche Artikel oben sollte Ihnen eine Vorstellung davon geben, wie Sie dies implementieren können). Beispielsweise:
Jetzt, da Sie verwenden
dynamic
, können Sie Lua-Objekte so verwenden, als wären sie echte Klassen in C #.quelle
Ich würde lieber das Gegenteil tun: Schreiben Sie alles in einer dynamischen Sprache und suchen Sie dann die Engpässe (falls vorhanden). Sobald Sie eine gefunden haben, können Sie die damit verbundenen Funktionen mithilfe eines C # oder (eher) C / C ++ selektiv neu implementieren.
Ich sage Ihnen dies hauptsächlich, weil Sie versuchen, die Flexibilität Ihres Systems im C # -Teil einzuschränken. Wenn das System komplex wird, sieht Ihre C # "Engine" wie ein dynamischer Interpreter aus, wahrscheinlich nicht der beste. Die Frage ist: Sind Sie bereit, den größten Teil Ihrer Zeit in das Schreiben einer generischen C # -Engine zu investieren oder Ihr Spiel zu erweitern?
Wenn Ihr Ziel das zweite ist, wie ich glaube, werden Sie wahrscheinlich Ihre Zeit am besten nutzen, um sich auf Ihre Spielmechanik zu konzentrieren und einen erfahrenen Interpreter den dynamischen Code ausführen zu lassen.
quelle