As we have discussed before, a scene can contain any number of layers you want. Well, as long as performance is not an issue. As CCLayer inherits from CCNode, it can be added as the child of CCScenes or other CCLayers, allowing you to organize your content in a nice fashion.
There are three types of CCLayers that you can use and combine in your games. They are as follows:
In the following examples, we will be creating some CCLayers in different ways to achieve different results.
We will begin by building a simple Heads Up Display (HUD) for our game. Its purpose is to show some useful data about the current state of the game to the player. The idea behind making the HUD into a new layer is to simplify the logic of the GameLayer. This way, the GameLayer will only handle stuff of the game itself while leaving the HUD logic to the HUDLayer.
In our game, the HUD will display the remaining lives, score, remaining bombs, and anything you want to display later. Once it is done, all we need to do in the GameLayer is send a message so the HUDLayer gets updated.
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "GameScene.h"
@interface HudLayer : CCLayer
{
CCBitmapFontAtlas * level;
CCBitmapFontAtlas * score;
CCBitmapFontAtlas * bombs;
NSMutableArray * lives;
}
@property (nonatomic,retain) CCBitmapFontAtlas * level;
@property (nonatomic,retain) CCBitmapFontAtlas * score;
@property (nonatomic,retain) CCBitmapFontAtlas * bombs;
@property (nonatomic,retain) NSMutableArray * lives;
@end
#import "HudLayer.h"
@implementation HudLayer
@synthesize lives,bombs,score,level;
- (id) init
{
if ((self = [super init])) {
CCSprite * background = [CCSprite spriteWithFile:@"hud_background.png"];
[background setPosition:ccp(160,455)];
[self addChild:background];
lives = [[NSMutableArray arrayWithCapacity:3]retain];
for(int i=0;i<3;i++)
{
CCSprite * life = [CCSprite spriteWithFile:@"hud_life.png"];
[life setPosition:ccp(18+ 28*i,465)];
[self addChild:life];
[lives addObject:life];
}
CCSprite * bomb = [CCSprite spriteWithFile:@"hud_bomb.png"];
[bomb setPosition:ccp(18,445)];
[self addChild:bomb];
GameLayer * gl = (GameLayer *)[self.parent getChildByTag:KGameLayer];
level = [CCBitmapFontAtlas bitmapFontAtlasWithString:@"Level 1"
fntFile:@"hud_font.fnt"];
[level setAnchorPoint:ccp(1,0.5)];
[level setPosition:ccp(310,465)];
[level setColor:ccBLACK];
[self addChild:level];
score = [CCBitmapFontAtlas bitmapFontAtlasWithString:@"Score 0"
fntFile:@"hud_font.fnt"];
[score setAnchorPoint:ccp(1,0.5)];
[score setPosition:ccp(310,445)];
[score setColor:ccBLACK];
[self addChild:score];
bombs = [CCBitmapFontAtlas bitmapFontAtlasWithString:@"X3"
fntFile:@"hud_font.fnt"];
[bombs setAnchorPoint:ccp(1,0.5)];
[bombs setPosition:ccp(47,440)];
[bombs setColor:ccBLACK];
[self addChild:bombs];
}
return self;
}
- (void) dealloc
{
[super dealloc];
[lives release];
}
@end
You can find the images and the font used above in the companion files at Support.
- (id) init
{
self = [super init];
if (self != nil)
{
[self addChild:[GameLayer node] z:0 tag:KGameLayer];
//kGameLayer defined in the GameScene.h file.
#define kGameLayer 1
[self addChild:[HudLayer node] z:1 tag:KHudLayer];
//kHudLayer defined in the GameScene.h file. #define
kHudLayer 2
}
return self;
}
The only thing missing now is to make some changes here and there to be able to update the HUDLayer with the actual state of the game. Let's update the score and remaining lives, for now.
-(void)loseLife
{
self.lives--;
HudLayer * hl = (HudLayer *)[self.parent getChildByTag:KHudLayer];
CCSprite * live = [hl.lives objectAtIndex:self.lives];
[live setVisible:NO];
if(self.lives ==0)
{
[self resetGame];
//LOSE THE GAME
//GO TO GAME OVER LAYER
}
}
-(void)resetGame
{
HudLayer * hl = (HudLayer *)[self.parent getChildByTag:KHudLayer];
for(CCSprite * c in hl.lives)
{
[c setVisible:YES];
}
self.level=1;
[hl.level setString:@"Level 1"];
self.score=0;
[hl.score setString:@"Score 0"];
self.bombs =3;
[hl.bombs setString:@"X3"];
lives = STARTING_LIVES;
}
These methods will handle the displaying of the remaining lives.
-(void)destroy
{
[self reset];
[theGame setScore:theGame.score+100];
HudLayer * hl = (HudLayer *)[theGame.parent getChildByTag:KHudLayer];
[hl.score setString:[NSString stringWithFormat:@"Score
%d",theGame.score]];
}
We just went through the steps needed to create a new layer, adding it to the scene and updating its contents.
Our new layer just holds some information of the game state and displays it to the player. In order to achieve that we just added a few CCSprites and CCBitmapFontAtlases which get updated when needed.
Once the HudLayer class was created we added it to the GameScene over the GameLayer, so its contents are always shown on top of the GameLayer's ones. We also provided a tag for both layers, as we will need to access them from other places. We could also have added a reference to the other layer inside them.
That is all what we need to do in order to add more layers to a scene. The rest of the code just handles the updating of the contents of the HudLayer. When the player hits an enemy, a score is awarded. Then the label placed in the HUD is updated.
When the hero is hit and a life is lost, we just turn the corresponding icon's visibility off, then when the game is reset we turn all of them on.