Scrolling a Level Selection Scene

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.

Getting ready

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.

How to do it…

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:

  • The layerCount variable keeps the total layers and nodes you add
  • The layerNode 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 individually

Next, 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

How it works…

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.

How it works…

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.

How it works…
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.163.238