Ejecta & Impact.js – Which Resolution for iPhone?

 
3 Kudos
Don't
move!

The official documentation of Ejecta is alright to get you started, but the stuff about retina and iPhone resolutions just gave me a headache, especially since I wanted to do a pixel-perfect game with no scaling. So I ran some tests and share them with you to save you the time.

You’re probably interested in one of these cases:

  • Make a pixel style game where pixels scale up automatically by a factor of 2 or 4
  • Make a pixel-perfect game where pixels are shown 1:1

There’s a summary at the end of this article, if you want to jump directly to the solution. However, if you’re interested in all the things you can do wrong, you should take a quick look at all the stuff I tested and what you should avoid to prevent resolutions that feel “off”.

The desired outcome is influenced by:

  • the images you provide
  • the resolution you set for the game (or canvas element)
  • the ingame scaling

Setup

I use a standard installation of Impact 1.23 and I added two lines of code:

MyGame = ig.Game.extend({
    // Load a font
    font: new ig.Font( 'media/04b03.font.png' ),
    img: new ig.Image( 'media/test284.png' ),
    ...

    draw: function() {
        // Draw all entities and backgroundMaps
        this.parent();
        this.img.draw(0,0);
        ...

The game draws one of these 3 test images I created. Image credit Burning_Sunrise by raynoa. These are the three test images:

test284.png test568.png test568@2x.png

I also downloaded Ejecta and use it in ins default installation with 3 modifications:

  • Icon.plist: Set “Initial interface orientation” to “Landscape (right home button)”.
  • Project view: Status Bar Style: Uncheck “hide during application launch”. You can leave it checked. This was a test for something else, but actually gives a good idea for the proportions etc.
  • Content of index.js:
ejecta.include('lib/impact/impact.js');
ejecta.include('lib/game/main.js');

I have an iPhone 5 with a screen resolution of 1136×640. If you have an iPhone 4(s), you might want to adjust everything to 960×640.

Cache

The iPhone and/or Xcode seem to hold assets like images and js-files in some sort of cache. To make sure that your settings apply, you should wipe the app from the phone (tap and hold until the X shows, then tap the X to remove the app) and clean the build files in Xcode (Product -> Clean). I found that doing only one of these things wasn’t always enough.

The first line after every screenshot shows the startup log of the Ejecta app.

Tests

Please click the images to see the scaling in a better resolution.

Test 1

ejecta-resolution-test-01

Creating ScreenCanvas (2D): size: 640×480, style: 640×480, retina: yes = 1280×960, msaa: no

I modified the following line to achieve this effect:

ig.main( '#canvas', MyGame, 60, 320, 240, 2 ); // scaling ingame

Note that the resolution of 320×240 is a bit off for an iPhone 5 and an ingame scaling (last parameter = 2) is not recommended in the Ejecta docs.

Comment: Looks totally off, since the scaling stretches pixels in the wrong way. Shouldn’t be used.

Test 2

ejecta-resolution-test-02

Creating ScreenCanvas (2D): size: 640×480, style: 640×480, retina: yes = 1280×960, msaa: no

Same settings as above, but added the line:

ig.System.scaleMode = ig.System.SCALE.CRISP;
ig.main( '#canvas', MyGame, 60, 320, 240, 2 );

Comment: Looks still off, since 320×240 cannot be scaled properly to the iPhone 5’s resolution.

Test 3

ejecta-resolution-test-03

Creating ScreenCanvas (2D): size: 320×240, style: 320×240, retina: yes = 640×480, msaa: no

Disabled ingame scaling and set to a factor of 1:

ig.main( '#canvas', MyGame, 60, 320, 240, 1 );

Comment: What we now have is an image of 284×160 scaled up to 568×320 (factor 2 scaling) on a canvas that is 640×480 in reality. The text “It works” is shown not in the center, which implies that everything is somehow a bit off. Only the scaling itself is kind of crisp and nice.

Test 4

ejecta-resolution-test-04

Same as above, but I removed this line:

ig.System.scaleMode = ig.System.SCALE.CRISP;

Comment: This one is ugly. You should enable crisp scaling. It looks way better.

Test 5

ejecta-resolution-test-05

Creating ScreenCanvas (2D): size: 568×320, style: 568×320, retina: yes = 1136×640, msaa: no

In this test, I increased the resolution to 568×320:

ig.main( '#canvas', MyGame, 60, 568, 320, 1 );

Comment: Now it gets interesting. The game still loads the small 284×160 image. It’s a quarter of the “game resolution”, but since the iPhone 5 has a retina display of a real resolution of 1136×640, the image gets scaled by a factor of 2. We’re getting there…

Test 6

ejecta-resolution-test-06

Creating ScreenCanvas (2D): size: 568×320, style: 568×320, retina: yes = 1136×640, msaa: no

We just changed the image in this test:

img: new ig.Image( 'media/test568.png' ),

Comment: This is already what you want to achieve in a pixel-style game with a scaling factor of 2. The game resolution is 568×320, the image is the same resolution, but since the real resolution of the iPhone is twice that size, the image gets scaled by a factor of 2. The next test helps to understand this.

Test 7

ejecta-resolution-test-07

Creating ScreenCanvas (2D): size: 1136×640, style: 1136×640, retina: yes = 2272×1280, msaa: no

My first naive approach had me select the game resolution according to the resolution of the iPhone, like so:

ig.main( '#canvas', MyGame, 60, 1136, 640, 1 );

Comment: This however, creates a real canvas of 2272×1280, which is way too big for our game. The image itself is scaled again, but notice how “It works” just disappeared? This is because the text is in the center of the real canvas (approximately at position 1136×640).

Test 8

ejecta-resolution-test-08

Creating ScreenCanvas (2D): size: 568×320, style: 568×320, retina: yes = 1136×640, msaa: no

Two changes. First, I reduced the resolution of the game back to 568×320:

ig.main( '#canvas', MyGame, 60, 568, 320, 1 );

Second, I added the test568@2x.png image to the media/-directory. According to the Ejecta docs, the @2x-image is loaded automatically.

Comment: So, this is where I start to get a headache. You’re effectively programming the entire game as if it had a resolution of 568×320, but you provide images with twice the size (@2x-filenames) to show them with a scaling-factor of 1. If your main character is 32 pixels high, the actual image must be 64 pixels in height. Notice how the font doesn’t have a @2x-version and therefore is scaled by a factor of 2!

Test 9

ejecta-resolution-test-09

Creating ScreenCanvas (2D): size: 1136×640, style: 1136×640, retina: yes = 2272×1280, msaa: no

Again, I increased the game resolution and kept the @2x-image in the media-directory:

ig.main( '#canvas', MyGame, 60, 1136, 640, 1 );

Comment: This loads the @2x-image automatically, but “It works” is missing again, because the real canvas is too big and the font gets centered in the real canvas. Don’t do this.

Test 10

ejecta-resolution-test-10

Creating ScreenCanvas (2D): size: 1136×640, style: 1136×640, retina: yes = 2272×1280, msaa: no

In this test, I kept the resolution as in the previous test, but I renamed the test568@2x.png file to othertest.png and used this:

img: new ig.Image( 'media/test568.png' ),

Comment: What it does is this: It loads an 1136×640 image (the 568×320 @2x-version) and shows it on a canvas that is 2272×1280 in reality, which causes the image to get scaled by a factor of 2. Now, the image and the font “It works” are way to big for the iPhone 5 screen.

Test 11

ejecta-resolution-test-11

Creating ScreenCanvas (2D): size: 284×160, style: 284×160, retina: yes = 568×320, msaa: no

Still with me? Three changes: I removed the @2x-version and changed 2 lines of code:

img: new ig.Image( 'media/test568.png' ),
...
ig.main( '#canvas', MyGame, 60, 284, 160, 1 );

Comment: This tries to load a 568×320 image to a real canvas of 568×320, but since this image isn’t the @2x version, it gets messed up entirely. Wrong approach.

Test 12

ejecta-resolution-test-12

Creating ScreenCanvas (2D): size: 284×160, style: 568×320, retina: yes = 1136×640, msaa: no

As you can see, this creates a factor 4 scaling. How do you do it? Remove @2x versions. Set the game resolution to 284×160 and add canvas stretching:

img: new ig.Image( 'media/test284.png' ), // load 284x160
...
canvas.style.width = window.innerWidth;
canvas.style.height = window.innerHeight;
ig.System.scaleMode = ig.System.SCALE.CRISP;
ig.main( '#canvas', MyGame, 60, 284, 160, 1 );

Summary: Which resolution to pick?

Always enable CRISP mode:

ig.System.scaleMode = ig.System.SCALE.CRISP;

Pixel-perfect games with a factor 1 scaling (no scaling):

ejecta-resolution-test-08

Set game resolution to 568×320 for an iPhone 5 and provide all images in twice that resolution (@2x-images). If you drew a beautiful character that is 64 pixel high, treat it ingame as if it were only 32 pixels high.

Pixel-style games with factor 2 scaling:

ejecta-resolution-test-06

Set the game resolution to 568×320 and do not provide @2x-images. If your character is 32 pixel high, treat it ingame as if it is 32 pixel high. It will be automatically stretched to 64 pixels on a bigger canvas.

Pixel-style games with a factor 4 scaling:

ejecta-resolution-test-12

Set the game resolution to 284×160, do not provide any @2x-images. Add canvas stretching:

canvas.style.width = window.innerWidth;
canvas.style.height = window.innerHeight;

Ejecta will do the rest and scale stuff up to the iPhone 5’s native 1136×640 retina resolution.

Leave a Reply

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