Cloning Zelda, part 2: Tile thing
Needless to say, upon reflection, that looked like a really bad idea. So I went back to the drawing board, and came up with several design considerations:
- Only repaint the background image when it changes (not every game tick!)
- Use two canvas layers to separate background from sprites (so player and enemy movement won't trigger a background redraw)
- Use a "tile" approach to limit image size in memory
So, armed with my trusty copy of Paint Shop Pro 7, I started slicing up the map. What I discovered was that the game overworld uses a surprisingly sparse number of tiles to do its job... in fact, these 79 tiles cover all the bases! As I said before, the full map of Hyrule is 4096 pixels wide by 1408 pixels high. We can reproduce the whole thing by using a 2-dimenional array of 256x88 tiles, 16 pixels square. I chose to go one step further, subdividing the map into individual screens, and each screen into its component tiles. This gave me a 3-level map structure:
- 1 map of 4096x1408 pixels
- = a 16x8 matrix of map screens,
- each of which = a 16x11 matrix of 16x16 tiles
Now came the long & tedious part: encoding the map as a data structure! I let the above structure inform my design decisions, creating a Map class with: a current property to contain an x/y pair representing the currently visible screen within the map, and a 16x8 two-dimensional array containing MapScreen objects. Each MapScreen object knows its (x,y) position within the larger map, and contains a 16x11 array of cells, each an (x,y) coordinate pair representing that cell's source tile in the global "tiles" image. Map and MapScreen both contain draw() methods that take an HTML Canvas 2d drawing context as a parameter, and which take care of drawing themselves when requested. The code for both Map and MapScreen is here: map.js, and the data file is here: mapData.js
Once the code for the new map was done, there was still the matter of encoding the map data in a way the Map/MapScreen classes could use. I started out hand-coding the map data myself, but this soon proved to be the gateway to madness, and I decided that I needed to build a map editing tool. This would be useful, I reasoned, not only in terms of saving me time now, but also because it would allowing for custom map creation in the future (assuming I live long enough to get this beast fully running!).
Anyway, after a few days of spare-time work and referring often to the original overworld map image, I've finished encoding the map, and the new version of the game is here. Basically the same functionality as from Part 1, but with a much smaller footprint. I've also started to implement collision detection, which the tiled map makes quite a bit simpler, but considering how long it took me to encode the map tile data, that task kind of took over this step of the process.**
Next time, we're going to finish implementing collision detection, and introduce the missing Armos statues (hint: they're not part of the current map for a reason)!
** Footnote 2: You may notice some blurring and visual artifacts in this new version of the game map; these appear to be due to the fact that I'm scaling the game up to 2x its original size, so I'm going to have to experiment with resizing it differently, or keeping it in its original 256x240 size. As with the Mapper performance, Chrome seems to handle this much better than Firefox, but a new solution is probably in order.