1x, 2x, 4x, oh my!

Handling multiple devices and resolutions has been a part of development for many months now. It’s been working rather well, too. I’ve been using “Strategy 3: Smart Object Placement” as described in the Starling Manual for Multi-Resolution Development. Everything was looking and working great on all iOS devices, from the now-ancient iPhone 3GS at 480×320, to the retina iPhones at 960×640, the iPhone 5 at 1136×640, the iPads at 1024×768, and the retina iPads at 2048×1536. Whew!

To support all of these devices, I naively started naming my images roughly according to iOS developer standards, that is, non-retina assets are just called filename.png, retina assets are [email protected], and retina iPad could be [email protected], for example. That’s fine, it worked okay for supporting only iOS. Even so, it became very tedious because I had to write a bunch of custom code for adding the proper extension to every file name when attempting to load assets, based on what device was currently being used. Then I looked at the Starling mobile scaffold project, and realized that they simply separated their assets into 1x, 2x, and 4x directories, but kept their assets named identically. In other words, they had: /1x/filename.png, /2x/filename.png, etc. Well that would certainly make life easier for me! Let’s do it!

Recently we decided that we want to release all of our games on Android as well as iOS, and the hacks and “fixes” we’ve done to get things working on all iOS devices are now coming back to bite us in the ass. One example of this is our in-game background tiles that make up our dungeon/stage view. Due to the aspect ratio difference of iOS phones and tablets, we used two different sizes of background tiles. The iPhone uses tiles like this:

iphone_bg_tile

iPhone bg tile – notice how short it is

And the iPad uses tiles like this:

ipad_bg_tile

iPad bg tile – extra bits at the top

So that right there is a bit of an issue if we’re going to attempt to move to the new 1x, 2x, etc. system because the iPhone retina and non-retina iPad are both technically going to use “2x” assets. So which tile do we use? The answer was actually quite simple, and very helpful when trying to think in terms of supporting any resolution: for the above issue with the bg tiles, I ended up discarding the iPhone tile completely, and just using the iPad tile as the /2x asset. Then I modified the code that positions the bg tiles to line up the bottom of the bg tiles with the lower portion of the screen, and everything works great – on the iPhone the top parts of the tiles are simply off the top of the screen, which is perfectly acceptable for what we’re doing.

iphone_bg_tiles

How things actually work on our iPhone build – the red box is the visible portion of the screen

There were a few more places I had to make adjustments, like on the map screen. But overall it was pretty easy to get working, and it makes supporting various Android resolutions much easier.

Also, Andreas (author of the awesome TexturePacker) replied to an email I sent him, and he offered a solution to another issue I was having – how can I leverage the auto-SD options in TexturePacker to export into my /1x, /2x, etc. directories? He suggested I try something like this:

texturepacker_1x_2x_4x

Using TexturePacker to auto-generate all asset sizes

And it worked perfectly! Now my loading code is greatly simplified, it’s so much easier to exclude certain asset sizes from builds – say for example we wanted a web build with only 1x assets, all we have to do is go into our assets directly after doing a release build, and simply delete the 2x and 4x directories, and everything is ready to go. Awesome!

The only custom code I have now is a small modification to Starling’s AssetManager.enqueue:

                else if (rawAsset is String)
                {
					var newName:String = (rawAsset as String).replace("/img/", 
						"/img/" + Constants.DEVICE_DEF.DirectoryName);

                    enqueueWithName(newName);
                }

All that code does is adds the appropriate /1x/, /2x/, etc. to the file’s path. That way we can enqueue assets with something as simple as

assetManager.enqueue("assets/img/spritesheet_menus.png");

and everything just works!

Leave a Reply

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