Experiments in rendering a Tiled Map in javascript/html…

Sophia Game mk1.



Sophia’s first tiles!
Embrace the pixels!

Sophia has been chomping at the bit to make more games. Since it’s been going on two years since I last flexed my gamemaking muscles fully, and since I rather adore Sophia, I’ve been chasing this rainbow.

I’ve been ever more intrigued by the idea of a pure html/javascript game engine of late, and have started taking existing, established tools (like mapeditor.org’s tiled) and putting them into the browser.

Here’s the result: (currently firefox-only). To fully get the pleasure, inspect elements on this example in firebug.

The idea is simple: html/js has affordances baked-in to parse xml documents. This can handle traditional map data. css sprite-sheet techniques have been used for years now, which directly mimic old tilset/vsp-style assets. Combine the two… and you have a effen map. Throw in browser optimizations for visible/hidden elements, and we should have a relatively cheap rendering method.

The above test is fairly simple: one 30×30 map, one layer. It loads instantaneously fast. It’s tiles are a single gif sized 304×144. Fairly economical. I decided to shove each of these boys into a div for now and use the background-image css spriting technique to get a “purist” tiling implementation going.

I opted against using canvas for now because I wanted to see how far I could get without it. So far so good, but I’ve not yet really stressed the system. The next jump will be to take some of my epic 6-layer maps from SotS, translate them into xml, and see how they fair in the browser.

Of the code I wrote, I suppose the “sauce” was a fairly common offset calculation. Although this sort of endeavor may not be so common in the modern age, it’s pretty commonplace to those of us who labored in 320×240 back in DOS. Get off my lawn.

var tileset = {
    tileWidth: 16,
    tileHeight: 16,
    setWidth: 304,
    setHeight: 144,
    
    getCoordsfromIdx : function( idx ) {
        var idx = parseInt(idx);
        idx--; //tmx is 1-based, not 0-based.  We need to sub 1 to get to a proper mapping.
        //idx--;
        
        var perRow = this.setWidth / this.tileWidth;
        
        var x = idx % perRow;
        var y = (idx / perRow);

        return [ 
            -(parseInt(x)*parseInt(this.tileWidth)),
            -(parseInt(y)*parseInt(this.tileHeight))
        ];        
    }
}

This is converting a single tile index into two coordinates for the renderer to consume. For instance, if you want tile 2, it takes a ‘2’ at the top, does some maths, and tells you that tile 2’s offset is 16 pixels in from the top-left corner, and 0 pixels down (ie, on the top row). Some strange quirks of this code: I had to decrement the idx, because Tiled’s xml format is 1-based, not 0 (ie, the first tile, the one at (0,0), is index 1, not index 0); and I negate the two numbers I return because the consumer of these coordinates is a css background-position style, and that’s how they work.

Also of note was a small hiccup when I uploaded this to my server. My sandbox had no trouble serving a .tmx file as Content-Type: text/xml, but my big-boy server threw a conniption about it. I didn’t realize that was a problem until I threw some debugger statements into the code that “should’ve just worked” and found that all of the proper stuff was in the responseText attribute, but responseXML was null. So I renamed the mapfile to .xml on the server and everything worked fine.

I guess next step, before trying to stress the system with a super macho map, is to figure out why this isn’t working in Safari/Chrome/IE/Opera/Whatever…

Also read...

Leave a Reply

Your email address will not be published. Required fields are marked *