cocos2d-x 六(界面控件之MenuItem)

无论是PC应用还是移动应用,必不可少的元素之一就是控件,对用户来说它们被用于用户与应用的交互,对应用本身来说它们被用于应用各个功能框架的交互。cocos2d-x里的控件包含的种类很多,这里记录的是最常用的控件类CCMenuItem。对于为什么将一个看上去更像是按钮控件的东西被命名为Menu,我是着实纠结了一小会儿,现在看来也许是因为cocos2d-x用的是节点(Node)来存储控制各个对象,所以更适合叫MenuItem而不是Button……

官方原例里有个MenuTest,里面演示了一些风格化的MenuItem。查看这个类的源码可以看到其下衍生出了一堆子类控件,其中最眼熟的就是CCMenuItemImage,这玩意就是新建一个工程时就被默认建立的那个右下角用于关闭应用的“电源”按钮:

// Create a "close" menu item with close icon, it's an auto release object.
        CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
            "CloseNormal.png",
            "CloseSelected.png",
            this,
            menu_selector(HelloWorld::menuCloseCallback));
        CC_BREAK_IF(! pCloseItem);

        // Place the menu item bottom-right conner.
        pCloseItem->setPosition(ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20));

        // Create a menu with the "close" menu item, it's an auto release object.
        CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
        pMenu->setPosition(CCPointZero);
        CC_BREAK_IF(! pMenu);

        // Add the menu to HelloWorld layer as a child layer.
        this->addChild(pMenu, 1);

上面的代码注释得很清楚了,使用流程就是先创建一个控件对象实例,再创建一个CCMenu实例,这东西其实继承的是CCLayer下的子类CCLayerRGBA,说白了就是个“层”,创建时用作为层的pMenu装载这个控件,最后加入到场景中。像这样的控件当然也会有几种创建方式,上例用的是包含了两种状态(普通和按下状态)的图片,并且点击时会执行一个回调函数,其它的具体可以看源代码。

第二种常用的就是切换状态或者参数时用的“切换按钮”CCMenuItemToggle,这样的控件常用在游戏设置上。不过我倒觉得这东西更像是个ListBox,因为可以在创建切换按钮时加入N个切换选项,当然,也可以动态添加/删除其中的选项,只是不会有下拉列表就是了,下面是官方原例中抽取出来的代码:

CCMenuItemToggle *item4 = CCMenuItemToggle::createWithTarget(this, 
                                                                menu_selector(MenuLayer4::menuCallback), 
                                                                CCMenuItemFont::create( "Off" ), 
                                                                NULL );
    
    //UxArray* more_items = UxArray::arrayWithObjects(
    //                                                 CCMenuItemFont::create( "33%" ),
    //                                                 CCMenuItemFont::create( "66%" ),
    //                                                 CCMenuItemFont::create( "100%" ),
    //                                                 NULL );
    // TIP: you can manipulate the items like any other CCMutableArray
    //有没觉得很像在添加ListItem
    item4->getSubItems()->addObject( CCMenuItemFont::create( "33%" ) ); 
    item4->getSubItems()->addObject( CCMenuItemFont::create( "66%" ) ); 
    item4->getSubItems()->addObject( CCMenuItemFont::create( "100%" ) ); 
    
    // you can change the one of the items by doing this
    item4->setSelectedIndex( 2 );
    
    CCMenuItemFont::setFontName( "Marker Felt" );
    CCMenuItemFont::setFontSize( 34 );
    
    CCLabelBMFont *label = CCLabelBMFont::create( "go back", "fonts/bitmapFontTest3.fnt" );
    CCMenuItemLabel* back = CCMenuItemLabel::create(label, this, menu_selector(MenuLayer4::backCallback) );
    
    CCMenu *menu = CCMenu::create(
                  title1, title2,
                  item1, item2,
                  title3, title4,
                  item3, item4,
                  back, NULL ); // 9 items.
  //这里设定了个表格式的对齐格式分出了四行2列,最后一行1列,分别对应于上面menu中添加的切换按钮  
    menu->alignItemsInColumns(2, 2, 2, 2, 1, NULL);
    
    addChild( menu );
	

	
这些控件也可以跑动画的,下面是官方原例里抽出的CCMenuItemFont的一个闪烁动画代码:
    // Font Item
    CCMenuItemFont* item8 = CCMenuItemFont::create("Quit", this, menu_selector(MenuLayerMainMenu::onQuit));
    
    CCMenuItemFont* item9 = CCMenuItemFont::create("Remove menu item when moving", this,
                                                   menu_selector(MenuLayerMainMenu::menuMovingCallback));
    
    CCActionInterval* color_action = CCTintBy::create(0.5f, 0, -255, -255);
    CCActionInterval* color_back = color_action->reverse();
    CCSequence* seq = CCSequence::create(color_action, color_back, NULL);
    item8->runAction(CCRepeatForever::create(seq));

    CCMenu* menu = CCMenu::create( item1, item2, item3, item4, item5, item6, item7, item8, item9, NULL);
    menu->alignItemsVertically();