How I handle multiple resolutions in Android games
Android devices come in a variety of screen sizes, resolutions, densities and aspect ratios. I have written a render-helper class in order to support all this device variety. Here’s how it works:
The first hindrance in achieving resolution independence is Android’s default way of trying to auto-adjust the textures according to the screen density of the device.This adjustment can be bypassed by creating a folder called drawable-nodpi in the res folder. This prevents any unwanted scaling of textures placed in that folder. Some developers make different art assets for different resolutions to avoid any scaling artifacts that may occur. I have extremely limited resources and don’t want to create multiple resolution-dependent art assets.
After a bit of research, I’ve come to the conclusion that most Android phones that I want to target have a 480×800-ish resolution. I’ve also noted that the smallest aspect ratio of any Android phone (held in landscape orientation) is 4:3, that is Android phones don’t get any ‘squarer’ than 4:3.
With this data in mind, I created a virtual game screen of 800×600. This means my game logic acts under the impression that the game is always running in a resolution of 800×600. All positions and velocities are absolute to that resolution. The game logic calls the render-helper class to render and load textures. This render-helper class scales the virtual game canvas to fit on the actual device screen. The textures are scaled by the same class at load time using the Bitmap.createScaledBitmap function. Drawing position coordinates are also scaled similarly. The scale is determined by: Scale = Actual Screen Width / Virtual Screen Width.
In devices with wider screens, some of the virtual screen bleeds out vertically. Alternatively, I’d have to horizontal display black bars on squarer screens, which is plain horrible. To deal with this vertical overflow, I just draw the HUD elements relative to the vertical offset. This offset can be calculated using: Offset = ((Scale * Virtual Screen Height) - Actual Screen Height)/2.
The results of this effort are games which run on most screens and even on older versions of Android (1.6 and onward). Porting to other platforms also becomes easier due to separation of game logic and rendering API calls. Font positioning is an issue, and I’d rather pre-rasterize them whenever possible. Physics accuracy may be compromised on larger resolutions, but won’t be particularly noticeable due to the small physical size of mobile screens.