This guide is for those of you who want to create a hi-res game for use on the RetinaDisplay, while also enabling you to support early iPhones/iPods with low-res displays.
This guide is valid for cocos2d v0.99.5-rc0 or newer and not valid for previous cocos2d versions.
The entire cocos2d API was converted to Points. Previous versions were using Pixels.
cocos2d v0.99.4 has RetinaDisplay support, however it required you to use two different sets of positions depending on the device , since the API was in Pixels.
For example to position a sprite at the top-right corner, you had to do:
// in v0.99.4 if( iPhone4isUsed) sprite.position = ccp(960,640); else sprite.position = ccp(480,320);
But in v0.99.5-rc0 (and newer) the only thing that you have to do is:
// v0.99.5 sprite.position = ccp(480,320);
What is a pixel ? A pixel according to wikipedia is this: http://en.wikipedia.org/wiki/Pixel.
The difference between Pixels and Points is that the logical coordinate space is measured in Points, while the device coordinate space is measured in Pixels.
Example:
| Device | Points | Pixels |
|---|---|---|
| iPhone 3GS or older [1] | 480×320 | 480×320 |
| iPhone4 in LowRes mode [2] | 480×320 | 480×320 |
| iPhone4 in HighRes mode [2] | 480×320 | 960×640 |
| iPad 1 and 2 | 1024×768 | 1024×768 |
| iPad 3 | 1024×768 | 2048×1536 |
| Mac | W x H | W x H |
[1]: It is also valid for iPod Touch 3rd generation and older devices
[2]: It is also valid for iPod Touch 4th generation
When HighRes mode is enabled on the iPhone4 then 1 Point == 4 pixels (2×2 pixels), otherwise 1 Point == 1 Pixel.
As mentioned previously, in v0.99.5 the API is in points, this means that:
// director CCDirector * director [CCDirector sharedDirector]; CGSize sizeA = [director winSize]; // is in Points CGSize sizeB = [director winSizeInPixels]; // in Pixels CGSize sizeA = [director displaySize]; // is in Points CGSize sizeB = [director displaySizeInPixels]; // in Pixels // Node CCNode *node = [...]; CGPoint posA = [node position]; // is in Points CGPoint posB = [node positionInPixels]; // is in Pixels CGSize sizeA = [node contentSize]; // is in points CGSize sizeB = [node contentSizeInPixels]; // is in pixels CGRect rectA = [node boundingBox]; // is in Points CGSize rectB = [node boundingBoxInPixels]; // is in pixels // Sprite CCSprite *sprite = [...]; CGRect rectA = [sprite rect]; CGRect rectB = [sprite rectInPixels];
This is also valid for the setters. eg:
[sprite setPosition:ccp(x,y)]; // in Points [sprite setPositionInPixels:(x,y)] // in Pixels
etc… The methods are ONLY in pixels if the methods or properties end with the “InPixels” suffix. If they don't have that suffix it means that they use Points.
95% of the time you will want to use the Point API, but there are special cases when you might need to use the Pixel API.
Some of cocos2d's complex objects use the Pixel API. eg: `CCSprite`, `CCTMXLayer`, `CCLabelBMFont`.
So, you might need to use the Pixel API if you are developing a complex object, specially if you need to parse a data file that has values in pixels.
Most likely, you'll want to have low-res images on iPhone 3GS and older devices, and high-res images on iPhone 4.
Apple uses the ”@2x” suffix, but cocos2d doesn't use that extension because of some incompatibilities. Instead, cocos2d has its own suffix: ”-hd”.
If you want to use a different suffix entirely, you can specify your own by editing the ccConfig.h file.
// Modify it to use your own suffix #define CC_RETINA_DISPLAY_FILENAME_SUFFIX @"-hd"
WARNING: It is NOT recommend to use the ”@2x” suffix. Apple treats those images in a special way which might cause bugs in your cocos2d application.
The only exception is the “Default@2x.png” image. Since cocos2d is not loaded at that time, you can use that image in order to have a High Res splash image.
Each file opened by cocos2d (image file, config file, sprite sheet, etc…) is opened using the CCFileUtils class.
When RetinaDisplay is enabled, this class will try to open the ”-hd” file instead. If that file doesn't exist, it will open the originally requested file.
Example: If you try to open the file “sprite.png” when RetinaDisplay mode is enabled, then the following will happen:
Same example, but trying to open the file “sprites-hd.plist”
As you can see, the ”-hd” suffix is valid for any file: Images (.png, .gif, .bmp, etc), TMX files (.tmx, .png), BMFont files (.fnt, .png), Sprite sheets (.plist, .png).
cocos2d, as of v0.99.5-rc0, doesn't support any other suffix, like an ”-ipad” suffix, but it will support it in the near future.
NOTE: If you have retina mode enabled, the compiler will require two graphic sources. The image with the -hd suffix (image-hd.png) and the regular file (image.png).
You should enable RetinaDisplay mode ONLY if you want to use HighRes images on an iPhone4. Remember that an iPhone4 also works in “low res” mode.
// Add this code in your Application Delegate, right after initializing the director // Director Initialization [director setOpenGLView:glView]; // Enables High Res mode (Retina Display) on iPhone 4 and maintains low res on all other devices if( ! [director enableRetinaDisplay:YES] ) CCLOG(@"Retina Display Not supported");
position is in pointspositionInPixels is in pixelscontentSize is in pointscotentSizeInPixels is in pixelsboundingBox is in pointsboundingBoxInPixels is in pixelsThe API is in Points:
+(id) labelWithString:(NSString*) string charMapFile: (NSString*) charmapfile itemWidth:(int)w itemHeight:(int)h startCharMap:(char)c;It means that the width and height are in points. So, if you call this method when RetinaDisplay mode is enabled, you MUST have a -hd image.
Quick way to create a “pseudo” high res image by using ImageMagick:
$ convert fps_label.png -scale 200% fps_label-hd.png
WARNING: You should NOT scale up a raster image. You won't gain quality. The above given example is a quick way to create an ”-hd” image so that you can test your game quickly.
The API is in points, so if you want to have both a low res and high res version, you have to create a 2x file by using Hiero (or your favorite BMFont editor).
Example: If have a low res BMFont called times32.fnt (and times32.png) (Times New Roman font with a font size of 32), then you'll have to:
This will create REAL HighRes images.
The API is in Points, so if you want to create a HighRes version you'll have to:
tilewidth, tileheight, spacing and margin.Sample of map.tmx:
<map version="1.0" orientation="orthogonal" width="10" height="10" tilewidth="32" tileheight="32"> <tileset firstgid="1" name="Desert" tilewidth="32" tileheight="32" spacing="1" margin="1"> <image source="tileset.png"/> </tileset>
Sample of map-hd.tmx:
<map version="1.0" orientation="orthogonal" width="10" height="10" tilewidth="64" tileheight="64"> <tileset firstgid="1" name="Desert" tilewidth="64" tileheight="64" spacing="2" margin="2"> <image source="tileset-hd.png"/> </tileset>
Quick way to create a “pseudo” high res image by using ImageMagick:
$ convert tileset.png -scale 200% tileset-hd.png
WARNING: You should NOT scale up a raster image. You won't gain quality. The above given example is a quick way to create an ”-hd” image so that you can test your game quickly.
You should generate the files (.plist and .png) again, this time using the high res sprites. Example: If you have generated your spritesheet.plist and spritesheet.pngfiles using the these 4 low-res images:
Then you'll have to create an HD version of those 4 images. But you should NOT rename them. Instead, what you should do is to place the HD files in another directory. eg:
$ mkdir hd_sprites $ convert sprite1.png -scale 200% hd_sprites/sprite1.png $ convert sprite2.png -scale 200% hd_sprites/sprite2.png $ convert sprite3.png -scale 200% hd_sprites/sprite3.png $ convert sprite4.png -scale 200% hd_sprites/sprite4.png
Then you will have to generate the spritesheet-hd.plist and spritesheet-hd.png files from the sprites that are located in the “hd_sprites” subdirectory.
WARNING: You should NOT scale up a raster image. You won't gain quality. The above given example is a quick way to create an ”-hd” image so that you can test your game quickly.
The sprite API is in points:
-(id) initWithFile:(NSString*)filename rect:(CGRect)rect;rect is in pointsrectInPixels is in pixelsSo, if you are going to use this method, be sure to have an ”-hd” image, otherwise your sprite won't look good.
Quick way to create a “pseudo” high res image by using ImageMagick:
$ convert spritesheet.png -scale 200% spritesheet-hd.png
WARNING: You should NOT scale up a raster image. You won't gain quality. The above example is a quick way to create an ”-hd” image so that you can test your game.