jump to navigation

Tiled Map Editor (Part 2) March 17, 2010

Posted by Jesse in : Game Development , trackback

If you haven’t already, read part one first.

Now that we can load Tiled maps into our game, what can we do with the data? In his article, Nick mentioned that you can create layers dedicated to rectangles with attached metadata. In the editor, these are called object layers. (In the code, the type is MapObjectLayer, containing a collection of type MapObject.)

Each object in the object layer has four important components.

Okay, knowing all of that, it would be pretty easy to write a bit of code create new Frog objects based on what we find in the object layer.

foreach (Layer layer in map.Layers)
{
    if (layer is MapObjectLayer)
    {
        MapObjectLayer mol = (MapObjectLayer)layer;
        foreach(MapObject mapObject in mol)
        {
            if (mapObject.Type == "Frog")
            {
                Frog frog = new Frog(mapObject.Name,
                  mapObject.Location, mapObject.Properties);
            }
        }
    }
}

And if we later wanted to add a new type of object called Turtle, we could simply add that in.

else if (mapObject.Type == "Turtle")
{
    Turtle turtle = new Turtle(mapObject.Name,
        mapObject.Location, mapObject.Properties);
}

That was pretty easy, but it would become quite an unwieldy mess if we have a large number of possible game object types. Also, every time you add a new object type to the game, you need to come back to this code and add it. That’s unfortunate, because it adds another place where we could let bugs slip into the code. Plus, there’s not really any reason that this code needs to know about every single type of game object that could ever exist.

This is where my new favorite programming tool comes in handy. Hooray for reflection! According to wikipedia, “reflection is the process by which a computer program can observe and modify its own structure and behavior.” Well, that sounds neat, but what does that mean for us?

In C#, we can use reflection to find out information about any type. We can search for different constructors, its properties, methods, and attributes. Using reflection, we could very simply create an instance of an object that our code didn’t know anything about when we wrote it. It’s really powerful stuff.

How about a quick example? Let’s see how we might look up and call the constructor for Vector2.

Without reflection:

Vector2 v = new Vector2(3.1f, 4.6f);

With reflection:

Type t = typeof(Vector2);
ConstructorInfo ci;
Vector2 v;

ci = t.GetConstructor(new Type[] {
    typeof(float), typeof(float) });
if (ci != null)
    v = (Vector2)ci.Invoke(new object[] { 3.1f, 4.6f });

Yes, that’s a pretty silly example, because it’s so easy to directly call the constructor for Vector2, so we don’t need all that extra code. But what if we didn’t know what type we wanted to construct when we wrote the code? How about instead we received the type to create in a string? (From the command line or from a file, for example.)

string typeToCreate;

// read typeToCreate from a file - for example "MyGame.Frog"

Type type = Type.GetType(typeToCreate);
if (type != null)
{
    // look up constructor here
}

Great! So now we’ve got all the pieces we need. We know the name of the type from the Type field of the MapObject. We can use that to look up the appropriate C# Type. We then use reflection to search that type for an appropriate constructor. In this example, all of the types are derived from a base class called GameObject, so that I can put them all in a List together. If we fail to find a Type or an appropriate constructor for it, it just skips to the next object.

foreach (MapObject mapObject in mol.Objects)
{
    Type type = Type.GetType(mapObject.Type);
    if (type == null)
        continue;
    ConstructorInfo ci = type.GetConstructor(new Type[] {
        typeof(string), typeof(Rectangle),
        typeof(PropertyCollection) });
    if (ci == null)
        continue;
    GameObject go = (GameObject)ci.Invoke(new object[] {
        mapObject.Name, mapObject.Location,
        mapObject.Properties, this });
    gameObjectList.Add(go);
}

I’ve put together a demo showing this all put together. I’ve added an object called DemoObject to Nick’s demo map. You can see the properties here:

And when you run the game, it uses that information to draw a rectangle:

I’m releasing this using the same license Nick used. (Ms-PL)

License
Source Code

Comments»

1. Warspawn - April 1, 2010

well, that’s just plain awesome, thanks for this. you and Nick have done some really great work here.

2. Jesse - April 1, 2010

I’m glad you like it. I’m working on a part 3 article right now, and hope to have it up today or tomorrow.

3. Tiled Map Editor – Series « g4m3d3v - June 28, 2011

[…] Series : Parte1 – Parte2 – […]