Archive

Archive for the ‘C++’ Category

Learning to call methods (C++ Reflection, part 2)

Ok, last time we got the basics of the system in place. Tonight we’ll fix up some of the stuff that we had before (in case you were wondering, I’m figuring this out at the same time as you guys), then get the invocation of some functions.

First, our RuntimeInfo struct from last time is a little lacking and should be implementing a little better.

Code:

class MapComparer
{
public:
    bool operator()( const char* s1, const char* s2 ) const
    {
        return strcmp(s1, s2) < 0;
    }
};

template< class T >
class RuntimeInfo
{
public:
    static const unsigned int CLASS_NAME_LENGTH = 50;

    RuntimeInfo( unsigned int classId, const char* name );

    unsigned int GetClassId() const;
    const char* GetClassName() const;

    void RegisterMethod( Method< T >* method );

    Method< T >* GetMethod( const char* name );
    std::map< const char*, Method< T >*, MapComparer >* GetMethods();

private:
    unsigned int _classId;
    char         _className[ CLASS_NAME_LENGTH ];
    std::map< const char*, Method< T >*, MapComparer > _methods;
};

The first changes to note is the change from a struct to a class. This is technically only a semantic change in C++, but we’ll be adding functionality via functions so it’s better to call it a class. Next, I moved the class ID and name to private member data, which it probably should have been in the first place. You should also notice that the class is now a templated class. The templace type will tell us the type for member methods will be called. The last important thing is the addition of the RegisterMethod function. This allows us to register any member function with the class so that we can later invoke it.

Alright, now that we’ve updated the RuntimeInfo class to support our Methods, let’s go ahead and define those. =)

Code:

template< class OwnerType >
class Method
{
public:
    typedef void (OwnerType::*m0)();

    Method( const char* name, m0 method );
    virtual ~Method();

    const char* GetName() const;

    void Invoke( OwnerType& obj );

protected:
    Method( const char* name );

private:
    char* _methodName;
    m0 _method;
};

Our Method class is pretty straight forward; it will be used to define functions that have no return type, and for now, take no parameters. First, this class is templated to define the type for the function that is being passed in. For instance, if I have a class MyInt and have exposed Double(), the type would be MyInt. Next thing to note is the typedef for the function signature; this is a function that returns void and takes no parameters. The next interesting piece is the Invoke() function; this is where all of the action will actually be done.

You might be wondering why I’ve created a protected Method constructor… that’s a good question. The reason is that when I start extending this class, I want to be able to take advantage of the base functionality for storing the name.

Alright, so this gives us the ability to call functions that don’t return anything, let’s extend it so that we can call a function and have it return something interesting.

Code:

template< class OwnerType, class ReturnType >
class Function : public Method< OwnerType >
{
public:
    typedef ReturnType (OwnerType::*f0)();

    Function( const char* name, f0 function );
    virtual ~Function();
    ReturnType Invoke( OwnerType& obj );

private:
    f0 _method;
};

The major difference between this class and the Method class is that this class takes two template arguments: the type for the member function and the return type for the function. Also notice the overloading of the Invoke() function so that it returns the proper type.

And that’s all there is to it. I’ll post a little sample application that shows it in use.

Code:

int _tmain( int argc, _TCHAR* argv[] )
{
   Object o;
   MyInt i;

   i.SetValue( 30 );

   Method< MyInt >* imi = i.GetRuntimeInfo()->GetMethod( "Double" );

    Function< MyInt, int >* imi2 =
        static_cast< Function< MyInt, int >* >( i.GetRuntimeInfo()->GetMethod( "GetValue" ) );

    cout << "-- OBJECT --" << endl;
    cout << "\tClass ID: " << o.GetRuntimeInfo()->GetClassId() << endl;
    cout << "\tClass Name: " << o.GetRuntimeInfo()->GetClassName() << endl;
    cout << endl;

    cout << "-- MYINT --" << endl;
    cout << "\tClass ID: " << i.GetRuntimeInfo()->GetClassId() << endl;
    cout << "\tClass Name: " << i.GetRuntimeInfo()->GetClassName() << endl;
    cout << "\tOriginal Value: " << i.GetValue() << endl;
    imi->Invoke( i );
    cout << "\tDouble Value: " << i.GetValue() << endl;
    cout << "\tGetValue: " << imi2->Invoke( i ) << endl;
    cout << endl;

    cout << "Press enter to exit." << endl;
    cin.get();

    return 0;
}

So there we have it. We’ve built a reflection system in C++. Is it the most robust and feature rich, no, most definately not. For instance, there is not way to pass in arguments to either the Method or Function class, there is no way to call the constructor, although, arguably that is just registering the constructor with by using the Function class. But overall, I think I’ve pretty much met the goal that I set out to achieve.

If you have any questions or comments, I’d be happy to answer them, but I think I’m relatively happy with the reflection system I have in C++… for now atleast. =)

Source code is here:Β Reflection.zip

-David

Categories: C++, Programming Tags:

Thinking about the problem (C++ Reflection, part 1)

Setting Goals

So you want to build a reflection system in C++? Well, I assume so since you’re reading this. =) Ok, enough jokes…

There are a few ways to go about building a reflection system in C++ and there are different levels that we can accomplish. For instance, to create a reflection based system that works without any modification to standard C++ types and classes would be very challenging, to say the least. In order to help us with this problem, we’ll start off with a set of goals so that we know what we want to aim for.

  1. Maintainable – It would be nice if (and when) we need to make modifications or bug fixes the code base is clean and logical.
  2. Robust – I don’t like when things only work when sprinkling some magic pixie dust, so let’s make this thing as robust as possible. This means we’ll be using templates rather than MACROs to do our magic.
  3. Effecient – The idea isn’t to create a reflection system takes five minutes to perform something, we want a small and fast system.
  4. Flexible – Let’s shoot for making an extensible system so that we can add to it later without too many problems.

I think that those goals are good enough to get started.

Where to Start

In order to being programming this thing we need to understand what type of information we want. For now the only things that we will concern ourselves with are unique ID for the class and the name of the class; we’ll add to it later to actually make it do some cool stuff.

To start off we’ll need the following classes to provide us with some basic run-time information: RuntimeInfo and RuntimeClass.

Code:

struct RuntimeInfo
{
    RuntimeInfo( unsigned int classId, const char* name );

    static const unsigned int CLASS_NAME_LENGTH = 32;

    unsigned int ClassId;
    char         ClassName[ CLASS_NAME_LENGTH ];
};

This class will define all of the cool details for our class; currently we only need to know the ID for the and the name for the class. The ID could be used to create a new type of class or to compare is two classes are the same.

Code:

template< class T, class BaseClass, unsigned int ClassId >
class RuntimeClass : public BaseClass
{
public:
    static inline RuntimeInfo* GetRuntimeInfo() { return &_info; }

protected:
    static RuntimeInfo _info;
};

template< class T, class BaseClass, unsigned int ClassId >
RuntimeInfo
RuntimeClass< T, BaseClass, ClassId >::_info( ClassId, typeid( T ).name() );

I hope you’re up to speed with your templates =). This class is a tricky way of injecting information that is shared by each type of class we’ll be using in our reflection system. All this class currently has is the runtime information that is created based on the templated information.

The next step is to create the base class we’ll be using for all of the objects in our system; it’s appropriately named Object.

Code:

class NullObject{};
class Object : public RuntimeClass< Object, NullObject, 0x0A >
{
public:
    Object();
    virtual ~Object();
};

One of the first things to notice is that it implements our RuntimeClass and passes in the type that it is, the type it derives from, and the ID to use for the class. As you can see, there is another class NullObject here; this is used so that are template parameters will be satisfied.

That’s it! I’ve given a very brief breakdown of what it takes to get started building a reflection system. Next time we’ll learn how set it up so we can create new instances and set some properties on our classes. I’ll leave you with a little sample app that shows it working.

Code:

class MyClass : public RuntimeClass< MyClass, Object, 0xF0 >
{
public:
    MyClass();
    virtual ~MyClass();
};

int
_tmain( int argc, _TCHAR* argv[] )
{
    Object o;
    MyClass c;

    cout << "-- OBJECT --" << endl;
    cout << "\tClass ID: " << o.GetRuntimeInfo()->ClassId << endl;
    cout << "\tClass Name: " << o.GetRuntimeInfo()->ClassName << endl;
    cout << endl;

    cout << "-- MYCLASS --" << endl;
    cout << "\tClass ID: " << c.GetRuntimeInfo()->ClassId << endl;
    cout << "\tClass Name: " << c.GetRuntimeInfo()->ClassName << endl;
    cout << endl;

    cout << "Press enter to exit." << endl;
    cin.get();

    return 0;
}

-David

Categories: C++, Programming Tags:

Using C# for game scripts (Part 2)

April 22, 2008 1 comment

In my last post I showed you how to get scripts to be compiled dynamically at run-time. This makes things super easy, but I left you guys hanging on two fronts.

  1. I didn’t show you how to compile multiple scripts into the same assembly.
  2. I totally spaced on the fact that this won’t work when using the compact framework (i.e. on the Xbox 36).

Since #1 is incredibly easy, I’ll combine both of these answers into this post.

Alright… compiling multiple scripts into the same assembly. When I first was looking at this my eye balls must have been blury form all the time staring at the monitor or something because I totally didn’t see what the parameter arguments are for the CompileAssemblyFromFile method. As it turns out, the second parameter is ‘params string[] files’. For some strange reason I thought it only took a single file. So all we need to do to get our scripts into the same assembly would be something like this:

Code:

// You need to define these somehow, maybe from a backing XML file. πŸ˜‰
string scriptPath;
string[] scriptFileNames;
string scriptTypeName;
string commandName;

// Create the actual type in memory so it can be used.
CodeDomProvider provider = new CSharpCodeProvider();
CompilerParameters compilerParams = new CompilerParameters();
compilerParams.CompilerOptions = "/target:library";
compilerParams.GenerateExecutable = false;
compilerParams.GenerateInMemory = true;
compilerParams.IncludeDebugInformation = false;

compilerParams.ReferencedAssemblies.Add("mscorlib.dll");
compilerParams.ReferencedAssemblies.Add("YourGame.exe");

CompilerResults result = provider.CompileAssemblyFromFile(compilerParams, scriptFileNames);
if (!result.Errors.HasErrors) {
    Type type = result.CompiledAssembly.GetType(scriptTypeName);
    Command cmd = Activator.CreateInstance(type) as Command;
    if (cmd != null) {
        cmd.Name = commandName;
        this.availableCommands.Add(cmd.Name.ToLower(), cmd);
    }
}

You should notice that are only two real differences with this code and the code from part 1:

  1. scriptFileName is now an array and is called scriptFileNames.
  2. scriptFileName now contains the path information as well as the name of the script.

Ok, with the easy stuff out of the way, let’s talk about pre-compiling our scripts. When we precompile our scripts we get some benefits. One of the most obvious and most beneficial is that we get useful compile errors. These compile errors greatly help with debugging stupid mistakes in our script code. Another wonderful benefit is that we reduce the amount of time the game takes to initialize as we don’t have to compile every script every time we run the game. This might not seem like a lot now, but if you have hundreds of scripts, the time can add up. The last benefit we’ll address is that fact that it will work everywhere; that is, it will work on both a Windows PC and the Xbox 360.

So how do we achieve this magic? Well, the answer is actually MUCH simplier than our solution for yesterday, at least in the terms of code that we need to add in order to support it. The “difficult” part is that you need to setup your own class library project in Visual Studio (or Visual C# Express/XNA Game Studio Express). Then you’ll need to rename the DLL to something that our game will load, unless of course you provide a means to customize how the script DLLs are loaded. After that, simply add the commands to your project and add a reference to your game DLL and you should be ready to go (you need the reference so you can find the Command class that your own commands will be deriving from).

Assuming that you were able to get a class library built of your commands (I know, I kind of glossed over that so ask questions if something wasn’t clear or you couldn’t figure something out), you now need to load that DLL in your game so that we can create the instances of the commands that we need.

Here it is:

Code:

// You need to define these somehow, maybe from a backing XML file. πŸ˜‰
string dllPath;
string[] scriptTypeNames;
string[] commandNames;

Assembly scriptDll = Assembly.LoadFrom(dllPath);

for (int i = 0; i < scriptTypeNames.Length; i++) {
    Type type = scriptDll.GetType(scriptTypeNames[i]);
    Command cmd = Activator.CreateInstance(type) as Command;
    if (cmd != null) {
        cmd.Name = commandNames[i];
        this.availableCommands.Add(cmd.Name.ToLower(), cmd);
    }
}

That’s it… you now know one possible way of adding both non-compiled and pre-compiled scripts, and therefore a cross-platform (Windows and Xbox 360) method of adding scripts to your game.

Good luck!

-David

Categories: C++, Programming Tags:

Using C# for game scripts (Part 1)

Alright, today I’m going to continue where my previous posts (Loading Map/Game Data from XML) left off. Those posts showed you how to get game data into your game, but how do you define game behavior? Simple! With scripts.

Now, there are lots of solutions for scripting available with one of the mose popular being Lua. However, I want this to be simple and easy, so we’re going to be using C#. I mean, what’s the point of doing all this setup that needs to be done with Lua when we have a perfectly working compiler and development environment sitting at our fingertips? =)

Ok, so first things first. When we are creating scripts that are going to be run, we need to have some time of entry point into the script; that is, we need to know how to execute the script. One simple way is to create and interface or a base class that defines the available methods that we can actually call on our script.

Continuing with the example of a text-based adventure, let’s figure out how we might allow for developers to create commands the user can type to interact with the game. All we need to do this will be the name of the command and an entry point into the script.

Code:

public abstract class Command {
   private string name;

   public string Name {
       get { return this.name; }
       set { this.name = value; }
   }

   public virtual void Execute(Game game, string arguments) {
    }
}

Now we have the base command in place, next we need a script that actually does something interesting. With this, you’re just going to have to bear with me as I won’t be posting the details of the Game class, but just assume the properties on it exist. =) Besides, this is more of a proof-of-concept.

Code:

public class MoveCommand : Command {
   public override void Execute(Game game, string direction) {
       direction = direction.ToLower();

       // Determine if the player can move the way they wanted to.
       Area currentArea = game.Map[game.Player.Position];
       if (currentArea.HasExit(direction)) {
           if (direction == "north") game.Player.Move(0, 1);
           else if (direction == "east") game.Player.Move(1, 0);
            else if (direction == "south") game.Player.Move(0, -1);
            else if (direction == "west") game.Player.Move(-1, 0);

            currentArea = game.Map[game.Player.Position];
            game.Describe(currentArea);
        }
        else {
            TextBuffer.AddTextLine("Invalid direction to move: " + direction);
        }
    }
}

It should be fairly obvious what this is script is supposed to do, after all it is called MoveCommand. πŸ˜‰ Basically we are just going to move the player in one of the given directions with the Area that we are in has an exit/door in that direction.

We know have two-thirds of the puzzle. The next question to answer is, “How the heck do I get that into my game?”. The answer is much simpler than you might think:

Code:

// You need to define these somehow, maybe from a backing XML file. πŸ˜‰
string scriptPath;
string scriptFileName;
string scriptTypeName;
string commandName;

// Create the actual type in memory so it can be used.
CodeDomProvider provider = new CSharpCodeProvider();
CompilerParameters compilerParams = new CompilerParameters();
compilerParams.CompilerOptions = "/target:library";
compilerParams.GenerateExecutable = false;
compilerParams.GenerateInMemory = true;
compilerParams.IncludeDebugInformation = false;

compilerParams.ReferencedAssemblies.Add("mscorlib.dll");
compilerParams.ReferencedAssemblies.Add("YourGame.exe");

CompilerResults result = provider.CompileAssemblyFromFile(compilerParams, Path.Combine(scriptPath, scriptFileName));
if (!result.Errors.HasErrors) {
    Type type = result.CompiledAssembly.GetType(scriptTypeName);
    Command cmd = Activator.CreateInstance(type) as Command;
    if (cmd != null) {
        cmd.Name = commandName;
        this.availableCommands.Add(cmd.Name.ToLower(), cmd);
    }
}

Simple huh? Heh, well… if you know what all those lines of code do then it is. Basically all we are doing is having the CodeDom compile that piece of code for us. This results in an assembly which we can then use reflection to retrieve an instance of the MoveCommand from this newly compiled assembly.

You might be wondering where you put this in your game code. Well, I put in my Initialize method which is one of the first methods that gets called. I actually wrap it in a LoadCommands method which goes through and compiles all of my game scripts, which are of course, defined using an XML file. =)

This approach works fine and dandy for script files that are independent of one another, but what if we want scripts to be able to use methods defines in other scripts? Well, for that we’ll need to compile all of the scripts into a single assembly. I’ll cover how to do that in my next post.

-David

Categories: C++, Programming Tags:

Loading Map/Game Data from XML (Part 3)

April 22, 2008 3 comments

So far we have the backing map.xml file, we have the classes that we are going to use to store the data in our game, now all we need to do is to parse the XML file and create the instances. We could have tried to use the XML serialization support that is built into .NET, but the approach that we are going to use it much more flexible and easy to understand. Let’s see some code:

Code:

private Map LoadMapData() {
   StreamReader reader = new StreamReader(@"map.xml");
   XmlDocument mapDoc = new XmlDocument();
   mapDoc.LoadXml(reader.ReadToEnd());
   reader.Close();

   Map map = new Map();

   Vector2D startingPosition = ParseVector2D(mapDoc.SelectSingleNode("/Map/StartingPosition"));
    map.StartingPosition = startingPosition;

    foreach (XmlNode areaNode in mapDoc.SelectNodes("/Map/Areas/Area")) {
        map.AddArea(ParseArea(areaNode));
    }

    return map;
}

private Vector2D ParseVector2D(XmlNode node) {
    Vector2D vec = new Vector2D();

    vec.X = Int32.Parse(node.Attributes["X"].Value);
    vec.Y = Int32.Parse(node.Attributes["Y"].Value);

    return vec;
}

private Area ParseArea(XmlNode node) {
    Vector2D position = ParseVector2D(node["Position"]);
    Area area = new Area(position);
    area.Title = node["Title"].InnerText.Trim();
    area.Description = node["Description"].InnerText.Trim();

    foreach (XmlNode itemNode in node.SelectNodes("Items/Item")) {
        area.AddItem(itemNode.Attributes["ID"].InnerText.Trim());
    }
    foreach (XmlNode exitNode in node.SelectNodes("Exits/Exit")) {
        area.AddExit(exitNode.Attributes["ID"].InnerText.Trim());
    }

    return area;
}

I bet you thought there was going to be a lot more code than that, huh? =) As you can see, it’s pretty easy to parse an XML file. The code pretty much speaks for itself so I’m going to leave it at that. If you don’t understand something I suggest that you first dig into the MSDN library on XmlDocuments and XmlNodes so that you can try and figure it out, however, do feel free to post any comments/questions you have here as well.

You should be able to take this example and extend it to any XML file holding your game data now. Good luck! =)

-David

Categories: C++, Programming Tags:

Loading Map/Game Data from XML (Part 2)

Alright, in the last part we dealt with creating the basic map file. This time around we’re going to look at the classes that hold the data that we will eventually be reading in.

The first class we’re going to be looking at is the Map class.

Code:

public class Map {
   private Vector2D startingPosition;
   private Dictionary<Vector2D, Area> areas;

   public Map() {
       this.areas = new Dictionary<Vector2D, Area>();
   }

   public Area this[Vector2D position] {
        get {
            return this.areas[position];
        }
    }

    public Vector2D StartingPosition {
        get {
            return this.startingPosition;
        }
        set {
            this.startingPosition = value;
        }
    }

    public void AddArea(Area area) {
        if (area == null) throw new ArgumentNullException("area");
        this.areas.Add(area.Position, area);
    }

    public bool RemoveArea(Vector2D position) {
        return this.areas.Remove(position);
    }
}

As you can see, there are two other classes that Map relies on: Vector2D and Area. Both of these are defined below. The Map class is pretty straight forward, the only thing to note is the way in which the Areas are stored. Instead of using a fixed array, I’m using a Dictionary so that I can create a map with only the Areas I want defined and not have an array full of null Areas.

Next is the Area class.

Code:

public class Area {
    private Vector2D position;
    private string description;
    private string title;
    private List<string> exits;
    private List<string> items;

    public Area(Vector2D position) {
        this.position = position;
        this.exits = new List<string>();
        this.items = new List<string>();
    }

    public Vector2D Position {
        get {
            return this.position;
        }
    }

    public string Description {
        get {
            return this.description;
        }
        set {
            this.description = value;
        }
    }

    public string Title {
        get {
            return this.title;
        }
        set {
            this.title = value;
        }
    }

    public IEnumerable<string> Exits {
        get {
            foreach (string exit in this.exits) {
                yield return exit;
            }
        }
    }

    public int ExitCount {
        get {
            return this.exits.Count;
        }
    }

    public bool HasExit(string direction) {
        return this.exits.Contains(direction);
    }

    public void AddExit(string direction) {
        if (!this.exits.Contains(direction)) {
            this.exits.Add(direction);
        }
    }

    public void RemoveExit(string direction) {
        this.exits.Remove(direction);
    }

    public IEnumerable<string> Items {
        get {
            foreach (string item in this.items) {
                yield return item;
            }
        }
    }

    public int ItemCount {
        get {
            return this.items.Count;
        }
    }

    public void AddItem(string item) {
        if (!this.items.Contains(item)) {
            this.items.Add(item);
        }
    }

    public void RemoveItem(string item) {
        this.items.Remove(item);
    }

    public bool HasItem(string item) {
        return this.items.Contains(item);
    }
}

And finally, let’s look at Vector2D – definately the simpliest of all of the items.

Code:

public struct Vector2D {
    public int X;
    public int Y;

    public Vector2D(int x, int y) {
        this.X = x;
        this.Y = y;
    }
}

The classes are all pretty self-explanatory (at least I think so =)), so I’m not going to go into great detail. Just remember that when we are storing the items and the exits, we will be using the IDs.

That’s it for this post. In the next post I’ll be showing you how to read the XML map file and create your map dynamically at run-time.

-David

Categories: C++, Programming Tags:

Loading Map/Game Data from XML (Part 1)

Over at 3D Buzz (http://www.3dbuzz.com/) there is an XNA class that is currently going: XNA 101. The class is currently going through the process of creating a text-based adventure game as it’s “Hello World!” app – ambitious for beginners yes, but way more interesting.

Of course, this class is geared toward beginners so all of the game data is hard coded into the code. This got me thinking, what if people wanted to venture out and load this data dynamically. That’s leads us to today’s post: loading map/game data from an XML file.

So where does one begin? Well, the first place I like to start is with an empty XML file. πŸ˜‰ But that’s not terribly interesting to look at. So we’ll create the basic structure here.

Code:

<?xml version="1.0" encoding="utf-8" ?>
<Map>
  <StartingPosition X="1" Y="0" />
  <Areas>
    <Area>
      <Position X="0" Y="0" />
      <Title>Lounge</Title>
      <Description>This is where all of the lazy bums come and sit instead of working.</Description>
      <Items>
        <Item ID="ITM_COUCH" />
      </Items>
      <Exits>
        <Exit ID="DIR_EAST" />
      </Exits>
    </Area>
    <Area>
      <Position X="1" Y="0" />
      <Title>Entrance</Title>
      <Description>This is the main lobby for the building.</Description>
      <Items>
        <Item ID="ITM_PEN" />
      </Items>
      <Exits>
        <Exit ID="DIR_EAST" />
        <Exit ID="DIR_WEST" />
      </Exits>
    </Area>
    <Area>
      <Position X="2" Y="0" />
      <Title>Office</Title>
      <Description>This is one of the many offices located within the building.</Description>
      <Items />
      <Exits>
        <Exit ID="DIR_WEST" />
      </Exits>
    </Area>
  </Areas>
</Map>

What you’ll see here is that our map data specifies some important data like the starting location for the player and details about each of the areas in the map. Within the areas are the IDs for the items and the directions (which are also stored in an XML file). We store IDs so that we can keep all of the data centralized in one location and not have to update it in many places.

I’m not going to really explain too much more about the XML file. You should create one that suites your own needs for your game.

Now that we have the XML file, we need a way to load that file into our game. We’ll cover that next time.

-David

Categories: C++, Programming Tags: