title: cocos2d 3.0 sliding menu grid
body: <p>I am migrating all my games to cocos2d 3.0. I used SlidingMenuGrid.m with slight modification. </p>
  
  <p>SlidingMenuGrid.h:</p>
  
  <pre><code>//
  //  SlidingMenuGrid
  //
  //  Created by Brandon Reynolds on 1/9/11.
  
  #import "cocos2d.h"
  
  @interface SlidingMenuGrid : CCLayer
  {
      tCCMenuState state; // State of our menu grid. (Eg. waiting, tracking touch, cancelled, etc)
      CCMenuItem *selectedItem; // Menu item that was selected/active.
  
      CGPoint padding; // Padding in between menu items.
      CGPoint menuOrigin; // Origin position of the entire menu grid.
      CGPoint touchOrigin; // Where the touch action began.
      CGPoint touchStop; // Where the touch action stopped.
  
      int iPageCount; // Number of pages in this grid.
      int iCurrentPage; // Current page of menu items being viewed.
  
      bool bMoving; // Is the grid currently moving?
      bool bSwipeOnlyOnMenu; // Causes swiping functionality to only work when siping on top of the menu items instead of entire screen.
      bool bVerticalPaging; // Disabled by default. Allows for pages to be scrolled vertically instead of horizontal.
  
      float fMoveDelta; // Distance from origin of touch and current frame.
      float fMoveDeadZone; // Amount they need to slide the grid in order to move to a new page.
      float fAnimSpeed; // 0.0-1.0 value determining how slow/fast to animate the paging.
  
  
  
      CGPoint pageIndicatorPosition;
  
  }
  
  
  //use this 5:
  -(int) getTotalPage;
  -(int) getCurrentPage;
  -(void) moveToPage: (int) page animated: (BOOL) animated;
  +(id) packWithArray: (NSMutableArray*) items posY: (int) posY indicatorPosY: (int) indiPosY;
  +(id) levelWithArray: (NSMutableArray*) items cols: (int) cols rows: (int) rows leftEdge: (int) leftEdge upperEdge: (int) upperEdge lowerEdge: (int) lowerEdge indicatorPosY: (int) indiPosY;
  
  
  
  
  +(id) menuWithArray:(NSMutableArray*)items cols:(int)cols rows:(int)rows position:(CGPoint)pos padding:(CGPoint)pad pageIndicatorPosition:(CGPoint)pip;
  
  -(id) initWithArray:(NSMutableArray*)items cols:(int)cols rows:(int)rows position:(CGPoint)pos padding:(CGPoint)pad verticalPaging:(bool)vertical pageIndicatorPosition:(CGPoint)pip;
  
  -(void) buildGrid:(int)cols rows:(int)rows;
  -(void) buildGridVertical:(int)cols rows:(int)rows;
  -(CCMenuItem*) GetItemWithinTouch:(UITouch*)touch;
  - (CGPoint) GetPositionOfCurrentPageWithOffset:(float)offset;
  - (CGPoint) GetPositionOfCurrentPage;
  
  - (bool) IsSwipingOnMenuOnlyEnabled;
  - (void) SetSwipingOnMenuOnly:(bool)bValue;
  
  - (float) GetSwipeDeadZone;
  - (void) SetSwipeDeadZone:(float)fValue;
  
  - (bool) IsVerticallyPaged;
  - (void) SetVerticalPaging:(bool)bValue;
  
  @property (nonatomic, readwrite) CGPoint padding;
  @property (nonatomic, readwrite) CGPoint menuOrigin;
  @property (nonatomic, readwrite) CGPoint touchOrigin;
  @property (nonatomic, readwrite) CGPoint touchStop;
  @property (nonatomic, readwrite) int iPageCount;
  @property (nonatomic, readwrite) int iCurrentPage;
  @property (nonatomic, readwrite) bool bMoving;
  @property (nonatomic, readwrite) bool bSwipeOnlyOnMenu;
  @property (nonatomic, readwrite) bool bVerticalPaging;
  @property (nonatomic, readwrite) float fMoveDelta;
  @property (nonatomic, readwrite) float fMoveDeadZone;
  @property (nonatomic, readwrite) float fAnimSpeed;
  
  @end
  </code></pre>
  
  <p>SlidingMenuGrid.m</p>
  
  <pre><code>#import "SlidingMenuGrid.h"
  
  #import "Constants.h"
  
  @implementation SlidingMenuGrid
  
  @synthesize padding;
  @synthesize menuOrigin;
  @synthesize touchOrigin;
  @synthesize touchStop;
  @synthesize bMoving;
  @synthesize bSwipeOnlyOnMenu;
  @synthesize fMoveDelta;
  @synthesize fMoveDeadZone;
  @synthesize iPageCount;
  @synthesize iCurrentPage;
  @synthesize bVerticalPaging;
  @synthesize fAnimSpeed;
  
  
  -(int) getTotalPage {
      return iPageCount;
  }
  -(int) getCurrentPage {
      return iCurrentPage;
  }
  
  +(id) packWithArray: (NSMutableArray*) items posY: (int) posY indicatorPosY: (int) indiPosY {
  
  
      CGSize size = [CCDirector sharedDirector].winSize;
      BOOL vertical = NO;
      //pos, padding, pageindicatorpos
      CGPoint pos = ccp(size.width / 2, posY);
      CGPoint posIndicator = ccp(size.width / 2, indiPosY);
      //padding no matter
  
      return [SlidingMenuGrid menuWithArray:items cols:1 rows:1 position:pos padding:ccp(0, 0) verticalPaging:vertical pageIndicatorPosition:posIndicator];
  
  }
  +(id) levelWithArray: (NSMutableArray*) items cols: (int) cols rows: (int) rows leftEdge: (int) leftEdge upperEdge: (int) upperEdge lowerEdge: (int) lowerEdge indicatorPosY: (int) indiPosY {
  
      CGSize screen = [CCDirector sharedDirector].winSize;
      BOOL vertical = NO;
  
      CGSize itemSize = [[items objectAtIndex:0] boundingBox].size;
      //pos, padding, pageindipos
      CGPoint posIndicator = ccp(screen.width / 2, indiPosY);
  
      int posx = leftEdge + itemSize.width / 2;
      int posy = screen.height - (upperEdge + itemSize.height / 2);
      int padx = (screen.width - itemSize.width - 2 * leftEdge) / (cols - 1);
      int pady = (screen.height - upperEdge - lowerEdge - itemSize.height) / (rows - 1);
  
      return [SlidingMenuGrid menuWithArray:items cols:cols rows:rows position:ccp(posx, posy) padding:ccp(padx, pady) verticalPaging:vertical pageIndicatorPosition:posIndicator];
  }
  
  
  
  +(id) menuWithArray:(NSMutableArray*)items cols:(int)cols rows:(int)rows position:(CGPoint)pos padding:(CGPoint)pad pageIndicatorPosition:(CGPoint)pip
  {
      return [[[self alloc] initWithArray:items cols:cols rows:rows position:pos padding:pad verticalPaging:false pageIndicatorPosition:pip] autorelease];
  }
  
  +(id) menuWithArray:(NSMutableArray*)items cols:(int)cols rows:(int)rows position:(CGPoint)pos padding:(CGPoint)pad verticalPaging:(bool)vertical pageIndicatorPosition: (CGPoint) pip
  {
      return [[[self alloc] initWithArray:items cols:cols rows:rows position:pos padding:pad verticalPaging:vertical pageIndicatorPosition:pip] autorelease];
  }
  
  -(id) initWithArray:(NSMutableArray*)items cols:(int)cols rows:(int)rows position:(CGPoint)pos padding:(CGPoint)pad verticalPaging:(bool)vertical pageIndicatorPosition:(CGPoint)pip
  {
      if ((self = [super init]))
      {
          self.isTouchEnabled = YES;
  
          int z = 1;
          for (id item in items)
          {
              [self addChild:item z:z tag:z];
              ++z;
          }
  
          padding = pad;
          iCurrentPage = 0;
          bMoving = false;
          bSwipeOnlyOnMenu = false;
          menuOrigin = pos;
          fMoveDeadZone = 10;
          bVerticalPaging = vertical;
          fAnimSpeed = 0.6f;
          (bVerticalPaging) ? [self buildGridVertical:cols rows:rows] : [self buildGrid:cols rows:rows];
          self.position = menuOrigin;
  
  
          pageIndicatorPosition = pip;
      }
  
      return self;
  }
  
  -(void) dealloc
  {
      [super dealloc];
  }
  
  -(void) buildGrid:(int)cols rows:(int)rows
  {
      CGSize winSize = [[CCDirector sharedDirector] winSize];
  
      int col = 0, row = 0;
      for (CCMenuItem* item in self.children)
      {
          // Calculate the position of our menu item. 
          item.position = CGPointMake(self.position.x + col * padding.x + (iPageCount * winSize.width), self.position.y - row * padding.y);
  
          // Increment our positions for the next item(s).
          ++col;
          if (col == cols)
          {
              col = 0;
              ++row;
  
              if( row == rows )
              {
                  iPageCount++;
                  col = 0;
                  row = 0;
              }
          }
      }
  
      if([self children].count &gt; rows * cols * iPageCount) iPageCount++;
  
  }
  
  
  
  -(void) buildGridVertical:(int)cols rows:(int)rows
  {
      CGSize winSize = [[CCDirector sharedDirector] winSize];
  
      int col = 0, row = 0;
      for (CCMenuItem* item in self.children)
      {
          // Calculate the position of our menu item. 
          item.position = CGPointMake(self.position.x + col * padding.x , self.position.y - row * padding.y + (iPageCount * winSize.height));
  
          // Increment our positions for the next item(s).
          ++col;
          if (col == cols)
          {
              col = 0;
              ++row;
  
              if( row == rows )
              {
                  iPageCount++;
                  col = 0;
                  row = 0;
              }
          }
      }
  
  
      if([self children].count &gt; rows * cols * iPageCount) iPageCount++;
  
  
  
  }
  
  -(void) addChild:(CCMenuItem*)child z:(int)z tag:(int)aTag
  {
      return [super addChild:child z:z tag:aTag];
  }
  
  -(CCMenuItem*) GetItemWithinTouch:(UITouch*)touch
  {
      // Get the location of touch.
      CGPoint touchLocation = [[CCDirector sharedDirector] convertToGL: [touch locationInView: [touch view]]];
  
      // Parse our menu items and see if our touch exists within one.
      for (CCMenuItem* item in [self children])
      {
          //only deal with the item
          if ([item isKindOfClass:[CCMenuItem class]]) {
              CGPoint local = [item convertToNodeSpace:touchLocation];
  
              CGRect r = [item rect];
              r.origin = CGPointZero;
  
              // If the touch was within this item. Return the item.
              if (CGRectContainsPoint(r, local))
              {
                  return item;
              }
          }
      }
  
      // Didn't touch an item.
      return nil;
  }
  
  -(void) registerWithTouchDispatcher
  {
      [[CCDirector sharedDirector].touchDispatcher addTargetedDelegate:self priority:kCCMenuHandlerPriority swallowsTouches:NO];
  }
  
  -(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
  {
      // Convert and store the location the touch began at.
      touchOrigin = [[CCDirector sharedDirector] convertToGL:[touch locationInView:[touch view]]];
  
      // If we weren't in "waiting" state bail out.
      if (state != kCCMenuStateWaiting)
      {
          return NO;
      }
  
      // Activate the menu item if we are touching one.
      selectedItem = [self GetItemWithinTouch:touch];
      [selectedItem selected];
  
      // Only track touch if we are either in our menu system or dont care if they are outside of the menu grid.
      if (!bSwipeOnlyOnMenu || (bSwipeOnlyOnMenu &amp;&amp; selectedItem) )
      {
          state = kCCMenuStateTrackingTouch;
          return YES;
      }
  
      return NO;
  }
  
  // Touch has ended. Process sliding of menu or press of menu item.
  -(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
  {   
      // User has been sliding the menu.
      if( bMoving )
      {
          bMoving = false;
  
          // Do we have multiple pages?
          if( iPageCount &gt; 1 &amp;&amp; (fMoveDeadZone &lt; abs(fMoveDelta)))
          {
              // Are we going forward or backward?
              bool bForward = (fMoveDelta &lt; 0) ? true : false;
  
              // Do we have a page available?
              if(bForward &amp;&amp; (iPageCount&gt;iCurrentPage+1))
              {
                  // Increment currently active page.
                  iCurrentPage++;
              }
              else if(!bForward &amp;&amp; (iCurrentPage &gt; 0))
              {
                  // Decrement currently active page.
                  iCurrentPage--;
              }
          }
  
          // Start sliding towards the current page.
          [self moveToCurrentPage];           
  
      }
      // User wasn't sliding menu and simply tapped the screen. Activate the menu item.
      else 
      {
          [selectedItem unselected];
          [selectedItem activate];
      }
  
      // Back to waiting state.
      state = kCCMenuStateWaiting;
  }
  
  -(void) moveToPage: (int) page animated:(BOOL)animated {
      float interval = 0;
      if (animated) {
          interval = 0.3f * abs(iCurrentPage - page);
      }
  
      iCurrentPage = page;
  
      // Perform the action
      CGPoint position = [self GetPositionOfCurrentPage];
      CCMoveTo* action = [CCMoveTo actionWithDuration:interval position:position];
      [self runAction:action];
  
  }
  
  // Run the action necessary to slide the menu grid to the current page.
  - (void) moveToCurrentPage
  {
      CGSize winSize = [[CCDirector sharedDirector] winSize];
  
      // Perform the action
      CGPoint position = [self GetPositionOfCurrentPage];
      CCMoveTo* action = [CCMoveTo actionWithDuration:fAnimSpeed * 0.3f position:position];
      [self runAction:action];
  
  }
  
  -(void) ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event
  {
      [selectedItem unselected];
  
      state = kCCMenuStateWaiting;
  }
  
  -(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
  {
  
  
      // Calculate the current touch point during the move.
      touchStop = [[CCDirector sharedDirector] convertToGL:[touch locationInView:[touch view]]];
  
      // Distance between the origin of the touch and current touch point.
      fMoveDelta = (bVerticalPaging) ? (touchStop.y - touchOrigin.y) : (touchStop.x - touchOrigin.x);
  
      // Set our position.
      [self setPosition:[self GetPositionOfCurrentPageWithOffset:fMoveDelta]];
      bMoving = true;
  
      if (selectedItem) {
          [selectedItem unselected];
          selectedItem = nil;
      }
  
  }
  
  - (CGPoint) GetPositionOfCurrentPage
  {
      CGSize winSize = [[CCDirector sharedDirector] winSize];
  
      return (bVerticalPaging) ?
      CGPointMake(menuOrigin.x,menuOrigin.y-(iCurrentPage*winSize.height))
      : CGPointMake((menuOrigin.x-(iCurrentPage*winSize.width)),menuOrigin.y);
  }
  
  - (CGPoint) GetPositionOfCurrentPageWithOffset:(float)offset
  {
      CGSize winSize = [[CCDirector sharedDirector] winSize];
  
      return (bVerticalPaging) ?
      CGPointMake(menuOrigin.x,menuOrigin.y-(iCurrentPage*winSize.height)+offset)
      : CGPointMake((menuOrigin.x-(iCurrentPage*winSize.width)+offset),menuOrigin.y);
  }
  
  
  
  // Returns whether or not we should only allow swiping on the actual grid.
  - (bool) IsSwipingOnMenuOnlyEnabled
  {
      return bSwipeOnlyOnMenu;
  }
  
  // Sets the ability to swipe only on the menu or utilize entire screen for swiping.
  - (void) SetSwipingOnMenuOnly:(bool)bValue
  {
      bSwipeOnlyOnMenu = bValue;
  }
  
  // Returns the swiping dead zone. 
  - (float) GetSwipeDeadZone
  {
      return fMoveDeadZone;
  }
  
  - (void) SetSwipeDeadZone:(float)fValue
  {
      fMoveDeadZone = fValue;
  }
  
  // Returns wheather or not vertical paging is enabled.
  - (bool) IsVerticallyPaged
  {
      return bVerticalPaging;
  }
  
  // Sets the vertical paging flag.
  - (void) SetVerticalPaging:(bool)bValue
  {
      bVerticalPaging = bValue;
      [self buildGridVertical];
  }
  
  
  
  
  
  
  
  
  
  
  - (void) visit
  {
      [super visit];//&lt; Will draw after glPopScene.
  
      BOOL showPagesIndicator = YES;
  
  
      ccColor4B pagesIndicatorNormalColor_ = ccc4(180, 180, 180, 255);
      ccColor4B pagesIndicatorSelectedColor_ = ccc4(255, 255, 255, 255);
      if (showPagesIndicator)
      {
          int totalScreens = iPageCount;
  
          // Prepare Points Array
          CGFloat n = (CGFloat)totalScreens; //&lt; Total points count in CGFloat.
          CGFloat pY = pageIndicatorPosition.y; //&lt; Points y-coord in parent coord sys.
          CGFloat d = ph_pad(16.0f, 16.0f * 2); //&lt; Distance between points.
          CGPoint points[totalScreens];
          for (int i=0; i &lt; totalScreens; ++i)
          {
              CGFloat pX = pageIndicatorPosition.x + d * ( (CGFloat)i - 0.5f*(n-1.0f) );
              points[i] = ccp (pX, pY);
          }
  
          // Set GL Values
  #if COCOS2D_VERSION &gt;= 0x00020000
  //        ccGLEnable(CC_GL_BLEND);
          ccPointSize( ph_pad(5.0 * CC_CONTENT_SCALE_FACTOR(), 5.0 * CC_CONTENT_SCALE_FACTOR() * 2) );
  #define DRAW_4B_FUNC ccDrawColor4B
  
  #else
          glEnable(GL_POINT_SMOOTH);
          GLboolean blendWasEnabled = glIsEnabled( GL_BLEND );
          glEnable(GL_BLEND);
  
          // save the old blending functions
          int blend_src = 0;
          int blend_dst = 0;
          glGetIntegerv( GL_BLEND_SRC, &amp;blend_src );
          glGetIntegerv( GL_BLEND_DST, &amp;blend_dst );
          glPointSize( ph_pad(5.0 * CC_CONTENT_SCALE_FACTOR(), 5.0 * CC_CONTENT_SCALE_FACTOR() * 2) );
  
  #define DRAW_4B_FUNC glColor4ub
  
  #endif
          ccGLBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  //        glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
  
          // Draw Gray Points
          DRAW_4B_FUNC(pagesIndicatorNormalColor_.r,
                       pagesIndicatorNormalColor_.g,
                       pagesIndicatorNormalColor_.b,
                       pagesIndicatorNormalColor_.a);
  
          ccDrawPoints( points, totalScreens );
  
          // Draw White Point for Selected Page
          DRAW_4B_FUNC(pagesIndicatorSelectedColor_.r,
                       pagesIndicatorSelectedColor_.g,
                       pagesIndicatorSelectedColor_.b,
                       pagesIndicatorSelectedColor_.a);
          ccDrawPoint(points[iCurrentPage]);
  
          // Restore GL Values
  #if COCOS2D_VERSION &gt;= 0x00020000
          ccPointSize(1.0f);
  #else
          glPointSize(1.0f);
          glDisable(GL_POINT_SMOOTH);
          if (! blendWasEnabled)
              glDisable(GL_BLEND);
  
          // always restore the blending functions too
          ccGLBlendFunc( blend_src, blend_dst);
  //        glBlendFunc( blend_src, blend_dst );
  #endif
      }
  }
  
  
  
  
  @end
  </code></pre>
  
  <p>The source code is from Brandon Reynolds and I have modified it a bit to better suit my game. I use this 5 methods to easily build menus for packs (single row, multi columns) and levels (multi rows, multi columns)</p>
  
  <pre><code>-(int) getTotalPage;
  -(int) getCurrentPage;
  -(void) moveToPage: (int) page animated: (BOOL) animated;
  +(id) packWithArray: (NSMutableArray*) items posY: (int) posY indicatorPosY: (int) indiPosY;
  +(id) levelWithArray: (NSMutableArray*) items cols: (int) cols rows: (int) rows leftEdge: (int) leftEdge upperEdge: (int) upperEdge lowerEdge: (int) lowerEdge indicatorPosY: (int) indiPosY;
  </code></pre>
  
  <p>But the open gl code is not working anymore for cocos2d 3.0 (e.g. <code>ccGLBlendFunc</code> etc). How can I update this class for cocos2d 3.x? Or any new implementation for similar menu grid? </p>