Experiments in rendering a Tiled Map in javascript/html…
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…