当前位置 : 主页 > 网络编程 > 其它编程 >

cocos2d-x学习笔记-CCMenu和CCMenuItem详解

来源:互联网 收集:自由互联 发布时间:2023-07-02
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的子类,用来渲染文字标签的,可以指定字体,每次设置字符串内容时都需要重新创建纹理和渲染,性能不好,可以看它的相关源码:

    [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

    上一篇:❤️hadoop必知必会的基本知识❤️
    下一篇:没有了
    网友评论