Universal app development

I’ve created this thread to allow members to discuss the various pro’s and con’s associated with Universal app development. That is writing apps in Codea that will run (unmodified) on all the main devices from 320x240 iPhone 3GS / iPod touch, retina screen devices, through to iPhone 5/6/6+ with their differing resolutions.

What I’ve done so far with my own projects is work off a virtual coordinate system (ie in the range 0-1) and then multiply the numbers by WIDTH & HEIGHT as necessary. This works for me and I can “fake” different devices by simply setting WIDTH & HEIGHT to the required values. However this means I can end up with a lot of fractional coordinates which aren’t compatible with the new integer restrictions in Lua 5.3 and I have to call math.floor() a lot - this suggests to me that there must be a better (read simpler) way.

Another idea I’m considering is to pick a resolution and simply stick with it and then use the scale() command with an appropriate fixed value to sort things out, but do I opt for the lowest res (320x240) and scale up or the highest res (768x1024) and scale down. What about distortion when catering to devices with different aspect ratios - again an option might be to pick the most compatible res and be wary of “overscan” or “safe zones” - ie not putting important UI elements too close to the screen edges.

What about using different layouts for each device (or class of device) so that a different “view” is presented on phones as opposed to tablets.

Lastly what about orientation changes - personally I tend to pick an orientation and stick to it, but in a lot of cases it makes sense to have different layouts per orientation - like adding a UI split view on the iPad landscape vs having it slide in from the left on portrait, I’ve also seen many apps that present a totally different view depending on orientation - especially on phones.

If you look up any post on HTML5 gaming, layout / resolution / orientation is a big issue given the range of devices and whilst we don’t have that problem there is now at least 5 different resolutions in the Apple eco-system and I can’t see the situation getting any better.

Ladies & Gent’s the floor is open for your comments… :slight_smile:

@TechDojo which functions are you having to floor your input on? As far as I’m aware only clip has this restriction — and I’m thinking of removing it to allow for fractional clipping on retina displays (where the clip ultimately ends up on a pixel boundary).

I have yet to test my app on a smaller device, so my comments are all “in theory”. I think if you’re doing a 2D game, if you design the playing arena to be scrollable, rather than a fixed screen, you’re probably going to make things easier for yourself down the line. Smaller screens will just have to scroll more.

Also, allowing the orientation to be flipped mid-game is a good way to test (I hope), that your game is “aspect-ratio agnostic”, even if it’s not a feature that you want to enable in the shipped product: if the game is just as happy (and playable) in 3:4 as it is in 4:3, then that probably bodes well for other ratios (eg iPhone 5/5S/iPod Touch 5 are 1 pixel shy of 16:9/ 9:16).

From somewhere I got a device emulator class (maybe Reefwing Software?), which just sets WIDTH, HEIGHT to various settings (I think you have to start the project and then immediately hit restart in order for the new W/H settings to work, though apparently that’s fixed in the next version of Codea).

But I guess you don’t really know about the usability, the playability (which is the ultimate aim), until you actually try it on a smaller device. It’s all very well if everything scales correctly, but if that makes elements on screen too small to see/ interact with, then that’s no use (and for this reason, I think using scale could be a better route then using your pixel units). In other words we need to take into account the differing pixel densities of different devices (retina iPhone is much more dense than retina iPad), not just differing width/height.

Maybe I’ll have a look at that emulator class and see if I can get it to simulate different pixel densities by scaling, so that an object appears the same size as it would on an iPhone (rather than the same resolution).

Ok, the short version for those who can’t be bothered to read my screed above is, we tend to focus on different devices resolutions, but pixel density might be a more useful metric to consider, from a playability point of view.

@Simeon - the image:set() function also requires ints. But I also wary of having to do all the extra multiplies as well.

@yojimbo2000 - With regards to layout etc I was as much thinking about menu screens, UI etc where I wouldn’t want to scroll. Likewise I was thinking about single screen - puzzle style games where again I don’t want to scroll.

With regards changing the size, what I found on my iPad was that when I changed the WIDTH / HEIGHT values, rendering on the screen was actually quite close to the physical size of my iPod & iPhone5S, but yes you’re correct - exporting to xCode and then compiling on a real device did give a different experience - holding the device in one hand, that kind of thing.

However I am particularly interested in any different ways that people have solved the universal issue.

@yojimbo2000 Interestingly enough I don’t think pixel density makes that much of a difference. When considering the iPhone 6 the screen has a x2 pixel density of 750 x 1334 pixels, but in Codea you treat the resolution as 375x667 and let the OS / Codea runtime sort out the retina issues.

Yes, luckily for us Codea automatically takes care of Retina vs non-Retina. I was pointing out though that things will appear 80% smaller on an iPhone 4, and 60% smaller on an iPhone 6+ than on a full-size iPad (which could affect your ability to accurately touch a button for example), because they have more pixels-per-inch. Comparison of different PPIs:

http://www.tekrevue.com/retina-display-comparison/

Although, we should also consider the different distances people hold their devices at, different sizes of finger, etc etc. This UXmatters website is great for these kinds of thing:

http://www.uxmatters.com/mt/archives/2013/03/common-misconceptions-about-touch.php

I have released 6 games that I have made with Codea so far, all are universal.

What I do is just find the multiple of whatever fixed number I need, and use WIDTH or HEIGHT divided by that multiple. Hard to explain, so an example will make it clearer:

If I have a rectangle in the direct center of the screen (rectMode(CENTER)):


rect(384 ,512 , 256, 128)

For the size of the object I get a multiple of both X and Y depending on the WIDTH of the screen, I found that for the size of objects, you need to have both WIDTH and HEIGHT size of object to be both depending on the WIDTH or both depending on the HEIGHT, else you get stretching of sprites and it throws the size of your sprites/objects off. With that said…

I will divide the 768/384, resulting in 2, so place WIDTH/2 for the first number (X location). Then 1024/512, again resulting in 2, to get HEIGHT/2 for the second number (Y location). Then for the size of the object I always use WIDTH for both, so 768/256 = 3 resulting in WIDTH/3 for the third number (x size), and 768/128 = 6, so WIDTH/6 for the fourth number (y size).

The end result is:


rect(WIDTH/2,HEIGHT/2,WIDTH/3,WIDTH/6)

This allows the rectangle to be in the correct size and position on any sized device, in any aspect ratio, and in any orientation. You can test it by adding the above rectangle to the draw() function of a new project and change WIDTH and HEIGHT to whatever you want in setup(), and the rectangle will always be in the center.

I do this with EVERY fixed number, including fontSize(), which I do according to WIDTH.

I tried to simplify it by making a multiple in setup (per the suggestion of a forum member), then dividing the fixed number by that multiple, for example in setup():


xMulti = WIDTH/768
yMulti = HEIGHT/1024

then in draw():


rect(384/xMulti, 512/yMulti, 256/xMulti, 128/xMulti)

This worked perfectly in Codea, even when changing the WIDTH and HEIGHT in setup(), and I though it would have made my life easier, but for some reason it bugged out in Xcode, and the app was rejected because the scrolling background was leaving black lines where the background wasn’t scaling correctly on some devices. So I went back to my original foolproof way and the app was accepted.

@yojimbo2000 - according to the original Apple design specs they used to specify that a minimum size for touchable UI elements should be 44x44 pixels (or 88x88 for retina) - as a guideline that gives a useable button size on all devices.

@Crumble - I think we take a similar approach, just come at it from different sides - I work with coords in the range 0-1 so if I want to draw a sprite a quarter of the way across the screen I just set it’s coord value to 0.25 and I have wrapper functions that detect if a coord is <= 1 and if it is it automatically multiplies it by WIDTH (or HEIGHT) - worked perfectly and my universal app was accepted first time :slight_smile:

I was just wondering if there was a simpler way - like for instance working on a “pretend” coordinate system of 0-1000 and then doing a single call to scale with appropriate scale factors as the first line of draw().

As for font’s I coded a fontSizeEm() function that multiplies the argument by a fixed value depending on the resolution, I worked it off the idea that using a font size of 20em’s using the default font, a string of 20 upper case M’s would just fit the width of a portrait screen, that way text is automatically sized so the physical size of a string (in relation to the screen width) is the same across all devices.

I’ve also written my own widget UI library that can create a full UI from a setup table, it wouldn’t be too much of a pain to use different tables for different devices / orientations.

Currently I’m doing values of 0-1 multiplied by WIDTH and HEIGHT.

Compared to using a scale system here’s how I see it:

Scale system:

  • things maintain relative size and distance to each other

WIDTH, HEIGHT system:

  • things maintain relative size and position to entire screen

The only issue I’ve had with multiplying coords is that on devices with different aspect ratios the heights differ and the positions are more spaced apart, but it’s not been a massive problem yet.