Cocos2d tutorial: Creating a reusable pause layer

This is the first post we are doing for being posted in http://idevblogaday.com/. I really hope you find it useful!

One thing that most, if not all, games have is a pause screen. In all this time developing games with Cocos2d I have seen people asking around the fourms how to do a proper pause screen that can have its elements animated. There are several solutions for this issue, but this is the one i found the easiest to implement and that we have been using for most of our games.

Cocos2d offers a simple method to pause and resume itself, but these methods stop the CCDirector (the class that manages most aspects of a Cocos2d’s app lifetime) from running actions and lower the fps to 5 to conserve battery life.

So, how can we easily get our game to get paused without canceling any running actions or scheduled methods and easily resume leaving the game in the very same state it was before being paused? Here is the answer.

I am going to show you how to create a simple class, PauseLayer, that once it is added to the scene, it pauses the layer we passed as delegate and when this pause layer is removed, it resumes the layer where the game is running.

This is the PauseLayer.h

#import <Foundation/Foundation.h>
#import “cocos2d.h”

@interface PauseLayerProtocol: CCNode

-(void)pauseLayerDidPause;
-(void)pauseLayerDidUnpause;
@end

@interface PauseLayer : CCLayerColor {

PauseLayerProtocol * delegate;
}

@property (nonatomic,assign)PauseLayerProtocol * delegate;

+ (id) layerWithColor:(ccColor4B)color delegate:(PauseLayerProtocol *)_delegate;
– (id) initWithColor:(ccColor4B)c delegate:(PauseLayerProtocol *)_delegate;
-(void)pauseDelegate;

@end

And PauseLayer.m

//
//  PauseLayer.m
//  Pause
//
//  Created by Pablo Ruiz on 06/06/11.
//  Copyright 2011 PlaySnack. All rights reserved.
//

#import “PauseLayer.h”

@implementation PauseLayer

@synthesize delegate;

+ (id) layerWithColor:(ccColor4B)color delegate:(id)_delegate
{
return [[[self alloc] initWithColor:color delegate:_delegate] autorelease];
}

– (id) initWithColor:(ccColor4B)c delegate:(id)_delegate {
self = [super initWithColor:c];
if (self != nil) {

CGSize wins = [[CCDirector sharedDirector] winSize];

delegate = _delegate;
[self pauseDelegate];

CCSprite * background = [CCSprite spriteWithFile:@”pause_background.png”];

[self addChild:background];

CCMenuItemImage *resume = [CCMenuItemImage itemFromNormalImage:@”pause_btn_resume.png”
selectedImage:@”pause_btn_resume_dwn.png”
target:self
selector:@selector(doResume:)];
CCMenu * menu = [CCMenu menuWithItems:resume,nil];

[menu setPosition:ccp(0,0)];

[resume setPosition:ccp([background boundingBox].size.width/2,[background boundingBox].size.height/2)];

[background addChild:menu];

[background setPosition:ccp(wins.width/2,wins.height/2)];

}
return self;
}

-(void)pauseDelegate
{
if([delegate respondsToSelector:@selector(pauseLayerDidPause)])
[delegate pauseLayerDidPause];
[delegate onExit];
[delegate.parent addChild:self z:10];
}

-(void)doResume: (id)sender
{
[delegate onEnter];
if([delegate respondsToSelector:@selector(pauseLayerDidUnpause)])
[delegate pauseLayerDidUnpause];
[self.parent removeChild:self cleanup:YES];
}

-(void)dealloc
{
[super dealloc];
}

@end

This is what is going on in the code. First the PauseLayer is initialized with a color of your choosing and the delegate, which is the layer that we want to pause, generally this would be the layer where the whole game in the current scene is running.  We call the pauseDelegate method which will call the delegate’s pauseLayerDidPause method, that you can implement in your class. You can use this moment to take any actions in your game before pausing.

Then, back in the init method, we add the pause menu’s interface (in this case just a background image and a resume button, but you can add more stuff in there).

When the resume button is pressed, we call the doResume which unpuses the delegate and calls its pauseLayerDidUnpause that if implemented can be used by you to do stuff once the game has been unpaused. Then, the pause layer is removed from its parent.

Since we are not pausing the CCDirector, we can run any action inside this Pause Layer, for example animating its buttons or whatever you need to do.

The magic happens by calling the delegate’s onExit method when pausing it, and then calling the onEnter method when resuming, with just this the layer is frozen and we don’t lose anything that was happening in there. We don’t need to unschedule/re/ schedule selectors or restarting actions.

In order to use this class we just have to go to the game’s layer. Import the PauseLayer.h class and when you intend to pause the game just do:

-(void)doPause
{
ccColor4B c ={0,0,0,150};
[PauseLayer layerWithColor:c delegate:self];
}

That is all. This class has many other uses other than using it as a pause screen. We could create a tutorial screen that pauses the action while it is being shown, for example.

If you have any suggestions to improve it, we are all open to hearing them!

*If you managed to read up to here, please excuse us for the really bad formatting of the code sections! We are trying to find a good WordPress plugin for inserting code. If you know about a good one, please let us know!