you're reading...


How to Fix Your Five Year Old Cocos2D Game

The recent Flappy BirYellow thingd craze reminds me of our own arcade game, Air Kill. Developed back in 2009 originally on the iPod touch, AirKill seriously needs updating – at least to bring support to the newer iOS devices that came out since then and remove some code rot that came along. Ever since AirKill was updated, Apple brought in two new screen sizes (iPhone 5 and the iPad) and retina display. Some 3rd party libraries also became outdated and may even be discontinued – the most notable one was OpenFeint that was shut down in 2012.

So I thought maybe it’s a good time to bring new life to AirKill. Bring in the iPad and iPhone 5, get rid of OpenFeint, and replace it with Game Center. Maybe I can learn a thing or two from Flappy Bird’s fleeting success.

Then I pulled up my old dusty hard drive and gotten AirKill’s source code out. Fortunately everything was self contain and the project still ran pretty well on the simulator without any changes. Imagine the changes from Xcode 3.x to Xcode 5.x and iOS 3.x to iOS 7.x but the source code still works pretty much unchanged – kudos to Apple for keeping backward compatibility even on it’s youngest platform. Furthermore it turned out to be quite useful to have all of the project’s dependencies within one folder and not have it scattered all over the place (I’m looking at you, git modules!).

After that brief moment of joy, the first order of business was to upgrade Cocos2D – the game framework that Air Kill is built on. I downloaded the latest stable version, which was 3.0.0 RC2 at the time, and replaced AirKill’s copy with that one. Then the compiler started yelling all sorts of things to me. Unlike Apple, it looks like Cocos2D folks are less interested with backward compatibility. There were plenty of changes from class names, selector names, typedefs, and a whole bunch of other stuff. It’s not just 1:1 name changes – some classes were removed and others behaved differently.

Well, maybe they’re not all to blame. After all, I was migrating Cocos2D from version 0.8 to 3.0. Furthermore looking at some of the source code headers, it looks like the framework has changed hands several times. From the original author Ricardo Quesada to Zynga and currently it’s a band of folks who call themselves “Cocos2D Authors”. I guess that’s normal – and perhaps expected – when it comes to open source projects. Which reminds me of all the Linuxes back in the late 1990’s – but that’s another story.

I’ve tried to look for a migration guide but the best one I could find talked about upgrading from Cocos2D 2.x to 3.0. It was somewhat helpful, but I’m largely on my own in this. Luckily I took notes as I was fixing my code and you can save some time by learning from my experience.

Equivalents At a Glance

Here are some class names, method names, and other constructs that are somewhat equivalent between version 0.8 and 3.0.  Some are direct class-to-class replacements, some other new classes merge a few functionalities from the old ones, whereas others are not exactly equivalents but close enough. Be sure to lookup Cocos2D’s documentation as you’re applying these changes to your game.

Cocos2D 0.8 Cocos2D 3.0
Director CCDirector
Layer CCNode
ColorLayer CCNodeColor
Sprite CCSprite
ccTime CCTime
Label CCLabelTTF
RotateTo CCActionRotateTo
Action CCAction
MoveTo CCActionMoveTo
ScaleTo CCActionScaleTo
Sequence CCActionSequence
DelayTime CCActionDelay
TextureNode CCSprite
TextureMgr CCTextureCache
Texture2D CCTexture
IntervalAction CCActionInterval
[Sprite initWithFile:...] [CCSprite initWithImageNamed: ...]
[Director winSize] [CCDirector viewSize]
[Director convertCoordinate] [CCDirector convertToGL]
[Director setDisplayFPS] CCDirector.displayStats
[Layer isTouchEnabled] CCResponder.userInteractionEnabled
[TextureMgr cache] [CCTextureCache sharedTextureCache]
opacity_ = x _displayColor.a = x / 255
_rotation self.rotation
position_ _position
transformAnchor anchorPoint
[Layer isTouchEnabled] [CCResponder userInteractionEnabled]
ccTouchesBegan:(NSSet*) touches withEvent:(UIEvent*) evt touchBegan:(UITouch*) touch withEvent:(UIEvent*) evt

Director Differences

On iOS, CCDirector is a full fledged view controller now – thus you can simply show it as the initial view controller or show it as a modal view controller. However the director being a view controller could cause a slight complication if you currently attach the director to a pre-existing view controller.

In other words, you used the following sequence to setup your main director from a view controller…

    Director* director = [Director sharedDirector];
    [director setPixelFormat:kRGBA8];
    [director setLandscape:YES];
#ifndef NDEBUG  
    [director setDisplayFPS:YES];
    [director attachInView:self.view.window];

Now you should take slightly different steps in version 3.0.0. Note that you’ll probably need to create the director’s primary view which should be a subclass of CCGLView

    CCGLView *glView = [CCGLView
    CCDirector* director = [CCDirector sharedDirector];
#ifndef NDEBUG  
    [director setDisplayStats:YES];
    [self presentViewController:director animated:NO completion:nil];

What’s New with Nodes

Now you need to use at least a CCSprite instead of just CCNode to respond to touch events in your game objects. I haven’t dig deep into the reason why, but my guess is that plain CCNode doesn’t have any dimensions. Why I came to this conclusion? Formerly I used a Layer subclass as the root node of my game objects that are capable of handling touch. These classes are really blank containers that houses a few sprites in them. At first I mapped Layer to CCNode for those, but found out that it wasn’t accepting any touches. It finally worked after I “pull up” the largest sprite and made it the root game object nodes.

Opacity is now a floating-point value that ranges 0..1 instead of a simple byte ranging 0..255. Instead of saying opacity_ = 200 you now say _displayColor.a = 200.0f / 255 – hopefully a straightforward change in your code.

Any Other Stuff

Moving to automatic reference counting (ARC) was pretty much straightforward after I got the game working on the new version of Cocos2D. Initially I tried the other way around – migrating to ARC before upgrading Cocos2D – and it didn’t work well since there’s plenty of Cocos2D code that aren’t ARC compatible, even after re-written with Xcode’s ARC migration tool.

So I hope you find this post useful. Until next time, take care!

Do you enjoy this post? Enter your e-mail address below to receive articles like this one in your mailbox.
  • Great write-up, I’m sure this will be helpful to many people! Regarding backwards compatibility, we keep things backwards compatible in-between major versions e.g. any 3.x update will be backwards compatible, but version 4.x may not be a 100% compatible with 3.x. I guess lots of things have happened since the 0.x days. :)

Free Updates!

Learn how to grow your indie business while keeping your day job.



Keep updated!

Don't miss out on new articles!