Using Inkscape as a map editor

February 13, 2009

BattleMints is coming along great.

When I started working on it, I slapped together a quick-and-dirty map editor myself. Making a basic editor that could place enemies and wireframe walls took only a day of work in Factor, but when I got to the point where I tried to design actual maps, I found myself craving all the trappings of a decent vector graphics illustrator: grouping, copy and paste, rotation, node snapping, and so on. Rather than reinvent all those wheels, I realized that with a little work I could use Inkscape, the free vector graphics editor, to build maps and write them out in a format BattleMints can use.

Inkscape uses SVG as its native format, with extensions to store extra editing information and features that basic SVG doesn't support. This makes its output easy to work in any XML library. Inkscape also provides a simple scripting interface that allows input, output, and effects plugins to be written in any language. Using just the scripting interface, I was able to bend Inkscape to my will without touching the source. (I'm sure someone could do the same sorts of things in Illustrator, but in this economy, who can afford it?)

I have three layers set up in my map documents:

The "Templates" layer is where I draw of all the different game objects as I want them to appear in Inkscape. Once I draw each template, I give it a descriptive id like "player" and place place at the upper-left corner of the page (the origin in the SVG coordinate space):

Not very easy to work with everything overlapping like that. To actually build the maps, I make clones of all of the templates and arrange them in a nice layout in the "Palette" layer:

I can then duplicate these clones into the "Map" layer and arrange them to design maps. Clones in Inkscape are represented using the SVG use tag, so when I later go to build a map from the SVG I just look at the xlink:href attribute to see what kind of object to place. And since I positioned the originals at the origin, the transform tag of each clone tells me where the object is and how it's oriented.

I also have "tripwire" objects, which are trigger points in the map that cause events to happen, such as waking up enemies, jumping to the next map, triggering messages, and so on. For these objects I needed more information in the map file than kind and position.

I use Inkscape's XML editor, which gives full control over the XML representation of the underlying SVG file, to store this information. I set the xmlns:battlemints namespace declaration on the root svg element, draw my tripwires out as paths, then add attributes like battlemints:tripwire (to indicate what kind of tripwire) and battlemints:next-board (for a goal tripwire, what map to load as the next level) to set up the tripwire.

Now to save a map file, I wrote a script that takes an Inkscape SVG document and outputs a BattleMints board file. It ignores the Palette and Templates layers and walks through the Map layer, generating a game object for every use tag and tripwire path. The script also performs various postprocessing tasks like eliminating adjacent tile walls from collision detection and swizzling tile objects to improve memory locality. To integrate my script with Inkscape, I write an INX file to describe the script as a plugin:

<inkscape-extension>
    <_name>BattleMints board</_name>
    <id>com.duriansoftware.BattleMints.board-compiler</id>
    <dependency type="executable" location="extensions">battlemints-board-compiler</dependency>
    <output>
        <extension>.board</extension>
        <mimetype>application/x-vnd.DurianSoftware-battlemints-board</mimetype>
        <_filetypename>BattleMints board (*.board)</_filetypename>
        <_filetypetooltip>BattleMints!</_filetypetooltip>
    </output>
    <script>
        <command reldir="extensions">battlemints-board-compiler</command>
    </script>
</inkscape-extension>

After dropping the script and the INX in ~/.inkscape/extensions, I can save my map to a board using Inkscape's "Save as Copy" command (while retaining the SVG for future edits), and I'm done:

In summary, Inkscape is a decent graphics editor, it provides easy access to the underlying XML of its documents, its SVG files are easy to manipulate with any language that has an XML library, and it provides a straightforward interface to plugins written in any language. Inkscape is a fantastic tool for designing game maps and other graphical odd jobs.