学习cocos2d-x中的菜单主要须要了解:菜单(CCMenu)和菜单项(CCMenuItem)以及CCMenuItem的详细子类。

a. 以下来学习一下相关的类。
1. CCMenu
菜单,是CCLayer的子类,是一个层(容器),能够往里面加入菜单项。以下是它的类结构图:

 

CCMenu默认接受触屏事件的优先级是-128(优先级非常高,由于值越小,响应触屏事件的优先级越高),能够通过继承它实现自己定义的效果,创建CCMenu对象的函数:

static CCMenu* menuWithItems(CCMenuItem* item, ...);
static CCMenu* menuWithItem(CCMenuItem* item);

2. CCMenuItem
菜单项,开发中通常是直接使用它的子类。CCMenuItem有三个直接子类:
CCMenuItemLabel(字符标签菜单)、CCMenuItemSprite(图片菜单)、CCMenuItemToggle(开关菜单)。
以下是CCMenuItem的类结构图:

 

如今分别来了解一下各个不同的菜单项。

(1) CCMenuItemLabel:使用文字标签创建菜单项
全部支持CCLabelProtocol的节点都能够用来创建CCMenuItemLabel。CCLabelProtocol是标签的共同接口。CCLabelProtocol也有三个直接子类,以下是类结构图:

 

CCLabelTTF:同一时候也是CCSprite的子类,用来渲染文字标签的,能够指定字体。每次设置字符串内容时都须要又一次创建纹理和渲染,性能不好。能够看它的相关源代码:

void CCLabelTTF::setString(const char *label)
{
if (m_pString)
{
delete m_pString;
m_pString = NULL;
}
m_pString = new std::string(label); CCTexture2D *texture;
if( CCSize::CCSizeEqualToSize( m_tDimensions, CCSizeZero ) )
{
texture = new CCTexture2D();
texture->initWithString(label, m_pFontName->c_str(), m_fFontSize);
}
else
{
texture = new CCTexture2D();
texture->initWithString(label, m_tDimensions, m_eAlignment, m_pFontName->c_str(), m_fFontSize);
}
this->setTexture(texture);
texture->release(); CCRect rect = CCRectZero;
rect.size = m_pobTexture->getContentSize();
this->setTextureRect(rect);
}

能够用CCLabelBMFont或者CCLabelAtlas取代它。
CCLabelBMFont:也是CCSpriteBatchNode的子类,创建CCLabelBMFont对象须要一个字符串和一个fnt格式的文件(字库),如:

CCLabelBMFont *label = CCLabelBMFont::labelWithString("Bitmap Font Atlas", "fonts/bitmapFontTest.fnt");

这个fnt文件包括了这些信息:相应图片的名字(图片包括了全部你要绘制的字符)、图片中的字符相应的unicode编码、字符在图片中的坐标、宽高等。初始化CCLabelBMFont对象时,会把图片加入到缓存(CCTextureCache)中。解析fnt文件,把fnt文件里相应的信息保存到一个ccBMFontDef类型的数组里面,数组的索引是charId(字符的unicode编码值),ccBMFontDef是一个结构体:

typedef struct _BMFontDef {
//! ID of the character
unsigned int charID;
//! origin and size of the font
CCRect rect;
//! The X amount the image should be offset when drawing the image (in pixels)
int xOffset;
//! The Y amount the image should be offset when drawing the image (in pixels)
int yOffset;
//! The amount to move the current position after drawing the character (in pixels)
int xAdvance;
} ccBMFontDef;

绘制字符串时,依据字符相应的unicode码去查找ccBMFontDef信息,从缓存中取出图片。再依据ccBMFontDef中坐标、宽高取出相应区域的字符图片,把字符在字符串中的索引位置作为tag加入到CCLabelBMFont中。由于CCLabelBMFont本身是CCSpriteBatchNode。这样就实现了批处理渲染精灵,提高了性能。以下是创建字符相应的CCSprite的部分代码:

void CCLabelBMFont::createFontChars()
{
/** .... */
//以下代码是遍历字符串时:for循环内的代码
const ccBMFontDef& fontDef = (*(m_pConfiguration->m_pBitmapFontArray))[c]; CCRect rect = fontDef.rect; CCSprite *fontChar; fontChar = (CCSprite*)(this->getChildByTag(i));
if( ! fontChar )
{
fontChar = new CCSprite();
fontChar->initWithBatchNodeRectInPixels(this, rect);
this->addChild(fontChar, 0, i);
fontChar->release();
}
else
{
// reusing fonts
fontChar->setTextureRectInPixels(rect, false, rect.size); // restore to default in case they were modified
fontChar->setIsVisible(true);
fontChar->setOpacity(255);
} /** .... */
}

CCLabelAtlas:也是CCAtlasNode的子类,创建一个CCLabelAtlas对象的代码例如以下:

static CCLabelAtlas * labelWithString(const char *label, const char *charMapFile, unsigned int itemWidth, unsigned int itemHeight, unsigned char startCharMap);
//演示样例
CCLabelAtlas* label1 = CCLabelAtlas::labelWithString("123 Test", "fonts/tuffy_bold_italic-charmap.png", 48, 64, ' ');

參数的含义:要绘制的字符,图片文件,图片文件里每一个字符的宽度。图片文件里每一个字符的高度,图片的起始字符。
CCAtlasNode封装了一个CCTextureAtlas的变量。CCTextureAtlas初始化图片文件的时候会把图片载入到缓存(CCTextureCache)中:

bool CCTextureAtlas::initWithFile(const char * file, unsigned int capacity)
{
// retained in property
CCTexture2D *texture = CCTextureCache::sharedTextureCache()->addImage(file); if (texture)
{
return initWithTexture(texture, capacity);
}
else
{
CCLOG("cocos2d: Could not open file: %s", file);
delete this; return NULL;
}
}

接下来CCTextureAtlas负责管理该大图。能够任意绘制图片的某一矩形区域,渲染方式採用的是OpenGL ES VBO(顶点缓冲对象。保存在显存中)。 CCTextureAtlas有一个m_pQuads属性,它是CCTextureAtlas类的核心。是一个ccV3F_C4B_T2F_Quad类型的数组,ccV3F_C4B_T2F_Quad是一个结构体,有四个成员属性。它们都是ccV3F_C4B_T2F类,分别表示左上。左下,右上,右下。看源代码:

//! a Point with a vertex point, a tex coord point and a color 4B
typedef struct _ccV3F_C4B_T2F
{
//! vertices (3F)
ccVertex3F vertices; // 12 bytes
// char __padding__[4]; //! colors (4B)
ccColor4B colors; // 4 bytes
// char __padding2__[4]; // tex coords (2F)
ccTex2F texCoords; // 8 byts
} ccV3F_C4B_T2F; //! 4 ccVertex2FTex2FColor4B Quad
typedef struct _ccV2F_C4B_T2F_Quad
{
//! bottom left
ccV2F_C4B_T2F bl;
//! bottom right
ccV2F_C4B_T2F br;
//! top left
ccV2F_C4B_T2F tl;
//! top right
ccV2F_C4B_T2F tr;
} ccV2F_C4B_T2F_Quad;

ccV3F_C4B_T2F有三个成员,分别表示:顶点、颜色、纹理坐标。
CCTextureAtlas类就是依据这个数组来绘制矩形的,数组的容量就是要绘制的字符数量。指定字符串的时候:是依据指定字符的ASCII码值跟startCharMap(图片起始字符)ASCII码值的偏移量。得到该字符在图片上的区域的。然后生成绘制矩形所须要的数据,源代码:

//CCLabelAtlas - CCLabelProtocol
void CCLabelAtlas::setString(const char *label)
{
/** .... */
this->updateAtlasValues(); /** .... */
} //CCLabelAtlas - Atlas generation
void CCLabelAtlas::updateAtlasValues()
{
unsigned int n = m_sString.length(); ccV3F_C4B_T2F_Quad quad; const unsigned char *s = (unsigned char*)m_sString.c_str(); CCTexture2D *texture = m_pTextureAtlas->getTexture();
float textureWide = (float) texture->getPixelsWide();
float textureHigh = (float) texture->getPixelsHigh(); for(unsigned int i = 0; i < n; i++) {
unsigned char a = s[i] - m_cMapStartChar;
float row = (float) (a % m_uItemsPerRow);
float col = (float) (a / m_uItemsPerRow); #if CC_FIX_ARTIFACTS_BY_STRECHING_TEXEL
// Issue #938. Don't use texStepX & texStepY
float left = (2 * row * m_uItemWidth + 1) / (2 * textureWide);
float right = left + (m_uItemWidth * 2 - 2) / (2 * textureWide);
float top = (2 * col * m_uItemHeight + 1) / (2 * textureHigh);
float bottom = top + (m_uItemHeight * 2 - 2) / (2 * textureHigh);
#else
float left = row * m_uItemWidth / textureWide;
float right = left + m_uItemWidth / textureWide;
float top = col * m_uItemHeight / textureHigh;
float bottom = 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(&quad, i); }
}

所以图片上的字符排列顺序要依照ASCII码表的顺序连续排列。CCLabelAtlas的绘制效率高,可是限制性太多,没有CCLabelBMFont灵活。

从类结构图能够看到CCMenuItemLabel有两个子类CCMenuItemAtlasFont和CCMenuItemFont。CCMenuItemAtlasFont是使用CCLabelAtlas创建MenuItemLabel的辅助类,CCMenuItemFont是使用CCLabelTTF创建MenuItemLabel的辅助类。例如以下源代码所看到的:

bool CCMenuItemAtlasFont::initFromString(const char *value, const char *charMapFile, int itemWidth, int itemHeight, char startCharMap, CCObject* target, SEL_MenuHandler selector)
{
CCAssert( value != NULL && strlen(value) != 0, "value length must be greater than 0");
CCLabelAtlas *label = new CCLabelAtlas();
label->initWithString(value, charMapFile, itemWidth, itemHeight, startCharMap);
label->autorelease();
if (CCMenuItemLabel::initWithLabel(label, target, selector))
{
// do something ? }
return true;
} bool CCMenuItemFont::initFromString(const char *value, CCObject* target, SEL_MenuHandler selector)
{
CCAssert( value != NULL && strlen(value) != 0, "Value length must be greater than 0"); m_strFontName = _fontName;
m_uFontSize = _fontSize; CCLabelTTF *label = CCLabelTTF::labelWithString(value, m_strFontName.c_str(), (float)m_uFontSize);
if (CCMenuItemLabel::initWithLabel(label, target, selector))
{
// do something ? }
return true;
}

2. CCMenuItemSprite和CCMenuItemImage:本质上都是使用图片创建菜单项,前者是使用精灵对象创建,后者使用图片名称创建。CCMenuItemImage是CCMenuItemSprite的子类。能够使用三套图片:未选中状态、选中状态、不可用状态。前面两种状态的图片是必需的,不可用状态的图片可选。例如以下代码所看到的:

static CCMenuItemSprite * itemFromNormalSprite(CCNode* normalSprite, CCNode* selectedSprite, CCNode* disabledSprite = NULL);

static CCMenuItemImage* itemFromNormalImage(const char *normalImage, const char *selectedImage);
static CCMenuItemImage* itemFromNormalImage(const char *normalImage, const char *selectedImage, const char *disabledImage);

3. CCMenuItemToggle: 开关菜单
它是一个容器,能够切换包括的子项(能够是不论什么的MenuItem对象)。

它封装了一个CCMutableArray<CCMenuItem*>*类型的属性m_pSubItems。代码演示样例:

static CCMenuItemToggle* itemWithTarget(CCObject* target, SEL_MenuHandler selector, CCMenuItem* item, ...);        

CCMenuItemToggle* item1 = CCMenuItemToggle::itemWithTarget(this,menu_selector(MenuLayer4::menuCallback),
CCMenuItemFont::itemFromString( "On" ),
CCMenuItemFont::itemFromString( "Off"),NULL );

b. 分析了菜单的各个相关类的原理和使用方法后。如今来看看怎样使用它们,以下演示样例代码整合了各种菜单项的创建:

void MenuLayer::onEnter()
{
CCLayer::onEnter();
CCSize winSize = CCDirector::sharedDirector()->getWinSize(); /**---CCMenuItemLabel:由指定的字符串标签创建菜单--**/
//CCMenuItemFont:内部使用CCLabelTTF
CCMenuItemFont::setFontName("Arial");
CCMenuItemFont::setFontSize(22);
CCMenuItemFont* pFontMenuItem = CCMenuItemFont::itemFromString("font item", 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);
}

Cocos2d中的Menu使用的更多相关文章

  1. 在活动中使用Menu

    1.在res下创建menu普通文件夹,在menu下创建名为main的Menu资源文件 2.在menu组件下创建item组件:资源id,title标题名称 3.覆盖活动中的onCreateOptions ...

  2. cocos2d中的可见性检测

    游戏的在进行一次渲染的时候,通常会提交大量的渲染对象给gpu.在这些需要渲染的对象中,并不是所有对象都会出现镜头中,即有一部分对象是不可见的. 通常有两种方式来完成不可见对象的剔除工作: (1)直接交 ...

  3. Cocos2d 中的Sprite大小调整问题

    以前用UIImageView,比如  UIImageView *view = [[UIImageViewalloc] initWithImage:[UIImageimageNamed:@"b ...

  4. cocos2d 中判断CGPoint或者CGSize是否相等

    cocos2d 中判断CGPoint是否相等 调用CGPointEqualToPoint(point1, point2) 判断CGSize是否相等 调用CGSizeEqualToSize(size1, ...

  5. 利用HTML 5中的Menu和Menuitem元素快速创建菜单

    原文:Introducing the HTML5 “Menu” and “Menuitem” Elements 译文:HTML 5中Menu和Menuitem的元素介绍 译者:dwqs 今天向你介绍H ...

  6. cocos2d中如何使用图片纹理图集的加载来实现一个动画的功能

    cocos2d中要实现一个动画,一般采用纹理图集的方式,也就是说把几个连续动作的图片挨个显示切换这样就是动画 一: 首先先看下今天要实现的具体的目的,打飞机的时间屏幕上会有一个喷火的小飞机,飞机的尾部 ...

  7. Cocos2D中节点Z序的计算规则

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交 ...

  8. Cocos2D中Action的进阶使用技巧(一)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 大家对Cocos2d中动作的使用大概都很清楚了,其实本身act ...

  9. Cocos2D中Node的userObject实例变量使用时一个要注意的地方

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们知道在Cocos2D中,CCNode对象有一个ivar为us ...

随机推荐

  1. Resource Access Based on Multiple Credentials

    A collection of multiple user credentials each associated with one of multiple different users is ob ...

  2. 洛谷 P1881 绳子对折

    P1881 绳子对折 题目描述 FJ 有一个长度为L(1<= L <= 10,000)的绳子. 这个绳子上有N(1 <= N <= 100)个结,包括两个端点. FJ想将绳子对 ...

  3. HDU 5188 zhx and contest(带限制条件的 01背包)

    Problem Description As one of the most powerful brushes in the world, zhx usually takes part in all ...

  4. android图片特效处理之怀旧效果

    图片特效处理系列将介绍图片的像素点的特效处理,这些物资注重的是原理.也就是说只要你知道这些算法不管是C++,VB,C#,Java都可以做出相同的特效.下面将介绍图片怀旧效果的算法.算法如下: 上面公式 ...

  5. IAR for STM8介绍、下载、安装与注册--转

    Ⅰ.写在前面 本文讲述的内容是IAR for STM8的介绍.下载.安装与注册,其安装.注册过程和IAR for ARM类似,如果需要了解IAR for ARM相关的文章,可以到我博客,或微信公众号查 ...

  6. 数组&对象

    一.遍历数组的几种方式   var arr = [1,2,3]; Array.prototype.test=function(){} arr.name='jq'   1. for  /* * inde ...

  7. VMware Tools安装问题的解决

    一.VMware Tools工具的作用 VMware虚拟机的插件工具,安装上它可以实现主机与虚拟机的文件共享及拖放.简单的说就是从Ubuntu上边经常输入命令行会出现错误的情况,需要复制到Window ...

  8. git还原本地提交的某个历史记录

    转载地址:http://jingyan.baidu.com/article/e4511cf33479812b855eaf67.html 1.以还原index2.html文件为例,打开index2.ht ...

  9. 洛谷 P1724 东风谷早苗

    P1724 东风谷早苗 题目描述 在幻想乡,东风谷早苗是以高达控闻名的高中生宅巫女.某一天,早苗终于入手了最新款的钢达姆模型.作为最新的钢达姆,当然有了与以往不同的功能了,那就是它能够自动行走,厉害吧 ...

  10. python 命令行參数解析

    本文是从我还有一个博客转载过来的,欢迎大家点击进去看一下,帮我添加点人气^_^ ImPyy 选择模块 依据python參考手冊的提示,optparse 已经废弃,应使用 argparse 教程 概念 ...