This is the second of two posts about supporting high-res graphics in iOS games. The first post was a general overview called Retinafy Your Game, and this post is a more specific look at how I implemented high-res graphics in Cocos2D. I’d recommend reading the first post before you read this post, so that you have an idea of some things to consider when adding Retina support to your game.
What did you do?
Nothing too crazy. The point of this technique was to change Cocos2D to support Retina graphics without having to change any of the actual game logic or code. Once you’ve made the changes to Cocos2D, all you have to do is supply high-res images. This also gives you nice looking high-res graphics on the iPad in 2x zoom mode without having to make your game universal.
Warning: Cocos2D is in a constant state of change. I used the newest develop branch to do these changes, but as long as you’re using 0.99.4 or above you should be able to get it to work. It’s possible to make it to work with even earlier versions, but it’ll take a bit more effort. There’s a good chance you’ll run into some issues while putting this into your own game, so feel free post a comment, email me, or message me on Twitter. There’s also a thread discussing this on the Cocos2D forum.
Ok, but what did you actually do?
I won’t go through every change line-by-line, instead, you can see the diffs for my changes on GitHub. I removed the Mac things from my branch because they have nothing to do with Retina support. The gist of the changes is this: we scale the root of the display tree by 2x when we’re in high-res mode, so that it’s double the size. Whenever we grab a texture in CCSprite when we’re in high-res mode, we double the size of the rect we’re grabbing. That’s about it, aside from a couple extra fixes to make point particles and CCRenderTexture work properly, as well as some changes in the code that converts between OpenGL and UIKit points.
How do I use it?
Either grab the code from GitHub, or go through the GitHub changes line-by-line and add them to your own Cocos2D files(there really aren’t that many changes, so this is probably the easiest option.). Once you’ve done that, you have to start your CCDirector a fairly specific way in your AppDelegate. This is how I did it:
//
//
_window = [[UIWindow alloc] initWithFrame:CGRectMake(0,0,320,480)];
[_window setUserInteractionEnabled:YES];
[_window setMultipleTouchEnabled:YES];
BOOL isHD = NO;
if([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) //iPad and iPhone 4
{
if([[UIScreen mainScreen] scale] == 2)
{
isHD = YES;
}
}
if([[[UIDevice currentDevice] model] rangeOfString:@"iPad"].location != NSNotFound)
{
isHD = YES;
}
if( ! [CCDirector setDirectorType:kCCDirectorTypeDisplayLink] )
[CCDirector setDirectorType:kCCDirectorTypeNSTimer];
CCDirector *director = [CCDirector sharedDirector];
[director setDeviceOrientation:kCCDeviceOrientationPortrait];
[director setDisplayFPS:NO];
[director setAnimationInterval:1.0/60];
EAGLView *glView = [EAGLView viewWithFrame:CGRectMake(0.0, 0.0, 320, 480)
pixelFormat:kEAGLColorFormatRGBA8
depthFormat:0 /* GL_DEPTH_COMPONENT24_OES */
preserveBackbuffer:NO];
if(isHD)
{
[director setContentScaleFactor:2.0];
}
[director setOpenGLView:glView];
[director setProjection:kCCDirectorProjection2D];
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];
[_window addSubview:glView];
[_window makeKeyAndVisible];
[[CCDirector sharedDirector] runWithScene:[DemoSceneA node]];
//
//
My changes only work for 2D projection mode, but I’m sure someone who knows OpenGL better than me could get it to work in 3D projection mode as well.
The one last piece of code is a simple macro that’ll load images with an HD suffix when you’re high-res mode (eg. demoAtlas.png becomes demoAtlasHD.png).
// // #define GetPNGFileName(__imageName__) (([[CCDirector sharedDirector] contentScaleFactor] == 2) ? [NSString stringWithFormat:@"%@HD.png",__imageName__] : [NSString stringWithFormat:@"%@.png",__imageName__]) //Usage CCSprite *someSprite = [CCSprite spriteWithFile:GetPNGFileName(@"someSpriteName")]; // //
That’s about it. I created a full demo project which demostrates the technique in action. I tested it on an iPod Touch, iPhone 4, and iPad, and it works great on all of them. I also tested it in all four orientations. Please let me know if you run into any issues with it. Get it here: http://struct.ca/files/hires/HighResDemoProject.zip
This blog is part of a group of awesome blogs that make up iDevBlogADay. If you’re an iOS developer you should definitely check it out. You’ll get at least two fresh blog posts per day. Delicious.




