http:blog.csdn.netzhoujianghaiarticledetails8145015学习cocos2d-x中的菜单主要需要了解:菜单(CCMenu)和菜单项(CCMenu http://blog.csdn.net/zhoujianghai/article/details/8145015 学习cocos2d-x中的菜单主要需要了解:菜单
           
        
        http:blog.csdn.netzhoujianghaiarticledetails8145015学习cocos2d-x中的菜单主要需要了解:菜单(CCMenu)和菜单项(CCMenu                                                                                         
http://blog.csdn.net/zhoujianghai/article/details/8145015
学习cocos2d-x中的菜单主要需要了解:菜单(CCMenu)和菜单项(CCMenuItem)以及CCMenuItem的具体子类。a. 下面来学习一下相关的类。1. CCMenu
菜单,是CCLayer的子类,是一个层(容器),可以往里面添加菜单项。下面是它的类结构图:

CCMenu默认接受触屏事件的优先级是-128(优先级很高,因为值越小,响应触屏事件的优先级越高),可以通过继承它实现自定义的效果,创建CCMenu对象的函数:
[cpp]view plaincopy   
staticCCMenu*menuWithItems(CCMenuItem*item,...);  staticCCMenu*menuWithItem(CCMenuItem*item); 2. CCMenuItem菜单项,开发中一般是直接使用它的子类。CCMenuItem有三个直接子类:CCMenuItemLabel(字符标签菜单)、CCMenuItemSprite(图片菜单)、CCMenuItemToggle(开关菜单)。下面是CCMenuItem的类结构图:

现在分别来了解一下各个不同的菜单项。(1) CCMenuItemLabel:使用文字标签创建菜单项所有支持CCLabelProtocol的节点都可以用来创建CCMenuItemLabel,CCLabelProtocol是标签的共同接口。CCLabelProtocol也有三个直接子类,下面是类结构图:
 CCLabelTTF:同时也是CCSprite的子类,用来渲染文字标签的,可以指定字体,每次设置字符串内容时都需要重新创建纹理和渲染,性能不好,可以看它的相关源码:
CCLabelTTF:同时也是CCSprite的子类,用来渲染文字标签的,可以指定字体,每次设置字符串内容时都需要重新创建纹理和渲染,性能不好,可以看它的相关源码:
[cpp]view plaincopy   
voidCCLabelTTF::setString(constchar*label)  {  if(m_pString)  {  deletem_pString;  m_pString=NULL;  }  m_pString=newstd::string(label);    CCTexture2D*texture;  if(CCSize::CCSizeEqualToSize(m_tDimensions,CCSizeZero))  {  texture=newCCTexture2D();  texture->initWithString(label,m_pFontName->c_str(),m_fFontSize);  }  else  {  texture=newCCTexture2D();  texture->initWithString(label,m_tDimensions,m_eAlignment,m_pFontName->c_str(),m_fFontSize);  }  this->setTexture(texture);  texture->release();    CCRectrect=CCRectZero;  rect.size=m_pobTexture->getContentSize();  this->setTextureRect(rect);  } 可以用CCLabelBMFont或者CCLabelAtlas代替它。CCLabelBMFont:也是CCSpriteBatchNode的子类,创建CCLabelBMFont对象需要一个字符串和一个fnt格式的文件(字库),如:[cpp]view plaincopy   
CCLabelBMFont*label=CCLabelBMFont::labelWithString("BitmapFontAtlas","fonts/bitmapFontTest.fnt"); 这个fnt文件包含了这些信息:对应图片的名字(图片包含了所有你要绘制的字符)、图片中的字符对应的unicode编码、字符在图片中的坐标、宽高等。初始化CCLabelBMFont对象时,会把图片添加到缓存(CCTextureCache)中,解析fnt文件,把fnt文件中对应的信息保存到一个ccBMFontDef类型的数组里面,数组的索引是charId(字符的unicode编码值),ccBMFontDef是一个结构体:[cpp]view plaincopy   
typedefstruct_BMFontDef{  //!IDofthecharacter  unsignedintcharID;  //!originandsizeofthefont  CCRectrect;  //!TheXamounttheimageshouldbeoffsetwhendrawingtheimage(inpixels)  intxOffset;  //!TheYamounttheimageshouldbeoffsetwhendrawingtheimage(inpixels)  intyOffset;  //!Theamounttomovethecurrentpositionafterdrawingthecharacter(inpixels)  intxAdvance;  }ccBMFontDef; 绘制字符串时,根据字符对应的unicode码去查找ccBMFontDef信息,从缓存中取出图片,再根据ccBMFontDef中坐标、宽高取出对应区域的字符图片,把字符在字符串中的索引位置作为tag添加到CCLabelBMFont中,因为CCLabelBMFont本身是CCSpriteBatchNode,这样就实现了批处理渲染精灵,提高了性能。下面是创建字符对应的CCSprite的部分代码:[cpp]view plaincopy   
voidCCLabelBMFont::createFontChars()  {  /**....*/  //以下代码是遍历字符串时:for循环内的代码  constccBMFontDef    CCRectrect=fontDef.rect;    CCSprite*fontChar;    fontChar=(CCSprite*)(this->getChildByTag(i));  if(!fontChar)  {  fontChar=newCCSprite();  fontChar->initWithBatchNodeRectInPixels(this,rect);  this->addChild(fontChar,0,i);  fontChar->release();  }  else  {  //reusingfonts  fontChar->setTextureRectInPixels(rect,false,rect.size);    //restoretodefaultincasetheyweremodified  fontChar->setIsVisible(true);  fontChar->setOpacity(255);  }    /**....*/  } CCLabelAtlas:也是CCAtlasNode的子类,创建一个CCLabelAtlas对象的代码如下:[cpp]view plaincopy   
staticCCLabelAtlas*labelWithString(constchar*label,constchar*charMapFile,unsignedintitemWidth,unsignedintitemHeight,unsignedcharstartCharMap);  //示例  CCLabelAtlas*label1=CCLabelAtlas::labelWithString("123Test","fonts/tuffy_bold_italic-charmap.png",48,64,''); 参数的含义:要绘制的字符,图片文件,图片文件中每个字符的宽度,图片文件中每个字符的高度,图片的起始字符。CCAtlasNode封装了一个CCTextureAtlas的变量,CCTextureAtlas初始化图片文件的时候会把图片加载到缓存(CCTextureCache)中:[cpp]view plaincopy   
boolCCTextureAtlas::initWithFile(constchar*file,unsignedintcapacity)  {  //retainedinproperty  CCTexture2D*texture=CCTextureCache::sharedTextureCache()->addImage(file);    if(texture)  {  returninitWithTexture(texture,capacity);  }  else  {  CCLOG("cocos2d:Couldnotopenfile:%s",file);  deletethis;    returnNULL;  }  } 接下来CCTextureAtlas负责管理该大图,可以随意绘制图片的某一矩形区域,渲染方式采用的是OpenGL ES VBO(顶点缓冲对象,保存在显存中)。 CCTextureAtlas有一个m_pQuads属性,它是CCTextureAtlas类的核心,是一个ccV3F_C4B_T2F_Quad类型的数组,ccV3F_C4B_T2F_Quad是一个结构体,有四个成员属性,它们都是ccV3F_C4B_T2F类,分别表示左上,左下,右上,右下。看源码:[cpp]view plaincopy   
//!aPointwithavertexpoint,atexcoordpointandacolor4B  typedefstruct_ccV3F_C4B_T2F  {  //!vertices(3F)  ccVertex3Fvertices;//12bytes  //char__padding__[4];    //!colors(4B)  ccColor4Bcolors;//4bytes  //char__padding2__[4];    //texcoords(2F)  ccTex2FtexCoords;//8byts  }ccV3F_C4B_T2F;    //!4ccVertex2FTex2FColor4BQuad  typedefstruct_ccV2F_C4B_T2F_Quad  {  //!bottomleft  ccV2F_C4B_T2Fbl;  //!bottomright  ccV2F_C4B_T2Fbr;  //!topleft  ccV2F_C4B_T2Ftl;  //!topright  ccV2F_C4B_T2Ftr;  }ccV2F_C4B_T2F_Quad; ccV3F_C4B_T2F有三个成员,分别表示:顶点、颜色、纹理坐标。CCTextureAtlas类就是根据这个数组来绘制矩形的,数组的容量就是要绘制的字符数量。指定字符串的时候:是根据指定字符的ASCII码值跟startCharMap(图片起始字符)ASCII码值的偏移量,得到该字符在图片上的区域的,然后生成绘制矩形所需要的数据,源码:[cpp]view plaincopy   
//CCLabelAtlas-CCLabelProtocol  voidCCLabelAtlas::setString(constchar*label)  {  /**....*/  this->updateAtlasValues();    /**....*/  }    //CCLabelAtlas-Atlasgeneration  voidCCLabelAtlas::updateAtlasValues()  {  unsignedintn=m_sString.length();    ccV3F_C4B_T2F_Quadquad;    constunsignedchar*s=(unsignedchar*)m_sString.c_str();    CCTexture2D*texture=m_pTextureAtlas->getTexture();  floattextureWide=(float)texture->getPixelsWide();  floattextureHigh=(float)texture->getPixelsHigh();    for(unsignedinti=0;i  unsignedchara=s[i]-m_cMapStartChar;  floatrow=(float)(a%m_uItemsPerRow);  floatcol=(float)(a/m_uItemsPerRow);    #ifCC_FIX_ARTIFACTS_BY_STRECHING_TEXEL  //Issue#938.Don'tusetexStepX  floatright=left+(m_uItemWidth*2-2)/(2*textureWide);  floattop=(2*col*m_uItemHeight+1)/(2*textureHigh);  floatbottom=top+(m_uItemHeight*2-2)/(2*textureHigh);  #else  floatleft=row*m_uItemWidth/textureWide;  floatright=left+m_uItemWidth/textureWide;  floattop=col*m_uItemHeight/textureHigh;  floatbottom=top+m_uItemHeight/textureHigh;  #endif//!CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL    quad.tl.texCoords.u=left;  quad.tl.texCoords.v=top;  quad.tr.texCoords.u=right;  quad.tr.texCoords.v=top;  quad.bl.texCoords.u=left;  quad.bl.texCoords.v=bottom;  quad.br.texCoords.u=right;  quad.br.texCoords.v=bottom;    quad.bl.vertices.x=(float)(i*m_uItemWidth);  quad.bl.vertices.y=0;  quad.bl.vertices.z=0.0f;  quad.br.vertices.x=(float)(i*m_uItemWidth+m_uItemWidth);  quad.br.vertices.y=0;  quad.br.vertices.z=0.0f;  quad.tl.vertices.x=(float)(i*m_uItemWidth);  quad.tl.vertices.y=(float)(m_uItemHeight);  quad.tl.vertices.z=0.0f;  quad.tr.vertices.x=(float)(i*m_uItemWidth+m_uItemWidth);  quad.tr.vertices.y=(float)(m_uItemHeight);  quad.tr.vertices.z=0.0f;    m_pTextureAtlas->updateQuad(    }  } 所以图片上的字符排列顺序要按照ASCII码表的顺序连续排列。CCLabelAtlas的绘制效率高,但是限制性太多,没有CCLabelBMFont灵活。
从类结构图可以看到CCMenuItemLabel有两个子类CCMenuItemAtlasFont和CCMenuItemFont,CCMenuItemAtlasFont是使用CCLabelAtlas创建MenuItemLabel的辅助类,CCMenuItemFont是使用CCLabelTTF创建MenuItemLabel的辅助类。如下源码所示:
[cpp]view plaincopy   boolCCMenuItemAtlasFont::initFromString(constchar*value,constchar*charMapFile,intitemWidth,intitemHeight,charstartCharMap,CCObject*target,SEL_MenuHandlerselector)  {  CCAssert(value!=NULL  CCLabelAtlas*label=newCCLabelAtlas();  label->initWithString(value,charMapFile,itemWidth,itemHeight,startCharMap);  label->autorelease();  if(CCMenuItemLabel::initWithLabel(label,target,selector))  {  //dosomething?  }  returntrue;  }    boolCCMenuItemFont::initFromString(constchar*value,CCObject*target,SEL_MenuHandlerselector)  {  CCAssert(value!=NULL    m_strFontName=_fontName;  m_uFontSize=_fontSize;    CCLabelTTF*label=CCLabelTTF::labelWithString(value,m_strFontName.c_str(),(float)m_uFontSize);  if(CCMenuItemLabel::initWithLabel(label,target,selector))  {  //dosomething?  }  returntrue;  } 2. CCMenuItemSprite和CCMenuItemImage:本质上都是使用图片创建菜单项,前者是使用精灵对象创建,后者使用图片名称创建,CCMenuItemImage是CCMenuItemSprite的子类。可以使用三套图片:未选中状态、选中状态、不可用状态,前面两种状态的图片是必需的,不可用状态的图片可选。如下代码所示:[cpp]view plaincopy   staticCCMenuItemSprite*itemFromNormalSprite(CCNode*normalSprite,CCNode*selectedSprite,CCNode*disabledSprite=NULL);    staticCCMenuItemImage*itemFromNormalImage(constchar*normalImage,constchar*selectedImage);  staticCCMenuItemImage*itemFromNormalImage(constchar*normalImage,constchar*selectedImage,constchar*disabledImage); 3. CCMenuItemToggle: 开关菜单它是一个容器,可以切换包含的子项(可以是任何的MenuItem对象)。它封装了一个CCMutableArray*类型的属性m_pSubItems。代码示例:[cpp]view plaincopy   staticCCMenuItemToggle*itemWithTarget(CCObject*target,SEL_MenuHandlerselector,CCMenuItem*item,...);    CCMenuItemToggle*item1=CCMenuItemToggle::itemWithTarget(this,menu_selector(MenuLayer4::menuCallback),  CCMenuItemFont::itemFromString("On"),  CCMenuItemFont::itemFromString("Off"),NULL); b. 分析了菜单的各个相关类的原理和用法后,现在来看看如何使用它们,下面示例代码整合了各种菜单项的创建:[cpp]view plaincopy   voidMenuLayer::onEnter()  {  CCLayer::onEnter();  CCSizewinSize=CCDirector::sharedDirector()->getWinSize();    /**---CCMenuItemLabel:由指定的字符串标签创建菜单--**/  //CCMenuItemFont:内部使用CCLabelTTF  CCMenuItemFont::setFontName("Arial");  CCMenuItemFont::setFontSize(22);  CCMenuItemFont*pFontMenuItem=CCMenuItemFont::itemFromString("fontitem",this,menu_selector(MenuLayer::menuCallback));  CCMenu*pFontMenu=CCMenu::menuWithItems(pFontMenuItem,NULL);  pFontMenu->setPosition(ccp(winSize.width/2,winSize.height-30));  this->addChild(pFontMenu);    //CCMenuItemAtlasFont:内部使用CCLabelAtlas  CCMenuItemAtlasFont*pAtlasFontMenuItem=CCMenuItemAtlasFont::itemFromString("123456789",s_imgPathNum,15,19,'0',this,menu_selector(MenuLayer::menuCallback));  CCMenu*pAtlasFontMenu=CCMenu::menuWithItems(pAtlasFontMenuItem,NULL);  pAtlasFontMenu->setPosition(ccp(winSize.width/2,winSize.height-60));  this->addChild(pAtlasFontMenu);    //CCLabelBMFont  CCLabelBMFont*pBMFontLabel=CCLabelBMFont::labelWithString("configuration",s_imgPathBMFont);  CCMenuItemLabel*pItemBMFontLabel=CCMenuItemLabel::itemWithLabel(pBMFontLabel,this,menu_selector(MenuLayer::menuCallback));  CCMenu*pBMFontMenu=CCMenu::menuWithItems(pItemBMFontLabel,NULL);  pBMFontMenu->setPosition(ccp(winSize.width/2,winSize.height-90));  this->addChild(pBMFontMenu);    /**--CCMenuItemSprite:由指定的精灵类创建菜单--**/  CCSprite*spriteNormal=CCSprite::spriteWithFile(s_imgPathMenuItem,CCRectMake(0,23*2,115,23));  CCSprite*spriteSelected=CCSprite::spriteWithFile(s_imgPathMenuItem,CCRectMake(0,23*1,115,23));  CCSprite*spriteDisabled=CCSprite::spriteWithFile(s_imgPathMenuItem,CCRectMake(0,23*0,115,23));  CCMenuItemSprite*pMenuItemSprite=CCMenuItemSprite::itemFromNormalSprite(spriteNormal,spriteSelected,spriteDisabled,this,menu_selector(MenuLayer::menuCallback));  CCMenu*pSpriteMenu=CCMenu::menuWithItems(pMenuItemSprite,NULL);  pSpriteMenu->setPosition(ccp(winSize.width/2,winSize.height-120));  this->addChild(pSpriteMenu);    //CCMenuItemImage:由指定的图片文件名创建菜单  CCMenuItemImage*pMenuItemImage=CCMenuItemImage::itemFromNormalImage(s_imgPathCloseNormal,s_imgPathCloseSelected,this,menu_selector(MenuLayer::menuCallback));  CCMenu*pImageMenu=CCMenu::menuWithItem(pMenuItemImage);  pImageMenu->setPosition(ccp(winSize.width/2,winSize.height-150));  this->addChild(pImageMenu);    //CCMenuItemToggle:开关菜单,切换效果  //这里只使用了CCMenuItemFont,还可以使用其他的CCMenuItem  CCMenuItemToggle*pMenuItemToggle=CCMenuItemToggle::itemWithTarget(this,menu_selector(MenuLayer::menuCallback),  CCMenuItemFont::itemFromString("On"),  CCMenuItemFont::itemFromString("Off"),  NULL);  CCMenu*pToggleMenu=CCMenu::menuWithItems(pMenuItemToggle,NULL);  pToggleMenu->setPosition(ccp(winSize.width/2,winSize.height-180));  this->addChild(pToggleMenu);  } 运行效果如下:
程序使用的图片素材:


CCLabelBMFont代码段使用的素材是:cocos2d-x安装目录/tests/Resources/fonts/bitmapFontTest3.fnt和对应的png文件
ps:CCMenuItem默认使用的字体是Marker Felt,字体大小是32,在CCMenuItem.h中定义了:
[cpp]view plaincopy   #definekCCItemSize32  staticunsignedint_fontSize=kCCItemSize;  staticstd::string_fontName="MarkerFelt"; 转载请注明来自:Alex Zhou,本文链接:http://codingnow.cn/android/832.html