http://blog.csdn.net/zhoujianghai/article/details/8145015
学习cocos2d-x中的菜单主要需要了解:菜单(CCMenu)和菜单项(CCMenuItem)以及CCMenuItem的具体子类。 a. 下面来学习一下相关的类。 1. CCMenu
菜单,是CCLayer的子类,是一个层(容器),可以往里面添加菜单项。下面是它的类结构图:
CCMenu默认接受触屏事件的优先级是-128(优先级很高,因为值越小,响应触屏事件的优先级越高),可以通过继承它实现自定义的效果,创建CCMenu对象的函数:
- staticCCMenu*menuWithItems(CCMenuItem*item,...);
- staticCCMenu*menuWithItem(CCMenuItem*item);
2. CCMenuItem 菜单项,开发中一般是直接使用它的子类。CCMenuItem有三个直接子类: CCMenuItemLabel(字符标签菜单)、CCMenuItemSprite(图片菜单)、CCMenuItemToggle(开关菜单)。 下面是CCMenuItem的类结构图:
现在分别来了解一下各个不同的菜单项。 (1) CCMenuItemLabel:使用文字标签创建菜单项 所有支持CCLabelProtocol的节点都可以用来创建CCMenuItemLabel,CCLabelProtocol是标签的共同接口。CCLabelProtocol也有三个直接子类,下面是类结构图:
CCLabelTTF:同时也是CCSprite的子类,用来渲染文字标签的,可以指定字体,每次设置字符串内容时都需要重新创建纹理和渲染,性能不好,可以看它的相关源码:
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_fFontSize);
- }
- this->setTexture(texture);
- texture->release();
- CCRectrect=CCRectZero;
- rect.size=m_pobTexture->getContentSize();
- this->setTextureRect(rect);
- }
可以用CCLabelBMFont或者CCLabelAtlas代替它。
CCLabelBMFont
:也是CCSpriteBatchNode的子类,创建CCLabelBMFont对象需要一个字符串和一个fnt格式的文件(字库),如:
CCLabelBMFont*label=CCLabelBMFont::labelWithString("BitmapFontAtlas","fonts/bitmapFontTest.fnt");
这个fnt文件包含了这些信息:对应图片的名字(图片包含了所有你要绘制的字符)、图片中的字符对应的unicode编码、字符在图片中的坐标、宽高等。初始化CCLabelBMFont对象时,会把图片添加到缓存(CCTextureCache)中,解析fnt文件,把fnt文件中对应的信息保存到一个ccBMFontDef类型的数组里面,数组的索引是charId(字符的unicode编码值),ccBMFontDef是一个结构体:
typedefstruct_BMFontDef{
-
- unsignedintcharID;
- //!originandsizeofthefont
- CCRectrect;
- //!TheXamounttheimageshouldbeoffsetwhendrawingtheimage(inpixels)
- intxOffset;
- //!TheYamounttheimageshouldbeoffsetwhendrawingtheimage(inpixels)
- intyOffset;
- //!Theamounttomovethecurrentpositionafterdrawingthecharacter(inpixels)
- intxAdvance;
- }ccBMFontDef;
绘制字符串时,根据字符对应的unicode码去查找ccBMFontDef信息,从缓存中取出图片,再根据ccBMFontDef中坐标、宽高取出对应区域的字符图片,把字符在字符串中的索引位置作为tag添加到CCLabelBMFont中,因为CCLabelBMFont本身是CCSpriteBatchNode,这样就实现了批处理渲染精灵,提高了性能。下面是创建字符对应的CCSprite的部分代码:
voidCCLabelBMFont::createFontChars()
-
- //以下代码是遍历字符串时:for循环内的代码
- constccBMFontDef&fontDef=(*(m_pConfiguration->m_pBitmapFontArray))[c];
-
- CCRectrect=fontDef.rect;
- CCSprite*fontChar;
- fontChar=(CCSprite*)(this->getChildByTag(i));
- if(!fontChar)
- fontChar=newCCSprite();
- fontChar->initWithBatchNodeRectInPixels(this,rect);
- this->addChild(fontChar,i);
- fontChar->release();
- else
- //reusingfonts
- fontChar->setTextureRectInPixels(rect,false,rect.size);
- //restoretodefaultincasetheyweremodified
- fontChar->setIsVisible(true);
- fontChar->setOpacity(255);
- }
CCLabelAtlas
:也是CCAtlasNode的子类,创建一个CCLabelAtlas对象的代码如下:
staticCCLabelAtlas*labelWithString(char*label,char*charMapFile,unsignedintitemWidth,87); background-color:inherit; font-weight:bold">intitemHeight,87); background-color:inherit; font-weight:bold">charstartCharMap);
- //示例
- CCLabelAtlas*label1=CCLabelAtlas::labelWithString("123Test","fonts/tuffy_bold_italic-charmap.png",48,64,'');
参数的含义:要绘制的字符,图片文件,图片文件中每个字符的宽度,图片文件中每个字符的高度,图片的起始字符。
CCAtlasNode封装了一个CCTextureAtlas的变量,CCTextureAtlas初始化图片文件的时候会把图片加载到缓存(CCTextureCache)中:
boolCCTextureAtlas::initWithFile(char*file,87); background-color:inherit; font-weight:bold">intcapacity)
- //retainedinproperty
- CCTexture2D*texture=CCTextureCache::sharedTextureCache()->addImage(file);
- if(texture)
- returninitWithTexture(texture,capacity);
- 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类,分别表示左上,左下,右上,右下。看源码:
//!aPointwithavertexpoint,atexcoordpointandacolor4B
- struct_ccV3F_C4B_T2F
- //!vertices(3F)
- ccVertex3Fvertices;
- //char__padding__[4];
- //!colors(4B)
- ccColor4Bcolors;
- //char__padding2__[4];
- //texcoords(2F)
- ccTex2FtexCoords;
- }ccV3F_C4B_T2F;
- //!4ccVertex2FTex2FColor4BQuad
- struct_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码值的偏移量,得到该字符在图片上的区域的,然后生成绘制矩形所需要的数据,源码:
//CCLabelAtlas-CCLabelProtocol
- voidCCLabelAtlas::setString(char*label)
- /**....*/
- this->updateAtlasValues();
- //CCLabelAtlas-Atlasgeneration
- voidCCLabelAtlas::updateAtlasValues()
- intn=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<n;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&texStepY
- floatleft=(2*row*m_uItemWidth+1)/(2*textureWide);
- 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=( quad.tl.vertices.y=(float)(m_uItemHeight);
- quad.tl.vertices.z=0.0f;
- quad.tr.vertices.x=( quad.tr.vertices.y=(float)(m_uItemHeight);
- quad.tr.vertices.z=0.0f;
- m_pTextureAtlas->updateQuad(&quad,i);
-
所以图片上的字符排列顺序要按照ASCII码表的顺序连续排列。CCLabelAtlas的绘制效率高,但是限制性太多,没有CCLabelBMFont灵活。
从类结构图可以看到CCMenuItemLabel有两个子类CCMenuItemAtlasFont和CCMenuItemFont,CCMenuItemAtlasFont是使用CCLabelAtlas创建MenuItemLabel的辅助类,CCMenuItemFont是使用CCLabelTTF创建MenuItemLabel的辅助类。如下源码所示:
boolCCMenuItemAtlasFont::initFromString(char*value,charstartCharMap,CCObject*target,SEL_MenuHandlerselector)
- CCAssert(value!=NULL&&strlen(value)!=0,"valuelengthmustbegreaterthan0");
- CCLabelAtlas*label=newCCLabelAtlas();
- label->initWithString(value,charMapFile,itemWidth,itemHeight,startCharMap);
- label->autorelease();
- if(CCMenuItemLabel::initWithLabel(label,target,selector))
- //dosomething?
- returntrue;
- boolCCMenuItemFont::initFromString( CCAssert(value!=NULL&&strlen(value)!=0,"Valuelengthmustbegreaterthan0");
- m_strFontName=_fontName;
- m_uFontSize=_fontSize;
- CCLabelTTF*label=CCLabelTTF::labelWithString(value,m_strFontName.c_str(),(float)m_uFontSize);
- //dosomething?
- true;
- }
2. CCMenuItemSprite和CCMenuItemImage
:本质上都是使用图片创建菜单项,前者是使用精灵对象创建,后者使用图片名称创建,CCMenuItemImage是CCMenuItemSprite的子类。可以使用三套图片:未选中状态、选中状态、不可用状态,前面两种状态的图片是必需的,不可用状态的图片可选。如下代码所示:
staticCCMenuItemSprite*itemFromNormalSprite(CCNode*normalSprite,CCNode*selectedSprite,CCNode*disabledSprite=NULL);
- staticCCMenuItemImage*itemFromNormalImage(char*normalImage,87); background-color:inherit; font-weight:bold">char*selectedImage);
- char*selectedImage,87); background-color:inherit; font-weight:bold">char*disabledImage);
3. CCMenuItemToggle
: 开关菜单
它是一个容器,可以切换包含的子项(可以是任何的MenuItem对象)。它封装了一个CCMutableArray<CCMenuItem*>*类型的属性m_pSubItems。代码示例:
staticCCMenuItemToggle*itemWithTarget(CCObject*target,SEL_MenuHandlerselector,CCMenuItem*item,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> CCMenuItemToggle*item1=CCMenuItemToggle::itemWithTarget( CCMenuItemFont::itemFromString("On"),
- CCMenuItemFont::itemFromString("Off"),NULL);
b. 分析了菜单的各个相关类的原理和用法后,现在来看看如何使用它们,下面示例代码整合了各种菜单项的创建:
voidMenuLayer::onEnter()
- CCLayer::onEnter();
- CCSizewinSize=CCDirector::sharedDirector()->getWinSize();
- /**---CCMenuItemLabel:由指定的字符串标签创建菜单--**/
- //CCMenuItemFont:内部使用CCLabelTTF
- CCMenuItemFont::setFontName("Arial");
- CCMenuItemFont::setFontSize(22);
- CCMenuItemFont*pFontMenuItem=CCMenuItemFont::itemFromString("fontitem",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',108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> CCMenu*pAtlasFontMenu=CCMenu::menuWithItems(pAtlasFontMenuItem,248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> 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,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,23*1,23));
- CCSprite*spriteDisabled=CCSprite::spriteWithFile(s_imgPathMenuItem,23*0,248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> CCMenuItemSprite*pMenuItemSprite=CCMenuItemSprite::itemFromNormalSprite(spriteNormal,spriteSelected,spriteDisabled,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> CCMenu*pSpriteMenu=CCMenu::menuWithItems(pMenuItemSprite,248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> pSpriteMenu->setPosition(ccp(winSize.width/2,winSize.height-120));
- this->addChild(pSpriteMenu);
- //CCMenuItemImage:由指定的图片文件名创建菜单
- CCMenuItemImage*pMenuItemImage=CCMenuItemImage::itemFromNormalImage(s_imgPathCloseNormal,s_imgPathCloseSelected,108); list-style:decimal-leading-zero outside; color:inherit; line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> CCMenu*pImageMenu=CCMenu::menuWithItem(pMenuItemImage);
- pImageMenu->setPosition(ccp(winSize.width/2,winSize.height-150));
- this->addChild(pImageMenu);
- //CCMenuItemToggle:开关菜单,切换效果
- //这里只使用了CCMenuItemFont,还可以使用其他的CCMenuItem
- CCMenuItemToggle*pMenuItemToggle=CCMenuItemToggle::itemWithTarget( NULL);
- CCMenu*pToggleMenu=CCMenu::menuWithItems(pMenuItemToggle,248); line-height:18px; margin:0px!important; padding:0px 3px 0px 10px!important"> 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中定义了:
#definekCCItemSize32
- staticunsignedint_fontSize=kCCItemSize;
- staticstd::string_fontName="MarkerFelt";
转载请注明来自:Alex Zhou,本文链接:http://codingnow.cn/android/832.html (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|