http://blog.csdn.net/zhoujianghai/article/details/8145015
学习cocos2d-x中的菜单主要需要了解:菜单(Ccmenu)和菜单项(CcmenuItem)以及CcmenuItem的具体子类。
a. 下面来学习一下相关的类。
1. Ccmenu
菜单,是cclayer的子类,是一个层(容器),可以往里面添加菜单项。下面是它的类结构图:
Ccmenu默认接受触屏事件的优先级是-128(优先级很高,因为值越小,响应触屏事件的优先级越高),可以通过继承它实现自定义的效果,创建Ccmenu对象的函数:
[cpp] view plain copy staticCcmenu*menuWithItems(CcmenuItem*item,...); staticCcmenu*menuWithItem(CcmenuItem*item);
2. CcmenuItem
菜单项,开发中一般是直接使用它的子类。CcmenuItem有三个直接子类:
CcmenuItemLabel(字符标签菜单)、CcmenuItemSprite(图片菜单)、CcmenuItemToggle(开关菜单)。
下面是CcmenuItem的类结构图:
现在分别来了解一下各个不同的菜单项。
(1) CcmenuItemLabel:使用文字标签创建菜单项
所有支持cclabelProtocol的节点都可以用来创建CcmenuItemLabel,cclabelProtocol是标签的共同接口。cclabelProtocol也有三个直接子类,下面是类结构图:
cclabelTTF:同时也是CCSprite的子类,用来渲染文字标签的,可以指定字体,每次设置字符串内容时都需要重新创建纹理和渲染,性能不好,可以看它的相关源码:
可以用cclabelBMFont或者cclabelAtlas代替它。
cclabelBMFont :也是CCSpriteBatchNode的子类,创建cclabelBMFont对象需要一个字符串和一个fnt格式的文件(字库),如: copy cclabelBMFont*label=cclabelBMFont::labelWithString("BitmapFontAtlas","Fonts/bitmapFontTest.fnt");
这个fnt文件包含了这些信息:对应图片的名字(图片包含了所有你要绘制的字符)、图片中的字符对应的unicode编码、字符在图片中的坐标、宽高等。初始化cclabelBMFont对象时,会把图片添加到缓存(CCTextureCache)中,解析fnt文件,把fnt文件中对应的信息保存到一个ccBMFontDef类型的数组里面,数组的索引是charID(字符的unicode编码值),ccBMFontDef是一个结构体: copy typedefstruct_BMFontDef{ //!IDofthecharacter unsignedintcharID; //!originandsizeoftheFont CCRectrect; //!TheXamounttheimageshouldbeoffsetwhendrawingtheimage(inpixels) intxOffset; //!Theyamounttheimageshouldbeoffsetwhendrawingtheimage(inpixels) intyOffset; //!Theamounttomovethecurrentpositionafterdrawingthecharacter(inpixels) intxAdvance; }ccBMFontDef;
绘制字符串时,根据字符对应的unicode码去查找ccBMFontDef信息,从缓存中取出图片,再根据ccBMFontDef中坐标、宽高取出对应区域的字符图片,把字符在字符串中的索引位置作为tag添加到cclabelBMFont中,因为cclabelBMFont本身是CCSpriteBatchNode,这样就实现了批处理渲染精灵,提高了性能。下面是创建字符对应的CCSprite的部分代码: copy 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对象的代码如下: copy 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)中: copy 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类,分别表示左上,左下,右上,右下。看源码: copy //!aPointwithavertexpoint,atexcoordpointandacolor4B struct_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 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码值的偏移量,得到该字符在图片上的区域的,然后生成绘制矩形所需要的数据,源码: copy //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的辅助类。如下源码所示:
copy 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的子类。可以使用三套图片:未选中状态、选中状态、不可用状态,前面两种状态的图片是必需的,不可用状态的图片可选。如下代码所示: copy 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。代码示例: copy 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);
程序使用的图片素材:
cclabelBMFont代码段使用的素材是:cocos2d-x安装目录/tests/Resources/Fonts/bitmapFontTest3.fnt和对应的png文件
ps:CcmenuItem默认使用的字体是Marker Felt,字体大小是32,在CcmenuItem.h中定义了:
copy #definekCCItemSize32 staticunsignedint_FontSize=kCCItemSize; staticstd::string_Fontname="MarkerFelt";转载请注明来自:Alex Zhou,本文链接:http://codingnow.cn/android/832.html 总结
以上是内存溢出为你收集整理的cocos2d-x学习笔记-CCMenu和CCMenuItem详解全部内容,希望文章能够帮你解决cocos2d-x学习笔记-CCMenu和CCMenuItem详解所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)