Top
Navigation
I'm talking about
Last bookmarks...
jeudi
04juin2009

iPhone SDK gotchas #2

I was wondering why the Wifi was systematically shut down after a while in my game (it's a multiplayer game).

Well, another "gotcha": http://stackoverflow.com/questions/761140/wifi-connection-is-dropped-after-user-inactivity-period

Basically, you must set UIRequiresPersistentWiFi key in the Info.plist to TRUE, otherwise, after 30 minutes, the wifi will be shut down no matter what.

Thanks to the wisdom of the internet.

lundi
01juin2009

BitmapFontAtlas performance optimizations

A very exciting new feature from cocos2D 0.8 is the addition of BitmapFontAtlas support. A BitmapFontAtlas is a combination of 2 files: a definition file (.fnt) and a texture file (.png). Contrary to the LabelAtlas, the font is no longer with fixed-width, and it looks much much better. It's also easier to manage and produce using various tools like Hiero Font Tool

So because It looks so good, I went a little crazy and added a lot of them in my game. Unfortunatly, that's how I discovered a nasty performance issue with it, as each new instance would parse the font definition file, taking a few very noticable ms (look like hicups).

The fix is of course caching, but I wasn't sure the singleton "manager" design pattern would be in the spirit of the cocos lib and also, it would be a very small class so I searched for something else.

The final solution is a static NSMutableDictionnary on the BitmapFontAtlas class itself + a little bit of rerouting in the init method.

You can take a look at the issue & my patch here.

I'm interrested in comments on this trick :)

dimanche
31mai2009

Sample code for the loading screen

I've been pretty busy finishing up beta 2 of my game for the last few days so I'm a bit late.. but here goes some sample code for the loading screen implementation (my most popular post yet :)).

I'm using a state machine design pattern so in my "init game" state class: here is the code:

- (id) init
{
    self = [super init];
    if ( self )
    {   
        // Add the Label (in cocos2D universe)
        BitmapFontAtlas *label = [BitmapFontAtlas bitmapFontAtlasWithString: @"Initializing Game" 
                                                                    fntFile: @"comic_atlas.fnt" 
                                                                  alignment: UITextAlignmentCenter];
        label.position = ccp(240, 160);
        label.opacity = 0;
        [self addChild: label z: 0 tag: kInitializingLabel];
    
        // Add the UIActivityIndicatorView (in UIKit universe)
        self.activityIndicatorView = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleWhiteLarge] autorelease];
        activityIndicatorView.center = ccp(190,240);
        [activityIndicatorView startAnimating];
        [[self battleView] addSubview: activityIndicatorView];
    
        [self schedule: @selector(loadingInit)];
        
        // At this point, the cocos2d rendering is fine.
    }
    
    return self;
}

- (void) loadingInit
{
    [self unschedule: @selector(loadingInit)];

    // Fade in nicely
    BitmapFontAtlas *label = (BitmapFontAtlas*)[self getChildByTag: kInitializingLabel];
    [label runAction: [FadeIn actionWithDuration: .25]];

    [self schedule: @selector(loadingStep0) interval: .25];
}

- (void) loadingStep0
{
    [self unschedule: @selector(loadingStep0)];
    
    // Add you own code to load texture, sounds etc...
    // The cocos2D thread will be waiting (since it's the same as the main thread) but the UIKit thread will keep running in parallel
    
    // Can do multiple steps or just one
    [self schedule: @selector(loadingStep1) interval: .5];
}

- (void) loadingStep1
{
    [self unschedule: @selector(loadingStep1)];

    // Add you own code to load texture, sounds etc...

    [self schedule: @selector(loadingDone) interval: .1];
}

- (void) loadingDone
{
    gameIsReady = YES;
    
    [self.activityIndicatorView removeFromSuperview];
    
    BitmapFontAtlas *label = (BitmapFontAtlas*)[self getChildByTag: kInitializingLabel];
    [label setString: NSLocalizedString(@"Tap to start!", nil)];
    
    [label runAction: [RepeatForever actionWithAction: 
                       [Sequence actionOne: [EaseInOut actionWithAction: [MoveTo actionWithDuration: .6 position: ccp(210, 160)] rate: 2] 
                                       two: [EaseInOut actionWithAction: [MoveTo actionWithDuration: .6 position: ccp(270, 160)] rate: 2]
                        ]       
                       ]
     ];
    
}

- (BOOL)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    if ( gameIsReady )
    {
        [self openGame];
    }
    
    return kEventHandled;
}

If you need more explanations, please let me know.