Cocos2D Book Update: Progress Report

On May 29, 2011, in book, cocos2d, by Steffen Itterheim

It’s coming along great!

I completed the revisions on Chapter 1 through 5. The entire source code is now updated to use cocos2d-iphone v1.0.0 rc2. To make future code updates easier I also wrote a script that allows me to copy a newer cocos2d version to all projects, which essentially does Steps 1 & 2 described in the Updating Cocos2D in an Existing Project tutorial.

Most Notable Changes

Chapter 4 now includes a description of Glyph Designer for making Bitmap Fonts, and only mentions Hiero on the side. Glyph Designer is the better tool hands down.

Chapter 5 has seen a revision of the paragraph that explains subclassing from NSObject. I think I went too far off course here and subclassing from CCNode will make a lot of things easier while still giving the same benefits regarding class composition.

In Chapter 6 I decided to replace all descriptions of Zwoptex with TexturePacker as the preferred tool for making texture atlases.

For a while it looked like Zwoptex and TexturePacker would be competing on the same level. But recently Andreas Löw (TexturePacker & PhysicsEditor) made the move to work full-time on his tools, whereas Robert Payne is busy with a full-time job. I think the prospects are looking much better for TexturePacker now, and it is already leading in terms of features and update frequency.

That’s it for now.

Scheduling multiple update selectors

On March 2, 2011, in cocos2d, Programming, by Steffen Itterheim

I have a seemingly simple requirement for my project: each node should have preUpdate and postUpdate methods in addition to the regular update method. Preprocessing and postprocessing before and after all entities have run their “update” logic is a common requirement in game development. Sometimes called the setup stage before processing all entities in the world, and the finalize stage to complete the current game step and possibly resolve collisions or check any win, lose or achievements conditions.

Of course there are alternative and some may argue “better” implementations, after all an experienced game dev might argue that using pre and post update methods are merely signs of a badly designed game update loop (the jury is out on that one). However beginning game developers definitely understand this concept much better and every game-making tool I know implements pre and post updates, so it has its validity. Plus I find it more convenient than “outsourcing” some logic to a central game loop.

On the other hand it’s also bad practice to rely on one node’s update method to be called before or after all others. Especially once you get to prioritizing update method calls among various groups of nodes it’s just going to get you into trouble. If you set the priority wrong just once you can introduce very subtle issues that’ll be hard to track down. Think of some objects not colliding with the player, or some monsters crashing when you shoot at them with a specific weapon. Scheduled methods should never rely on the order they are called for various entities.

Not so easy …

It turns out the system in Cocos2D only allows one update method per node. That means for each node you can only have one update selector, and via the priority parameter you can only control when its update method is called relative to all other nodes’ update method. In that way you can at least ensure that the player’s update method is always called first, or last, depending on your requirements. But it’s bad programming practice to do so.

I thought, why not just schedule a “regular” selector with CCScheduler? Well, they don’t have a priority, and they are always called after any update method, so you could never schedule a “before update” method this way. And those scheduled selectors aren’t meant to be used for selectors that are called every frame due to the additional processing overhead (eg allocating, updating and releasing the CCTimer object, and comparing & updating time elapsed every frame).

So I had to write a class called ScheduleMultiUpdate which creates proxy instances, registers them with CCScheduler to receive an update message of their own, and then they forward that message to the actual node implementing the special update selector. By using the priority you can define if the selector is called before or after the regular update by using a negative (before) respectively a positive priority (after, must be 1 or greater).

Example Code

Here’s an example usage scheduling the beforeUpdate and afterUpdate selectors to be called before and after the regular update method.

[cc lang=”ObjC” height=”550″]
// in interface (.h)
KKScheduleMultiUpdate* multiUpdate;

// in implementation (.m)
-(void) scheduleUpdateMethods
{
multiUpdate = [[KKScheduleMultiUpdate alloc] initWithNode:self];
[multiUpdate scheduleUpdateSelector:@selector(beforeUpdate:) priority:-1];
[self scheduleUpdateWithPriority:priority];
[multiUpdate scheduleUpdateSelector:@selector(afterUpdate:) priority:1];
}

// this has to be cleanup because CCScheduler retains scheduled targets
// we have to give KKScheduleMultiUpdate a chance to unschedule its selectors or it won’t be deallocated
-(void) cleanup
{
[multiUpdate release];
multiUpdate = nil;
[super cleanup];
}

-(void) beforeUpdate:(ccTime)delta
{
}
-(void) update:(ccTime)delta
{
}
-(void) afterUpdate:(ccTime)delta
{
}
[/cc]

Here’s the actual implementation of KKScheduleMultiUpdate and its proxy class. Notice how the KKScheduleMultiUpdate simply retains a list of proxies and creates new ones, while the proxy class registers itself with CCScheduler to schedule its own update method based on the given priority, and then forwards the message to the baseNode. There’s currently no way to unschedule an update selector, but it should be fairly easy to add if you ever need to unschedule an update method while the game is running (I’d rather just use a bool and skip update).

@interface

[cc lang=”ObjC” height=”500″]
#import “cocos2d.h”

/** Allows you to schedule multiple update methods per node. */
@interface KKScheduleMultiUpdate : NSObject
{
CCNode* baseNode;
CCArray* updateProxies;
}

-(id) initWithNode:(CCNode*)node;
-(void) scheduleUpdateSelector:(SEL)selector priority:(int)priority;

@end

/** Since there can be only one update selector scheduled per instance, this proxy will implement
that update method and forward the message to the desired selector. */
@interface KKScheduleMultiUpdateProxy : NSObject
{
id target;
SEL selector;
TICK_IMP impMethod;
}

-(id) initWithTarget:(id)target selector:(SEL)selector priority:(int)priority;

@end
[/cc]

@implementation

[cc lang=”ObjC” height=”500″]
#import “KKScheduleMultiUpdate.h”

@implementation KKScheduleMultiUpdate

-(id) initWithNode:(CCNode*)node
{
if ((self = [super init]))
{
NSAssert(node != nil, @”%@ %@ - node is nil!”, NSStringFromClass([self class]), NSStringFromSelector(_cmd));
baseNode = [node retain];

updateProxies = [[CCArray alloc] initWithCapacity:1];
}
return self;
}

-(void) dealloc
{
CCLOG(@”%@ %@”, NSStringFromSelector(_cmd), self);

[baseNode release];
baseNode = nil;

// must do a cleanup to unschedule CCSelector, this is because CCScheduler retains scheduled targets
[updateProxies makeObjectsPerformSelector:@selector(cleanup)];
[updateProxies release];
updateProxies = nil;

NSAssert([self retainCount] == 1, @”%@ %@ - retainCount on cleanup should be 1 but is %i”, NSStringFromClass([self class]), NSStringFromSelector(_cmd), [self retainCount]);

[super dealloc];
}

-(void) scheduleUpdateSelector:(SEL)selector priority:(int)priority
{
NSAssert([baseNode respondsToSelector:selector], @”%@ %@ - node %@ does not respond to selector”, NSStringFromClass([self class]), NSStringFromSelector(_cmd), baseNode);
// TODO: might want to check here if the selector happens to be already scheduled

KKScheduleMultiUpdateProxy* proxy = [[KKScheduleMultiUpdateProxy alloc] initWithTarget:baseNode selector:selector priority:priority];
[updateProxies addObject:proxy];
[proxy release];
}

@end

@implementation KKScheduleMultiUpdateProxy

-(id) initWithTarget:(id)target_ selector:(SEL)selector_ priority:(int)priority
{
if ((self = [super init]))
{
NSAssert(target_ != nil, @”target is nil”);
NSAssert(selector_ != nil, @”selector is nil”);

target = target_; // weak ref
selector = selector_; // weak ref

impMethod = (TICK_IMP)[target methodForSelector:selector];
NSAssert(impMethod != nil, @”selector is not an instance method of target %@”, target);

[[CCScheduler sharedScheduler] scheduleUpdateForTarget:self priority:priority paused:NO];
}
return self;
}

-(void) cleanup
{
CCLOG(@”%@ %@”, NSStringFromSelector(_cmd), self);

[[CCScheduler sharedScheduler] unscheduleUpdateForTarget:self];
impMethod = nil;

NSAssert([self retainCount] == 1, @”%@ %@ - retainCount after cleanup should be 1 but is %i”, NSStringFromClass([self class]), NSStringFromSelector(_cmd), [self retainCount]);
}

-(void) dealloc
{
CCLOG(@”%@ %@”, NSStringFromSelector(_cmd), self);

[super dealloc];
}

-(void) update:(ccTime)delta
{
impMethod(target, selector, delta);
}

@end
[/cc]

As always, you’re free to use this code. I release it under the MIT License. You do not need to include a copyright notice, but I’d appreciate any mention or backlink to this website.

It’s all in the numbers …

On September 29, 2010, in cocos2d, by Steffen Itterheim

I assume we’re all eagerly awaiting for cocos2 v1.0 and to be given a download link to click on. The year 2010 started so promising, with v0.9 going through beta during end of 2009 and beginning of 2010. This v0.9 never came out of beta but was re-labelled as v0.99 and released as final version in February 2010 (if I remember correctly, it was either due to the amount of changes or the closeness to v1.0 that it was labelled v0.99). At this point I was thinking that by the end of spring, at the very least, we’d have a final v1.0 of cocos2d.

But 8 months later we’ve just seen v0.99.5 beta 3 release but no v1.0 in sight yet. I’m growing impatient. I’m wondering what the holdup is? The version labels seem to grow longer and longer, as if the labels were trying to prove the point that you can still have an infinity between 0.99 and 1.0 - if you only add enough digits and other stuff after the decimal sign this could go on forever.

So, please, for the love of god, just label it v1.0 already and lets get on with regular 0.1 steps from then on!

Just out of curiosity, I made a quick spreadsheet and hacked the average time between updates in, and it told me that according to this year’s release schedule v0.99.7 will be released on December 24th, 2010 and v1.0 sometime May next year. If version number updates continued at this rate, don’t hold your breath for v1.1 before the second half of 2012.

It’s just a silly estimation based on average days between new versions and their respective version numbers, so don’t take this seriously, or the wrong way. I’m merely growing annoyed and concerned how cocos2d progress has not been reflected in the version numbers in all of 2010, and how version numbers have grown out of proportion and anything I can relate to. Not that it’s any of my concern, but I do believe that doesn’t do cocos2d a good service to continue to label new versions like “0.99.5 beta 3”, and it certainly doesn’t help to portray it in the right light if you compare it to the progress other engines have made over the same period of time - if only in version numbers.

It’s almost as if going “v1.0” meant that cocos2d would be losing its virginity, and that being a life-changing event it shouldn’t happen without about a year of dating, right?

Right?

Well, for what it’s worth, I would suggest taking on the pretty-much-standard versioning style: major version dot minor version dot bugfix/hotfix (non-breaking) releases dot build number. Then go back to the regular release cycle with about two months for each 0.1 step, regardless of what the major number is.

I mean, a major version number change should still introduce something awesome, or useful, or practical, or helpful - in that case just skip the remaining 0.5 or so ahead and bump the major version right away. Personally, if HD support is in and points instead of pixels (what a concept) then that would be it for me. That would be a good v1.0. Get it done and all the bugs fixed, and label it v1.0 so we can all start looking forward to more reasonably labelled releases. Really, it just doesn’t matter that much if you change the first frickin’ number from 0 to 1.

Personally, I would have preferred if cocos2d were now closing in on v2.0. That would be about the version we might be at if the rate from 0.5 through 0.8 had continued at the past update rate. And a v2.0 would be absolutely justified for cocos2d, and I suppose a lot of people would feel much better working with a v2.0 than the current unstable 0.99.5 beta 3.

I hope we won’t see this happening again when cocos2d tries to get pregnant, and labels itself something like “v1.98.7 beta 6 final alpha” around that time to reflect the process, or progress, or lack thereof, or hormone levels, or morning sickness intensity, or whatever.

It’s a frickin’ version number, that’s all that it is!

And it needs some serious increasing to catch up with its level of maturity. Think about what that means to how cocos2d is first perceived by an outsider.

Heck, Unity is now at v3.0, SIO2 is racing towards v2.0, Shiva is close to v1.9 and even the slow-to-release-updates iTorque has gotten to v1.4 by now. Cocos2d is still afraid to go even v1.0 and it’s a shame, because it hurts its reputation, it doesn’t do itself justice, it’s likely to be perceived as being behind the pack and it doesn’t look good in terms of actual progress being made, regardless of the actual work that’s been done this year.

Tagged with:  

Xcode Project Tutorial Updates: Box2d & Template

On May 12, 2010, in Announcements, by Steffen Itterheim

If you followed my Xcode Project Tutorial or received it after signing up for my Newsletter you may have noticed that it would not compile if you added #import “box2d.h” to any of your classes. I investigated and thanks to your comments the problem was easy to fix. I wrote a Tutorial lesson detailing box2d integration issues and how to solve them.

In addition, Tim Soliday who blogs at FatFingerStudios.com went through the effort of creating a “real” Xcode Template from my Tutorial project. By “real” i mean an Xcode Template that will be added to Xcode’s “File -> New Project” list of applications so that you can choose to start with a “cocos2d Application from there. This has also been requested by readers. I added another Tutorial lesson which describes how to install Tim’s Xcode Template.

I will add Tim’s Xcode Template to the Newsletter welcome mail in a couple minutes so new Newsletter subscribers will receive it automatically! If you have already signed up for my Newsletter you’ll have it in your inbox shortly, you do not have to sign up again!

The new Projectfiles you’ll receive also contain the box2d fixes and include my free source code collection and a number of other changes. Most notably the addition of License files and folder structure that go along with it which help me and my customers to differentiate between my base source code that is only licensed to the customer vs. source code that is later fully owned by my customers. Feel free to disregard or delete these License files if you have no use for them.

Tagged with: