Best way to develop for iPhone and iPad?

Hello,
I am looking to find the best way to develop for iPhone, iPhone Retina & iPad. If I use dynamic resolution how would that look on the iPad? What if I developed in 1024x768 similar to how the Fruit Assassin example is? Before I start the development of my game, I want to find the best way to design for all these platforms so I do not have to reorganize all of the elements later on.

Thanks in advance.

Hello,

Thanks for the question. I too is interested on developing for ipod touch, iphone3, iphone 4 and ipad. Specifically and to save memory, would 480X960 (retina) look good on a ipad? That i could only provide 320X480 and 480X960 images and cover all the ios line.

Thanks for any pointers.

Mo

For what it's worth, for my current Universal portrait-orientation app I'm doing all the graphics in 1365x2048. I then scale things down to 640x960 for the iPhone Retina, and to half that size for non-Retina iPhones. For the iPad, I'm adding extended visuals left and right to get to 768x1024, but only for some crucial graphics, like the background (named "...@768x1024"), and otherwise re-use the Retina-made graphics (named "...@2x"). Internally in the code I'm using 320x480 as native pixel scope.

So I'm ending up with:
- one very-hi-res original design, ready to be exported into various smaller sizes (for present and future devices -- after all, there may one day be a higher resolution iPad etc.)
- two export sizes per graphic, plus rarely a third one

My config.lua looks like this:

1
2
3
4
5
6
7
8
9
10
11
application =  {
    content = {
        width = 320,
        height = 480,
        scale = "letterbox",
 
        imageSuffix = {
            ["@2x"] = 2,
        },
    }
}

Hello Philipp.

WOW! That's exactly I was looking for. Thank you so much for your in depth and clear explanations. Now I have a clear idea on what to do.

THANKS!

Mo

Philip,
Would you be able to use an example scenario on how to use this or even share your batch function?

Lemsim, glad it's of help!

Dacriburdan, do you mean an example scenario for the batch converter? In case that's what you mean, let me explain.

General background: Normally I have a bunch of layered graphics files in very high resolution. This is the design image with all objects separate. These files might be called main.cpt, menu.cpt, stingy-bee.cpt etc., of which I make very frequent phase backups. Then when I need to prepare the graphics as PNG, I export them one by one and in the Lua file, note down the respective (work-resolution-based) width and height of the PNG. I have a small sprite creation class that helps me with some of the details, and I also have a spritesheet workaround (as I ran into problems with spritesheets & universal apps which use physics, so I basically don't use spritesheets anymore).

As for the batch: On paper, I drew around 50 images, which are kind of like achievement bonus images. I scanned all them and cropped them, then saved them as high resolution PNGs. But now they're all of different sizes, so I needed a way to have them all be in my preferred width and height (plus the @2x Retina/ iPad size). The following is the full converter code (it makes references to "glasses" because these images are images of glasses and mugs) -- the converter also generates the necessary Lua data table. The goal width and height is 180*111 pixels:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<?
require_once('misc.php5');
header('Content-type: text/plain; charset=UTF-8');
// error_reporting(E_ALL);
 
main();
 
function main() {
    $factor = 2;
    $maxWidth = 180 * $factor;
    $maxHeight = 111 * $factor;
 
    $path = 'glass';
    $filepaths = Misc::getFilesInFolder($path);
    foreach ($filepaths as $filepath) {
        $filename = misc::getTextBetween($filepath, $path . '/', '.png');
        $width = 0; $height = 0;
 
        list($width, $height) = getImageSize($filepath);
        $filepathNew = $filepath;
        if ($factor == 2) { $filepathNew = str_iReplace('.png', '@2x.png', $filepathNew); }
        resizeImage($filepath, $filepathNew, $maxWidth, $maxHeight, $width, $height);
 
        $title = substr( $filename, strLen('00-') );
        $title = str_iReplace('-', ' ', $title);
        $title = misc::getProperTitleCase($title);
        misc::echoNow( "    app.glasses[#app.glasses + 1] = { filename = '$filename', title = '$title' }  \r" );
    }
}
 
function resizeImage($filepath, $filepathNew, $maxWidth, $maxHeight, $originalWidth, $originalHeight) {
    $ratio = ( (float)$maxWidth ) / $originalWidth;
    $ratio2 = ( (float)$maxHeight ) / $originalHeight;
    if ($ratio2 < $ratio) { $ratio = $ratio2; }
 
    $newWidth = $originalWidth * $ratio;
    $newHeight = $originalHeight * $ratio;
    $resizedImage = imageCreateTrueColor($maxWidth, $maxHeight);
    $white = imagecolorallocate($resizedImage, 255, 255, 255);
    imageFilledRectangle($resizedImage, 0, 0, $maxWidth, $maxHeight, $white);
 
    $source = imageCreateFromPng($filepath);
 
    imageAlphaBlending($resizedImage, false);
    imageSaveAlpha($resizedImage, true);
    imageAlphaBlending($source, false);
    imageSaveAlpha($source, true);
 
    $destinationX = intVal( ($maxWidth - $newWidth) / 2 );
    $destinationY = intVal( ($maxHeight - $newHeight) / 2 );
 
    imageCopyResampled($resizedImage, $source, $destinationX, $destinationY, 0, 0, $newWidth, $newHeight, $originalWidth, $originalHeight);
    $compression = 9;
    imagePng($resizedImage, $filepathNew, $compression);
 
    imageDestroy($resizedImage);
    imageDestroy($source);
}
 
?>

Is this all about saving memory? Corona scales for you if you set scale=zoomStretch in your config.lua. Don't you blow out the size of your application by including all of the different image resolutions?

Dave, if you want crisp & sharp graphics then you need to provide low-res graphics (for e.g. iPhone 3GS) as well as higher-res graphics (for e.g. iPhone 4 or iPad). An automatic up-zooming of graphics will add an unwanted blur to your graphics, meaning they won't be as nice to look at on higher-res devices. This may be OK with you for certain graphics, but it's not ideal for sharp, important graphics.

In a sense, yes, it is about saving memory, because otherwise I may just try to provide higher-res graphics even for lower-res devices, then have Corona automatically down-zoom them (I haven't tested how well the resampling works; you will often see differences in how a program zooms in or out of pixel graphics, as there will have to be loss in some way or another). Providing two sets of graphics on the other hand ensures the device won't unnecessarily load too-large graphics, because -- as you probably know -- the app will only load one set of the two graphics, based on the "@2x" extension.

Understand about up-scaling, which is why I'm sticking with the latter approach and providing higher res and letting Corona down-scale, which may be naive.

A question about the 2x resolution. If the asset is twice as big, but the screen isn't, won't they look different on different devices? For instance, a 32x48 sprite takes up 1/10th of the display of an iPhone 3GS. A 64x96 version of the same sprite will look relatively smaller on an iPad, won't it?

Or do you scale to fit the iPad in your @2x version, but then what about the Retina?

Two asset sizes doesn't seem enough to cover the range of aspect ratios.

> Understand about up-scaling, which is why I'm
> sticking with the latter approach and providing
> higher res and letting Corona down-scale, which may be naive.

I had figured this uses more texture memory than needed, but perhaps Corona does it in a smart way that doesn't really add to the memory. Perhaps someone from Ansca can clarify? It would certainly be easier to only prepare a single set of graphics.

> Or do you scale to fit the iPad in your @2x version, but
> then what about the Retina?

I instruct Corona to have all things be scaled to fit the screen. So there is a minor upscaling from the Retina graphics to fit the iPad. But this upscaling is so minimal that it won't cause distracting blur on the images. As for the different proportions when going from Retina to iPad, I fix this by providing a different background graphic just for the iPad (one which has some additional stuff to the left and right, while specifically not affecting game play, i.e. the base play area and side walls still have the same relations). In the end, I have two assets for most things (like moving sprites), and three assets for background images.

"I instruct Corona to have all things be scaled to fit the screen."

Using object.xScale and object.yScale?

No, but using this in the config.lua:

1
2
3
4
5
6
7
8
9
10
11
application =  {
    content = {
        width = 320,
        height = 480,
        scale = "letterbox",
 
        imageSuffix = {
            ["@2x"] = 2,
        },
    }
}

Thanks for the insight...this has been helpful. One final question. Is it best to place objects relative to the playable area? e.g., assuming I'm using the entire screen as my playable area, something like:

1
2
player.x = display.contentWidth/2
player.y = display.contentHeight/2

Don't worry about positioning in regards to different device resolutions -- Corona will all handle it quietly in the background for you. Corona knows your native resolution you coded for -- say, you've assigned sprite.x = 10 -- and repositions relatively to screen size on the final device.

The only thing you need to realize is that certain devices, like the iPad, have different proportions. For instance, In my current universal game, I have walls positioned to the left and right, outside the screen. On the iPad, I have more space to the left and right, which means those walls are now (automatically, because I used letterbox scaling) inside the screen. Of course, I *could* (would I want to) push those back out of the screen, but that would affect core game play and balance, which was fine-tuned and cannot be changed (I have certain brick-like things falling down from above and it's important that the number of bricks which can fill the game area remains constant across devices). So basically in my game, the most left and right areas are blocked by walls and mostly "decorative" (as they're filled by graphics, you won't notice as player).

That being said, I do often use constants like "app.maxXHalf" or "app.maxY" or "app.minX" when I assign certain positions, just because it's more readable. The actual values behind those however *won't* change with different resolutions. "app.maxX" will be 320 even when I'm on an iPad -- as mentioned, Corona quietly converts the value in the background (given the right config.lua) so we don't have to.

BTW. Unretiner is a fantastic tool for batch processing a bunch of images into half size images. It's dirt cheap on the Mac App store too.

And no, I'm not affiliated with the developer :) I just use the app.

Thanks Philip! That answered everything I needed and more. Can't thank you enough!

"BTW. Unretiner is a fantastic tool for batch processing a bunch of images into half size images. It's dirt cheap on the Mac App store too."

I use ImageMagick. It's free, has a command line interface, and supports all kinds of post-processing on images, including resizing and stitching into sprite sheets.

Ah. Unretiner is free currently. But I use in conjunction with Texture Packer for Sprite Sheets. Easy combo for people who don't want to get into complex scripts and server stuff.

Yup. There's more than one way to skin a cat :-)

Mmm Taco Bell!

:)

views:2163 update:2011/9/28 21:38:26
corona forums © 2003-2011