cocos2d: Displaying a grid of items in a scrollview, clipping node

In a cocos2d iOS game I am currently writing, one of the things I wanted was to display a menu of items using a grid style, display the said menu in a scrollview; so I would have multiple items per page, and then finally — put the items in a clipping node.

Here is a visual representation from my game,


This is a menu of 12 items displayed in a grid of 3×2, that is 6 items per page.

To make this work, I would need to use a CCScrollLayer to paginate between each page, each having 3×2 items on them.

Furthermore, I need to put them in a clipping node. By a clipping node I mean something which clips the viewport in which the grid appears in.

Imagine we have a modal pop-up window, or something where we do not want the visuals to “spill over” a certain boundary; this is what we use the clipping node for.

For all of this to work, you will need the following:

+ cocos2d-iphone v2.x (I did not test for 1.x) (cocos2d website)
+ CCScrollLayer (part of the cocos2d-iphone-extensions in github)
+ CCMenu+Layout.h (Tony Ngo)
+ Viewport ( or ClippingNode (via cocos2d website)
+ (Optional) CCMenuAdvanced (See: cocos2d-iphone-extensions)

I used Viewport rather than ClippingNode because I couldn’t quite get it to work, whereas I found Viewport used similar code and seemed to work a bit more straightforwardly.

Anyway, my code now follows. It may not necessarily work for you, but should give you some indications of what I did.


#import "Viewport.h"
#import "CCMenu+Layout.h"
#import "CCMenuAdvanced.h"
#import "CCScrollLayer.h"
// Notes
// Apple is a custom item.
// List would be your array of custom objects ie: Apples or whatever

// Display the items in a grid            
NSMutableArray *pageArray = [NSMutableArray array];
CCLayer *page = nil;
CCMenu *itemMenu = nil;

int tag = 0;
int count = 0;

// We want a grid of 3x2, this means count must 
// reach 6 before making a new page.
for (Apple *apple in list) {
    if (count == 0) {
        page = [CCLayer node];
        itemMenu=[CCMenu menuWithItems:nil];
        [itemMenu setContentSize:CGSizeMake(300, 100)];
        [itemMenu setAnchorPoint:CGPointMake(0, 0.5)];
        [itemMenu setPosition:CGPointMake(80, 90)];
        [page addChild:itemMenu];
        [pageArray addObject:page];
    // Avatar Button
    CCSprite *avtButton = nil;
    // Get the image from the custom object
    NSString *fileName = [NSString stringWithFormat:@"%@.png", apple.filename];

    avtButton = [AvatarButton spriteWithSpriteFrameName:fileName];
    [avtButton setScale:0.75];
    // Create menu item
    CCMenuItemSprite *btnWG = [CCMenuItemSprite itemFromNormalSprite:avtButton selectedSprite:nil target:self selector:@selector(menuButtonTapped:)];
    [btnWG setTag:tag];
    [itemMenu addChild:btnWG];
    if (count == 6) {
        [itemMenu alignItemsInGridWithPadding:CGPointMake(15, 2) columns:3];
} // next

// Now create the scroller and pass-in the pages (set widthOffset to 0 for fullscreen pages)
self.scroller = [[[CCScrollLayer alloc] initWithLayers:pageArray widthOffset:250] autorelease];
[self.scroller setShowPagesIndicator:YES];
[self.scroller setPagesIndicatorPosition:CGPointMake(335, 100)];            

Viewport *cn = [[Viewport alloc] initWithRect:CGRectMake(75,75, 300, 180)];
[cn setAnchorPoint:CGPointMake(0, 0.5)];
[cn addChild:scroller];
[self addChild:cn z:8];
[cn release];

Because we need a grid of 6 items, the `count` variable must reach 6 before “creating” a new page. Each page has it menu aligned to 3 columns.

The page gets added to the pageArray (a list of pages) which are used by the scroller object.

Finally, we create a clipping node and add the scroller as a child of the clipping node’s object before we add the clipping node to self (or it could be a layer).

I’ve been able to test it for 12 items, 6 per page but if you want a custom amount (say 2-4 per page) you must adjust the numbers in the code above to match your expectations.

I hope this helps in your code development.