Wie kommuniziere ich mit einer IronPython-Komponente in einem C # / XNA-Spiel?

8

Mein XNA-Spiel ist komponentenorientiert und enthält verschiedene Komponenten für Position, physikalische Darstellung, Rendering usw., die alle eine Basisklasse erweitern Component. Der Spieler und die Feinde haben auch Controller, die derzeit in C # definiert sind. Ich möchte sie über IronPython (eine .NET-Implementierung von Python) in Python-Skripte umwandeln. Mein Problem ist, dass ich nicht sicher bin, wie ich mit diesen Skripten interagieren soll.

Die Beispiele in Embedding IronPython in einer C # -Anwendung legen nahe, dass ich so etwas wie eine Skriptkomponente erstellen muss, die ein Python-Skript kompiliert und die Update-Methode des Controllers über Python aufruft - im Wesentlichen wäre es eine Wrapper-Klasse für C #, um mit Python zu kommunizieren .

Ich habe das Gefühl, dass mir etwas in meiner Forschung fehlt. Es muss eine Möglichkeit geben, ein Skript zu laden, ein Python-Objekt zu instanziieren (entweder im Python-Skript oder in C #) und dann einen direkten Verweis auf dieses Python-Objekt in meinem C # -Code zu haben.

Gibt es eine Möglichkeit, direkt mit einem IronPython-Objekt zu arbeiten , oder ist ein Wrapper erforderlich?

Doppelgrün
quelle

Antworten:

7

Ich habe herausgefunden, wie das geht. Wie erwartet, können C # - und IronPython-Objekte, da IronPython bis auf CLR kompiliert wird, problemlos miteinander interagieren, ohne dass eine spezielle Behandlung erforderlich ist. Ich habe ein Skript erstellt, das tatsächlich einen neuen Komponententyp erstellt, auf den von C # aus problemlos verwiesen werden kann.

Ein kurzes Wort zur Struktur meines Spiels: Die Lösung besteht aus zwei Projekten: Game und GameEngine. Das Spiel wird letztendlich in eine EXE-Datei kompiliert, und die GameEngine wird in eine DLL kompiliert, die sich im selben Verzeichnis befindet.

Das Skript

Dies befindet sich derzeit im Standardinhaltsprojekt, hat keine Erstellungsaktion und wird in das Ausgabeverzeichnis kopiert.

Beachten Sie, dass die Component-Klasse Teil von GameEngine ist und daher in GameEngine.dll kompiliert wird . Es hat auch nichts mit der GameComponent-Klasse von XNA zu tun und seine Methoden müssen nicht an ein GameTime-Objekt übergeben werden.

import clr
clr.AddReferenceToFileAndPath("GameEngine.dll")
from GameEngine import *
# or: from GameEngine import Component

class PyComponent(Component):
    def __new__(self):
        Component.__new__(self)

    def Initialize(self):
        pass

    def Update(self):
        pass

    def Draw(self):
        pass

pc = PyComponent()

Wie das Skript kompiliert und ausgeführt wird

Nur einmal im Spiel führe ich Folgendes aus:

// Engine setup stuff. The scope can work with variables in the script by
// adding references, accessing/removing current references, etc.
// Each script COULD have its own scope but I have no reason to do that yet.
ScriptEngine PythonEngine = Python.CreateEngine();
ScriptScope DefaultScope = PythonEngine.CreateScope();

string filename = @"Content\ScriptTest.py";
ScriptSource script = PythonEngine.CreateScriptSourceFromFile(filename, Encoding.ASCII);
script.Execute(scope);

Wenn das Skript ausgeführt wird, erstellt es eine eigene Instanz einer PyComponent.

Natürlich müssen Sie auf die IronPython-Bibliothek und die Microsoft Dynamic-Laufzeit verweisen. Ich habe festgestellt, dass ich nur diese vier DLLs aus dem Stammordner des IronPython-Downloads benötige:

  • IronPython.dll
  • IronPython.Modules.dll
  • Microsoft.Dynamic.dll
  • Microsoft.Scripting.dll

Fügen Sie diese Verweise zu Ihrem Projekt und dann diese usingAnweisungen zu Ihrem Code hinzu (gemäß Einbetten von IronPython in eine C # -Anwendung ):

using IronPython.Hosting;
using IronPython.Runtime;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;

Abrufen eines Verweises auf das Python-Objekt

Ich bin mir nicht sicher, wie ich eine Referenz direkt aus dem Skript erhalten soll, aber ich habe einen Umweg dazu. In meinem Motorkonzept registrieren sich alle Komponenten automatisch bei der Komponentensammlung der Engine, sodass ich dort einen Verweis auf das Objekt erhalten kann. In einem spezifischeren Fall könnten sich neue Python-Objekte einfach irgendwo in einer Warteschlange registrieren lassen, also erstellen Sie sie und rufen sie sofort ab.

Doppelgrün
quelle
Mein letztes Update für diesen Beitrag wird sein, wenn ich herausfinde, wie ich direkt einen Verweis auf das Python-Objekt erhalten kann.
Doppelgreener