Search code examples
cocos2d-x

How to make a sliding menu in cocos2dx in c++ for IOS game


I want to make a sliding menu just like the level menu in which on one screen there will be 40 sprites labelled as level 1 level 2 respectively up to 40. At the bottom right there will be another sprite with a arrow to which when I click it should slide to other screen and show the levels 41 to 80.Please provide me with a basic concept how to use it.I will be thankful to you. Note: I am using Xcode and ony want solution in cocos2d-x using c++


Solution

  • This is the way I have done this in the past...I had a game with the option for the player to select multiple space ships, 4 per page, with back/forward arrows on each page as well.

    Create a CCScene derived class.

    Place all your menu items, including the control arrows for ALL pages on it. You will have to space all the items so the items for the first page are on the visible part of the screen and the next group is 100% off to the right, the third group is 200% off the right, etc.

    The control buttons on the scene start an action to move the layer 100% to the left (if they move right) or 100% to the right (if they move left).

    All of these are attached to a single "Menu", which is what the actions are applied against. If you want, you can put the menu into a layer (so it has background that moves). This is up to you.

    In the example Scene below, I just used a simple menu.

    MainScene.h

    #ifndef __MainScene__
    #define __MainScene__
    
    #include "cocos2d.h"
    
    using namespace cocos2d;
    
    
    class MainScene : public CCScene
    {
    private:
       // This class follows the "create"/"autorelease" pattern.
       // Private constructor.
       MainScene();
       CCMenu* _menu;
       bool _sliding;
       void MenuCallback(CCObject* sender);
       void PageLeft();
       void PageRight();
       void SlidingDone();
    
    protected:
       // This is protected so that derived classes can call it
       // in their create methods.
       bool init();
    
    private:
       void CreateMenu();
    
    public:
    
       static MainScene* create();
    
       ~MainScene();
    
       virtual void onEnter();
       virtual void onExit();
       virtual void onEnterTransitionDidFinish();
       virtual void onExitTransitionDidStart();
    
    };
    
    
    #endif /* defined(__MainScene__) */
    

    MainScene.cpp

    #include "MainScene.h"
    
    #define ARROW_LEFT (-1)
    #define ARROW_RIGHT (-2)
    
    #define MENU_ITEMS_ACROSS 4
    #define MENU_ITEMS_DOWN 5
    #define MENU_ITEMS_PAGE (MENU_ITEMS_ACROSS*MENU_ITEMS_DOWN)
    #define MENU_ITEMS_TOTAL 50
    
    #define MENU_PAGES ((MENU_ITEMS_TOTAL/MENU_ITEMS_PAGE)+1)
    #define MENU_FRACTION (ccp(0.8,0.8))
    #define MENU_ANCHOR (ccp(0.5,0.5))
    
    #define SLIDE_DURATION 1.0
    
    MainScene::MainScene() :
       _menu(NULL)
       _sliding(false)
    {
    }
    
    MainScene::~MainScene()
    {
    }
    
    static CCPoint CalculatePosition(int itemNum)
    {
       CCSize scrSize = CCDirector::sharedDirector()->getWinSize();
       float Xs = scrSize.width;
       float Ys = scrSize.height;
       int gRows = MENU_ITEMS_DOWN;
       int gCols = MENU_ITEMS_ACROSS;
       int gBins = gRows*gCols;
       float Xb = MENU_FRACTION.x*Xs/gCols;
       float Yb = MENU_FRACTION.y*Ys/gRows;
       float Xa = MENU_ANCHOR.x * Xs;
       float Ya = MENU_ANCHOR.y * Ys;
       int page = itemNum / gBins;
    
       int binCol = itemNum % gCols;
       int binRow = (itemNum-page*gBins) / gCols;
    
       float xPos = binCol * Xb + Xb/2 + Xa - MENU_FRACTION.x*Xs/2 + page * Xs;
       float yPos = Ya - binRow*Yb - Yb/2 + MENU_FRACTION.y * Ys/2;
    
       CCPoint pos = ccp(xPos,yPos);
    
       return pos;
    }
    
    void MainScene::CreateMenu()
    {
       if(_menu == NULL)
       {
          CCSize scrSize = CCDirector::sharedDirector()->getWinSize();
    
          _menu = CCMenu::create();
          _menu->setPosition(ccp(0,0));
          addChild(_menu);
    
    
          CCMenuItemFont* pItem;
          CCPoint position;
    
          // Create the next/back menu items.
          for(int page = 0; page < MENU_PAGES; page++)
          {
             // Create the Back/Forward buttons for the page.
             // Back arrow if there is a previous page.
             if(page > 0)
             {
                pItem = CCMenuItemFont::create("Back", this, menu_selector(MainScene::MenuCallback));
                pItem->setTag(ARROW_LEFT);
                position = ccp(page*scrSize.width + scrSize.width*0.1,scrSize.height*0.1);
                pItem->setPosition(position);
                pItem->setFontSize(35);
                pItem->setFontName("Arial");
                _menu->addChild(pItem);
             }
             if(page < (MENU_PAGES-1))
             {
                pItem = CCMenuItemFont::create("Next", this, menu_selector(MainScene::MenuCallback));
                pItem->setTag(ARROW_RIGHT);
                position = ccp(page*scrSize.width + scrSize.width*0.9,scrSize.height*0.1);
                pItem->setPosition(position);
                pItem->setFontSize(35);
                pItem->setFontName("Arial");
                _menu->addChild(pItem);
             }
          }
          // Create the actual items
          for(int idx = 0; idx < MENU_ITEMS_TOTAL; idx++)
          {
             char buffer[256];
             sprintf(buffer,"Item #%d",idx);
             pItem = CCMenuItemFont::create(buffer, this, menu_selector(MainScene::MenuCallback));
             pItem->setFontSize(35);
             pItem->setFontName("Arial");
             pItem->setTag(idx);
             position = CalculatePosition(idx);
             pItem->setPosition(position);
             _menu->addChild(pItem);
    
          }
       }
    }
    
    
    bool MainScene::init()
    {
    
       return true;
    }
    
    MainScene* MainScene::create()
    {
       MainScene *pRet = new MainScene();
       if (pRet && pRet->init())
       {
          pRet->autorelease();
          return pRet;
       }
       else
       {
          CC_SAFE_DELETE(pRet);
          return NULL;
       }
    }
    
    void MainScene::onEnter()
    {
       CCScene::onEnter();
       CreateMenu();
    }
    
    void MainScene::onExit()
    {
       CCScene::onExit();
    }
    
    void MainScene::onEnterTransitionDidFinish()
    {
       CCScene::onEnterTransitionDidFinish();
    }
    
    void MainScene::onExitTransitionDidStart()
    {
       CCScene::onExitTransitionDidStart();
    
    }
    
    void MainScene::SlidingDone()
    {
       _sliding = false;
    }
    
    void MainScene::PageLeft()
    {
       if(_sliding)
          return;
       _sliding = true;
       CCSize scrSize = CCDirector::sharedDirector()->getWinSize();
       CCFiniteTimeAction* act1 = CCMoveBy::create(SLIDE_DURATION, ccp(scrSize.width,0));
       CCFiniteTimeAction* act2 = CCCallFunc::create(this, callfunc_selector(MainScene::SlidingDone));
       _menu->runAction(CCSequence::create(act1,act2,NULL));
    }
    
    void MainScene::PageRight()
    {
       if(_sliding)
          return;
       _sliding = true;
       CCSize scrSize = CCDirector::sharedDirector()->getWinSize();
       CCFiniteTimeAction* act1 = CCMoveBy::create(SLIDE_DURATION, ccp(-scrSize.width,0));
       CCFiniteTimeAction* act2 = CCCallFunc::create(this, callfunc_selector(MainScene::SlidingDone));
       _menu->runAction(CCSequence::create(act1,act2,NULL));
    }
    
    void MainScene::MenuCallback(CCObject* sender)
    {
       // This is a very contrived example
       // for handling the menu items.
       // -1 ==> Left Arrow
       // -2 ==> Right Arrow
       // Anything else is a selection
       CCMenuItem* pMenuItem = (CCMenuItem*)sender;
       switch(pMenuItem->getTag())
       {
          case ARROW_LEFT:
             PageLeft();
             break;
          case ARROW_RIGHT:
             PageRight();
             break;
          default:
             CCLOG("Got Item %d Pressed",pMenuItem->getTag());
             break;
       }
    }
    

    Note The formulas for getting the items spread across several pages can be a little tricky. There is a notion of "Screen fraction", which is how much the grid of items takes up on the page. There is also the notion of "menu anchor", which where on the page you want the grid to be.

    Some screen shots

    enter image description here

    enter image description here