If your game has say 20 levels, it is okay to have one single level selection scene to display all the level buttons; but what if you have more? In this section, we will modify the previous section's code, create a node, and customize the class to create a scrollable level selection scene.
We will create a new class called LevelSelectionLayer
, inherit from CCNode
, and move all the content we added to LevelSelectionScene
to it. This is done so that we can have a separate class and instantiate it as many times as we want in the game.
In the LevelSelectionLayer.m
file, we will change the code to the following:
#import "CCNode.h" @interface LevelSelectionLayer : CCNode { NSMutableArray *buttonSpritesArray; } -(id)initLayerWith:(NSString *)filename StartlevelNumber:(int)lvlNum widthCount:(int)widthCount heightCount:(int)heightCount spacing:(float)spacing; @end
We changed the init
function so that instead of hardcoding the values, we can create a more flexible level selection layer.
In the LevelSelectionLayer.m
file, we will add the following:
#import "LevelSelectionLayer.h" #import "LevelSelectionBtn.h" #import "GameplayScene.h" @implementation LevelSelectionLayer - (void)onEnter{ [super onEnter]; self.userInteractionEnabled = YES; } - (void)onExit{ [super onExit]; self.userInteractionEnabled = NO; } -(id)initLayerWith:(NSString *)filename StartlevelNumber:(int)lvlNum widthCount:(int)widthCount heightCount:(int)heightCount spacing:(float)spacing{ if(self = [super init]){ CGSize winSize = [[CCDirector sharedDirector]viewSize]; self.contentSize = winSize; buttonSpritesArray = [NSMutableArray array]; float halfWidth = self.contentSize.width/2 - (widthCount-1) * spacing * 0.5f; float halfHeight = self.contentSize.height/2 + (heightCount-1) * spacing * 0.5f; int levelNum = lvlNum; for(int i = 0; i < heightCount; ++i){ float y = halfHeight - i * spacing; for(int j = 0; j < widthCount; ++j){ float x = halfWidth + j * spacing; LevelSelectionBtn* lvlBtn = [[LevelSelectionBtn alloc]initWithFilename:filename StartlevelNumber:levelNum]; lvlBtn.position = CGPointMake(x,y); lvlBtn.name = [NSString stringWithFormat:@"%d",levelNum]; [self addChild:lvlBtn]; [buttonSpritesArray addObject: lvlBtn]; levelNum++; } } } return self; } -(void)touchBegan:(CCTouch *)touch withEvent:(CCTouchEvent *)event{ CGPoint location = [touch locationInNode:self]; CCLOG(@"location: %f, %f", location.x, location.y); CCLOG(@"touched"); for (CCSprite *sprite in buttonSpritesArray) { if (CGRectContainsPoint(sprite.boundingBox, location)){ CCLOG(@" you have pressed: %@", sprite.name); CCTransition *transition = [CCTransition transitionCrossFadeWithDuration:0.20]; [[CCDirector sharedDirector]replaceScene:[[GameplayScene alloc]initWithLevel:sprite.name] withTransition:transition]; } } } @end
The major changes are highlighted here. The first is that we added and removed the touch functionality using the onEnter
and onExit
functions. The other major change is that we set the contentsize
value of the node to winSize
. Also, while specifying the upper-left coordinate of the button, we did not use winSize
for the center but the contentsize
of the node.
Let's move to LevelSelectionScene
now; we will execute the following code:
#import "CCScene.h" @interface LevelSelectionScene : CCScene{ int layerCount; CCNode *layerNode; } +(CCScene*)scene; @end
In the header file, we will change it by adding two global variables to it:
layerCount
variable keeps the total layers and nodes you addlayerNode
variable is an empty node added for convenience so that we can add all the layer nodes to it so that we can move it back and forth instead of moving each layer node individuallyNext, in the LevelSelectionScene.m
file, we will add the following:
#import "LevelSelectionScene.h" #import "LevelSelectionBtn.h" #import "GameplayScene.h" #import "LevelSelectionLayer.h" @implementation LevelSelectionScene +(CCScene*)scene{ return[[self alloc]init]; } -(id)init{ if(self = [super init]){ CGSize winSize = [[CCDirector sharedDirector]viewSize]; layerCount = 1; //Basic CCSprite - Background Image CCSprite* backgroundImage = [CCSprite spriteWithImageNamed:@"Bg.png"]; backgroundImage.position = CGPointMake(winSize.width/2, winSize.height/2); [self addChild:backgroundImage]; CCLabelTTF *mainmenuLabel = [CCLabelTTF labelWithString:@"LevelSelectionScene" fontName:@"AmericanTypewriter-Bold" fontSize: 36.0f]; mainmenuLabel.position = CGPointMake(winSize.width/2, winSize.height * 0.8); [self addChild:mainmenuLabel]; //empty node layerNode = [[CCNode alloc]init]; [self addChild:layerNode]; int widthCount = 5; int heightCount = 5; float spacing = 35; for(int i=0; i<3; i++){ LevelSelectionLayer* lsLayer = [[LevelSelectionLayer alloc]initLayerWith:@"btnBG.png" StartlevelNumber:widthCount * heightCount * i + 1 widthCount:widthCount heightCount:heightCount spacing:spacing]; lsLayer.position = ccp(winSize.width * i, 0); [layerNode addChild:lsLayer]; } CCButton *leftBtn = [CCButton buttonWithTitle:nil spriteFrame:[CCSpriteFrame frameWithImageNamed:@"left.png"] highlightedSpriteFrame:[CCSpriteFrame frameWithImageNamed:@"left.png"] disabledSpriteFrame:nil]; [leftBtn setTarget:self selector:@selector(leftBtnPressed:)]; CCButton *rightBtn = [CCButton buttonWithTitle:nil spriteFrame:[CCSpriteFrame frameWithImageNamed:@"right.png"] highlightedSpriteFrame:[CCSpriteFrame frameWithImageNamed:@"right.png"] disabledSpriteFrame:nil]; [rightBtn setTarget:self selector:@selector(rightBtnPressed:)]; CCLayoutBox * btnMenu; btnMenu = [[CCLayoutBox alloc] init]; btnMenu.anchorPoint = ccp(0.5f, 0.5f); btnMenu.position = CGPointMake(winSize.width * 0.5, winSize.height * 0.2); btnMenu.direction = CCLayoutBoxDirectionHorizontal; btnMenu.spacing = 300.0f; [btnMenu addChild:leftBtn]; [btnMenu addChild:rightBtn]; [self addChild:btnMenu z:4]; } return self; } -(void)rightBtnPressed:(id)sender{ CCLOG(@"right button pressed"); CGSize winSize = [[CCDirector sharedDirector]viewSize]; if(layerCount >=0){ CCAction* moveBy = [CCActionMoveBy actionWithDuration:0.20 position:ccp(-winSize.width, 0)]; [layerNode runAction:moveBy]; layerCount--; } } -(void)leftBtnPressed:(id)sender{ CCLOG(@"left button pressed"); CGSize winSize = [[CCDirector sharedDirector]viewSize]; if(layerCount <=0){ CCAction* moveBy = [CCActionMoveBy actionWithDuration:0.20 position:ccp(winSize.width, 0)]; [layerNode runAction:moveBy]; layerCount++; } } @end
The important piece of the code is highlighted. Apart from adding the usual background and text, we will initialize layerCount
as 1
and initialize the empty layerNode
variable.
Next, we will create a for
loop, in which we will add the three level selection layers by passing the starting value of each selection layer in the btnBg
image, the width count, height count, and spacing between each of the buttons.
Also, note how the layers are positioned at a distance of the width of the screen from each other. The first one is visible to the player. The consecutive layers are added offscreen in a similar way to how we placed the second image offscreen while creating the parallax effect.
Then, each level selection layer is added to layerNode
as a child.
We will also create the left-hand side and right-hand side buttons so that we can move layerNode
to the left and right once clicked on. We will create two functions called leftBtnPressed
and rightBtnPressed
in which we will add functionality when the left-hand side or right-hand side button gets pressed.
First, let's look at the rightBtnPressed
function. Once the button is pressed, we will log out this button. Next, we will get the size of the window. We will then check whether the value of layerCount
is greater than zero, which is true as we set the value as 1
. We will create a moveBy
action, in which we give the window width for the movement in the x
direction and 0
for the movement in the y
direction as we want the movement to be only in the x
direction and not y
. Lastly, we will pass in a value of 0.20f
.
The action is then run on layerNode
and the layerCount
value is decremented.
In the leftBtnPressed
function, the opposite is done to move the layer in the opposite direction. Run the game to see the change in LevelSelectionScene
.
As you can't go left, pressing the left button won't do anything. However, if you press the right button, you will see that the layer scrolls to show the next set of buttons.
18.119.163.238