Cocos2d中的Menu使用
学习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使用的更多相关文章
- 在活动中使用Menu
1.在res下创建menu普通文件夹,在menu下创建名为main的Menu资源文件 2.在menu组件下创建item组件:资源id,title标题名称 3.覆盖活动中的onCreateOptions ...
- cocos2d中的可见性检测
游戏的在进行一次渲染的时候,通常会提交大量的渲染对象给gpu.在这些需要渲染的对象中,并不是所有对象都会出现镜头中,即有一部分对象是不可见的. 通常有两种方式来完成不可见对象的剔除工作: (1)直接交 ...
- Cocos2d 中的Sprite大小调整问题
以前用UIImageView,比如 UIImageView *view = [[UIImageViewalloc] initWithImage:[UIImageimageNamed:@"b ...
- cocos2d 中判断CGPoint或者CGSize是否相等
cocos2d 中判断CGPoint是否相等 调用CGPointEqualToPoint(point1, point2) 判断CGSize是否相等 调用CGSizeEqualToSize(size1, ...
- 利用HTML 5中的Menu和Menuitem元素快速创建菜单
原文:Introducing the HTML5 “Menu” and “Menuitem” Elements 译文:HTML 5中Menu和Menuitem的元素介绍 译者:dwqs 今天向你介绍H ...
- cocos2d中如何使用图片纹理图集的加载来实现一个动画的功能
cocos2d中要实现一个动画,一般采用纹理图集的方式,也就是说把几个连续动作的图片挨个显示切换这样就是动画 一: 首先先看下今天要实现的具体的目的,打飞机的时间屏幕上会有一个喷火的小飞机,飞机的尾部 ...
- Cocos2D中节点Z序的计算规则
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交 ...
- Cocos2D中Action的进阶使用技巧(一)
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 大家对Cocos2d中动作的使用大概都很清楚了,其实本身act ...
- Cocos2D中Node的userObject实例变量使用时一个要注意的地方
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们知道在Cocos2D中,CCNode对象有一个ivar为us ...
随机推荐
- oracle on linux 巡检脚本-部分
#!/bin/sh #ocpyang@126.com #Modified according to the actual situation mysql server IP and username ...
- Codefroces 832B Petya and Exam
B. Petya and Exam time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...
- 基于jQuery的一组图片的滚动
css: .displayB{display:block;}.fl{float:left;}.fr{float: right;}.posAb{position: absolute;}.posRe{po ...
- 【2017"百度之星"程序设计大赛 - 初赛(A)】度度熊的01世界
[链接]http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=775&pid=1006 [题意] 在这里写题意 [题 ...
- 洛谷 P1480 A/B Problem
P1480 A/B Problem 题目描述 输入两个整数a,b,输出它们的商(a<=10^5000,b<=10^9) 输入输出格式 输入格式: 两行,第一行是被除数,第二行是除数. 输出 ...
- CF #261 div2 D. Pashmak and Parmida's problem (树状数组版)
Parmida is a clever girl and she wants to participate in Olympiads this year. Of course she wants he ...
- fromCharCode vs chr
fromCharCode vs chr echo off set "fn=%*" set php=d:/www/php5/php.exe cls echo. %php% %fn% ...
- theme-windowAnimationStyle 动画设置
对于windowAnimationStyle 的引用,目前自己发现的有两处 1.就是直接在Theme 中引用的,如下 <style name="Theme.Funui" pa ...
- C++ 中的异或操作^
好好的利用异或能够产生奇妙的效果. 异或运算的性质: 不论什么一个数字异或它自己都等于0.也就是说.假设我们从头到尾依次异或数组中的每个数字,那么终于的结果刚好是那个仅仅出现一次的数字.由于那些出现两 ...
- [AngularJS] Interpolation fail in IE 11
When you occured this problem, check few things: For the input field, use // Use ng-attr-placeholder ...