Sponsored By

Featured Blog | This community-written post highlights the best of what the game industry has to offer. Read more like it on the Game Developer Blogs.

Scaling your Mobile Game to Any Device Size

Mobile devices come in many formats. An iPad Mini has a resolution of 768x1024 while a Nexus 7 is full HD at 1080x1920. This article demonstrates techniques used in designing a mobile game to work at any device size.

Martin Drapeau, Blogger

June 8, 2016

5 Min Read

This article is also published on Medium.

I just launched on my second mobile game called Miam Boom! Like my first, I wrote it in Javascript and used Cocoon.io to release it to iOS and Android. Again I used Backbone Game Engine. This time however, I made a few improvements to the quality of the game across screen sizes. You see, my games use image sprites. Resizing them dynamically causes blurriness. You lose the crispiness of the images. This is an issue I failed to properly address in Ludo’s Quest. This time around, I was determined to solve this issue.

Many devices, many screen sizes

Mobile devices come in many formats. My iPad Mini has 768x1024 physical pixels. My iPhone 6 has 750x1334 pixels. My Nexus 7 has 1080x1920 pixels. Sprites therefore have to be scaled accordingly. In Ludo’s Quest, the game was in landscape mode and I locked the width to 1024 pixels using the viewport meta tag.


<meta name=”viewport” content=”width=1024, user-scalable=no”/>

On my iPad mini this looked great. However on other devices, the dynamic resize made things look blurry.

The solution is not to force the width of the viewport, but use the actual physical width of the device, and to load pre-scaled sprites depending on the resolution. The viewport should be set this way:


<meta name=”viewport” content=”user-scalable=no”/>

Note: Many people on the Web mention to set width=device-width. This will set the width of your viewport to the CSS width of the device — not the physical width. For an iPhone 6, you’ll get 375*667 pixels instead of 750x1334 pixels. That’s not what you want.

Establishing sprite sizes

Remains the need to define the sprite sheets at multiple resolutions. In Miam Boom! I used the monsters (main characters) as the baseline. At the minimum resolution of an iPhone 3 without retina, it is 180 pixels, one fourth of the device height of 480 pixels. As the resolution increases, graphics are scaled by 2x, 3x or 4x. Here’s what The Cat, one of the monsters in the game, looks like on various devices properly scaled.

iPhone 4 (640x960) scale=2x, iPhone 6 (750x1334) scale=2x, and iPad Air (1536x2048) scale=3x

You will notice The Cat is sometimes smaller on certain screens. That’s okay but comes with side effects for the GUI and game play. I had to make my game responsive and position elements proportionally to the width and height of the viewport. For example, buttons are left, center and right justified. Labels are anchored to the top and bottom. The monster is always anchored relative to the bottom. These strategies work regardless of the height or aspect ratios.

Vector graphics

The key is to use vector graphics. With Ludo’s Quest I combined vector with pixel-based graphics. Scaling up non-vector graphics always results in blurry images. Lesson learned. This time around I used vector graphics exclusively. I have now mastered AI.

I defined my sprite sheets using Adobe Illustrator and exported images to the proper scaling factor. For example, this is the main game sprite sheet.

Miam Boom! artifact sprite sheet

The spritesheet has 4 different versions, for each scaling factor:

  • artifacts.png (990x360) scale=1x

  • artifacts2.png (1980x720) scale=2x

  • artifacts3.png (2970x1080) scale=3x

  • artifacts4.png (3960x1440) scale=4x

The trick is to load the properly scaled images depending on the device screen size.

Dynamic loading

In Ludo’s Quest I pre-loaded all graphics directly in the HTML file this way:

<body>

 <img id=”gui” src=”img/gui.png” style=”display:none;” />

 <img id=”artifacts” src=”img/artifacts.png” style=”display:none;” />

In Miam Boom! I could no longer do that. At runtime, I determine the scaling factor to load the proper sprites. I load them dynamically using Javascript. Backbone Game Engine has this little function to do so:


function loadImage(url, callback) {
  var img = document.createElement("img");
  img.src = url;
  if (callback) {
    img.onreadystatechange = callback;
    img.onload = callback;
  }
}

Backbone.SpriteSheet has an imageUrl property to dynamically load images. It uses this function so you don’t have to worry about it.

Note: On iOS, images get loaded really fast. On Android however it seems a lot slower. To avoid showing a screen without images, it is important to wait for all images to have been loaded. Backbone.SpriteSheetCollection has event allSpawnImg to handle that.

Before I load images, I need to determine the size of images to be loaded depending on the pysical pixel size of the device.


var screenWidth = Math.max(window.screen.width * window.devicePixelRatio, window.innerWidth);
var factor = screenHeight >= 960 ? 2 : 1;
if (screenHeight >= 960*2) factor = 3;
if (screenHeight >= 960*2.5) factor = 4;

Image urls are then modified to load the proper size:


imgUrl.replace(".png", factor + ".png");

Adapting gameplay

Since screen size and aspect ratios differ from device to device, I had to ensure the gameplay was adaptable to all situations. Again, I modified my heuristics to anchor to the top and sides. Furthermore, as the game measures distance in pixels, I needed to scale velocity and acceleration as well.

  

iPad Mini (768x1024) and iPhone 6 Plus (1080x1920)

Performance considerations

At first I thought loading much bigger images would impact performance. I also wondered about memory consumption. After all, an image scaled at 2x takes 4 times the amount of memory. Scaled at 4x is 16 times.

Fortunately, that does not seem to be the case. It seems there is enough processing power and memory on newer iPads and iPhones to handle the extra pixels. Even my Nexus 7 with a resolution of 1080p was performing well. I was pleasantly surprised.

Conclusion

I’m very happy with the outcome. Miam Boom! looks crisp on any device. This is a major improvement over Ludo’s Quest. What I’ve learned and applied here will serve me for my next game for sure. I invite you to check it out for yourself.

Miam Boom! is on the App Store.

Miam Boom! is also on Google Play.

Read more about:

Featured Blogs
Daily news, dev blogs, and stories from Game Developer straight to your inbox

You May Also Like