8
\$\begingroup\$

My XNA game is component-oriented, and has various components for position, physics representation, rendering, etc, all of which extend a base Component class. The player and enemies also have controllers which are currently defined in C#. I'd like to turn them into Python scripts via IronPython (a .NET implementation of Python). My problem is that I'm not sure how to interact with those scripts.

The examples in Embedding IronPython in a C# Application suggest I'd have to create something like a Script component which compiles a Python script and calls the controller's Update method via Python - essentially, it'd be a wrapper class for C# to interface with Python.

I feel that I'm missing something in my research. There must be a way to load up a script, instantiate a Python object (either in the Python script or in C#) and then then have a direct reference to that Python object in my C# code.

Is there a way to work with an IronPython object directly, or is a wrapper required?

\$\endgroup\$

1 Answer 1

7
\$\begingroup\$

I've figured out how to do this. As I expected, since IronPython compiles down to CLR, C# and IronPython objects can interact with each other just fine with no special treatment necessary. I've created a script which actually creates a new type of Component which can be referenced just fine from C#.

A brief word on my game's structure: Its solution has two projects: Game, and GameEngine. The Game is what is ultimately compiled into an EXE, and the GameEngine is compiled into a DLL which sits in the same directory.

The script

This currently sits in the default content project, has no build action and is copied to the output directory.

Note that the Component class is a part of GameEngine, and so is compiled into GameEngine.dll. It also has nothing to do with XNA's GameComponent class and its methods don't need to be passed a GameTime object.

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()

How the script is compiled and run

Just once within the game, I run this:

// 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);

When the script gets executed, it creates its own instance of a PyComponent.

Of course you'll need to reference the IronPython library and the Microsoft Dynamic runtime. I've found I only need these four DLLs from the root folder of the IronPython download:

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

Add these references to your project, then these using statements to your code (according to Embedding IronPython in a C# Application):

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

Obtaining a reference to the Python object

I'm not sure how I'd get a reference directly from the script, but I do have a roundabout way of doing that. In my engine design, all components automatically register themselves with the engine's component collection, so I can get a reference to the object through there. In a more specific case, you could just have new Python objects register themselves with a queue somewhere, so you create them and then immediately retrieve them.

\$\endgroup\$
1
  • \$\begingroup\$ My last update to this post will be when I figure out how to directly obtain a reference to the python object. \$\endgroup\$ Commented Apr 19, 2012 at 7:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .