Fantasy Sphere RPG Devlog 6

Turning Spritesheets Into Atlas

Since the last devlog there were 33 commits between 2019/03/19 and 2019/04/09, totaling 89 commits. I have worked 68 hours during this period, bringing the total to 210 hours.

As I started adding more things to my test map, I decided to first improve the workflow and prepare for future development. Tiled supports external tilesets – standalone data files that can be re-used between different tilemaps. Phaser currently doesn’t support them though, and in general there’s no reason to include all of tilemap data in the game. We can do better!

So, first things first, I switched my test map to use external tilesets. That meant I couldn’t load the map directly in Phaser. So I wrote a small tool that loads the Tiled JSON maps and the external tilesets it now references. Then it takes out all the useful data (tiles, layers, collision boxes, object types and positions, etc.) and saves it all into a custom JSON file. Then I had to somehow load it in Phaser. Which mostly meant copying over its Tiled loader code and adjusting it for my new format. I would be lying if I said it went without any issues:

tileset_bug|430x288

Now I had full control of everything and could do other necessary things. When rendering, due to floating-point errors, GPU can sometimes sample a pixel too far, causing an ugly effect that’s called pixel bleeding. To fix it, tiles on the texture need to be extruded, which means the pixels on the borders need to be repeated. So I implemented that.

I also took the time to pre-process the geometry used for physics/pathfinding. Boxes near each other could be combined into a single one, improving the generated navmeshes. I used another great Haxe library. A bit of merging and triangle decomposition (as mentioned before, naviagation mesh needs convex polygons to work), and this was the result:

optimized_navmesh|500x300

Done with the necessary things, I moved onto the not-so-necessary. For performance reasons it’s also better to use a single texture, as opposed to many smaller ones. Although with modern GPUs it’s not really true anymore, and it’s not like I was hitting any performance limits… but hey, I will take any excuse to code fun stuff. So apart from tile extruding I also added:

  • Merging: Let’s put everything into single texture (for now anyway). Tiles, sprites, animations, text, everything. “My name is Texture Atlas, for we are many sprites.”
  • Deduplication: Tilesets often have the same tile on multiple places, to make it easier for designers to find related tiles. We only need the one, so let’s automatically check for duplicates and remove them.
  • Filtering: We aren’t using every tile from the tilesets. Why drag them around?
  • Whitespace removal: Spritesheets use grid layout, each individual sprite has the same size. That makes finding the correct sprite, and therefore animation, easier (and historically, it saved memory – something we don’t need to care about anymore). But it means a lot of empty space being left behind. We can remove it, in exchange for storing more data about the texture atlas.

texture_atlas|800x600

There were some funny bugs along the way. This is so-called Phaser’s companion cube. It fills the empty space in your heart, and the good doggy knows exactly what you need:

spritesheet_load_bug|640x480

During this time I also wrote and published the second devlog and did some improvements to my blog (adding some Open Graph tags if I remember correctly).