Random Wrinkles with Cocos2D-Swift

Cocos2D-Swift is open source, so if you find an issue with it you can look at the engine code and you have a chance of fixing it. But be aware that the more you change the higher the maintenance cost. Cocos2D is frequently updated, so you have to be careful to redo/merge any fixes you've made to the engine on every update.

Not only is Cocos2D frequently updating, but it's forked into several versions (Cocos2D-x, Cocos2D-JS, Cocos2D (Python), Cocos2D-Swift, Cocos2D-XNA for example). This is great, but there's a downside every developer hits. It's hard for the internet to document the software in all it's variations, how to use it's features, the pitfalls, workarounds, and best practices. As a user, it's harder to find relevant information about your favourite flavour of Cocos2D as any reference to it on the web may well be incompatible.

I've had to delve around in the internals of Cocos2D to fix a few issues I found along the way while making Shift Escape, but I've minimised the changes - one-liners usually.

These are the random wrinkles that just popped up unexpectedly during development using Cocos2D v3.3 (SpriteBuilder v1.3.6):

1. CCLabelTTF

I wanted to use a custom TTF font for Shift Escape, but this caused the game to crash on iOS 6. Turns out the logic is the wrong way around in function:

+(NSString*) registerCustomTTF:(NSString *)fontFile

I changed the following line to be != (does-not-equal) rather than == (equals):

BOOL needsCGFontFailback = [[[UIDevice currentDevice] systemVersion] compare:@"7.0" options:NSNumericSearch] == NSOrderedAscending;

That said, the smarter answer here is: don't bother spending time supporting iOS 6 any more. It's a tiny percentage of users these days.

2. CCDrawNode

CCDrawNode started as a simple debugging facility to draw lines and polygons, but has become so useful it has been expanded and solidified a bit. However some immaturity remains. When drawing a polygon, the code internally 'extrudes' (moves) the vertices supplied before drawing them. This makes it very difficult to align polygons, for example to properly butt up against each other, and (worse) it means that long thin polygons are rendered incorrectly, corrupting the visuals. I needed a function that draws the polygon properly with vertices I specify, so I changed function:

-(void)drawPolyWithVerts:(const CGPoint *)_verts count:(NSUInteger)count fillColor:(CCColor*)fill borderWidth:(CGFloat)width borderColor:(CCColor*)line;

In particular (for minimal change) I just commented out one line:

extrude[i] = (struct ExtrudeVerts){offset, n2};

3. CCTableView

When archiving Shift Escape for release, the validation step came back warning about a function:

- (float) tableView:(CCTableView*)tableView heightForRowAtIndex:(NSUInteger) index;

This conflicted with the naming of a similar iOS function. To avoid the validation warning, I renamed it to ccTableView, and fixed up the references to it (changing CCTableView.m/.h), as suggested here.

4. Content Scale Factor

This didn't work for me as expected for iPhone 6 and iPhone 6+ out of the box. Nodes were not scaled as expected. It turns out Cocos2D has a global scale factor that can be manually set. I ended up setting specific values for these devices in the AppDelegate on startup. To detect which device was running, I used the macros here.

if( IS_IPHONE_6 )
        [[CCDirector sharedDirector] setContentScaleFactor: 2.5f];

5. Additionally

This is not a bug, but I found the following to be a useful addition to allow for changing the Anchor Point of a node without changing position on screen: CCNode+AnchorPos.m/h

SpriteBuilder and Cocos2D

I've been using SpriteBuilder for several months while developing Shift Escape and - let's cut straight to the chase - it's good. It's easy to use, efficient, and capable. SpriteBuilder is a free Mac App Store application providing an environment for authoring 2D games for iOS and Android. I'm more familiar with the iOS side so I'll concentrate on that, but note that Android development is only supported via a plugin where some features are provided free, others are paid for.

SpriteBuilder doesn't do everything - in order to create a game, Objective C and/or Swift programming skills are required. To aid the programmer, SpriteBuilder includes and uses the popular open source Cocos2D library, and this is now the recommended way to get and use Cocos2D. I should clarify I'm talking about Cocos2D-Swift which is for writing games in Objective-C and/or Swift. Other language forks are available but they don't integrate with SpriteBuilder.

SpriteBuilder is used to author and arrange 'nodes' (sprites, buttons, text, etc) hierarchically within scenes, author animations, apply physics, manage the game's assets (sprite sheets, audio etc), and link properties to relevant Objective C classes in XCode. SpriteBuilder helpfully creates the required XCode project at the start with all the relevant boilerplate code and the Cocos2D-Swift library code ready to go. The developer adds game specific code from there.

The workflow works smoothly. When you update something in SpriteBuilder, you press the publish button, which incrementally builds any changed assets into game ready formats for each platform. Then you switch to XCode and compile and run from there.

The hierarchy of nodes concept is strong. Each node has a name, position, rotation, scale, skew, anchor point, and content size. As a developer, obviously you can group together several nodes as children of a single parent in SpriteBuilder and they will all move together when the parent moves. You can also do the same thing in code to create a custom reusable node type. If for example you want a button that represents a single level in your game (as part of a level selection scene for example), then this can be assembled from several child nodes. It may have a button, an icon, text, a gold star when you complete it, or a padlock if it's not yet been unlocked. All these elements can be created in code as child nodes of a parent class that derives from the base CCNode type.

The UI lets you see how the game will look on different sized devices from the iPhone4s to the iPhone 6+. Nodes can be positioned relative to a corner of the screen for instance, so you can reduce the amount of code you need to keep the game looking good across all devices. One limitation is that you must choose whether your game will run in portrait or landscape - you can't support both orientations in the same game.

Unreal's Visual Scripting Blueprints

Unreal's Visual Scripting Blueprints

In the future, I'd like to see some Visual Scripting support (e.g. like Blueprints in Unreal Engine) added. Visual Scripting defines the behaviour of nodes without programming, making it quicker and more accessible to a larger audience of designers and other non-programmers.