Cocos2d-x 点击菜单按键居中放大(无需修改底层代码)

建议转至该处阅读 https://www.zybuluo.com/tangyikejun/note/21953

配置环境:win7+Cocos2d-x.2.0.3+VS2012
目标读者:已经了解Cocos2d-x中的坐标系统,精灵和图片的关系。并知道OOP中类和对象的关系。

 

目标

实现一个按键效果,按下去之前显示normal.png的图,按下去之后显示selected.png的图。selected.png尺寸大于normal.png。效果图如下:

效果图

 

正文

 

1、原始效果

笔者在这个问题上纠结了一天半,尝试了各种方法,一直以为是自己错误使用菜单类导致不能居中放大。之后查看了源码,源码用两个精灵保存前后两张图片,并设置其锚点为(0,0),因此按键前后的图片都是以左下角点为原点绘制,无法到达居中放大的效果。

默认绘制效果图

 

2、类间关系

我们先罗列出绘制一个按键所涉及的类,CCMenu、CCMenuItemSprite、CCSprite。它们在结点树上依次是爷爷、父亲、儿子的关系,当然你也可以认为是外婆、母亲、女儿的关系,随便。上述三个类中,CCMenu和CCSprite的锚点坐标都是(0,0),CCMenuItemSprite的锚点为(0.5,0.5),不建议更改这一默认设置。默认设定CCMenuItemSprite的大小和CCSprite的大小一致。当你没有抚摸屏幕的时候界面是这样的:

无按键时类间布局关系;

在这个图中,只对CCMenuItemSprite的位置进行了设置,其他对象的位置都是默认值。可以看到CCMenu对象的默认位置(position)为(0,0)。CCSprite的位置与CCMenuItemSprite的位置一致,即CCSprite的位置默认也是(0,0)。

 

3、解决方案

接下来我们通过实际的例子来讨论,本例中一些类和对象的关系如下表:

对象对应图片
CCSprite pNormalSprite normal.png
CCSprite pSelectedSprite selected.png
CCMenuItemSprite pCloseItem

现在我们只把注意力放在CCMenuItemSprite和CCSprite这两个类上。对于本例,pNormalSprite和pSelectedSprite两个对象的默认锚点和位置均为(0,0),也就是说均以pCloseItem的左下角点作为原点。为了达到中心放大的目的,只需要重新设置pSelectedSprite的位置即可,见下图伪代码:

第二张精灵位置计算

 

4、实现

具体的代码如下,直接在HelloWorld工程中的HelloWorld::init()函数中修改即可查看效果(当然要先把图放进去!)。

 
//start//////////////////下面这些代码都是通用的///////////////

/*新建按键前后两个精灵*/
CCSprite *pNormalSprite = CCSprite::create("normal.png");
CC_BREAK_IF(!pNormalSprite);

CCSprite *pSelectedSprite = CCSprite::create("selected.png");
CC_BREAK_IF(!pSelectedSprite);


/*计算两张图片的dW,dH*/
float dW = pNormalSprite->getContentSize().width
        - pSelectedSprite->getContentSize().width;
float dH = pNormalSprite->getContentSize().height
        - pSelectedSprite->getContentSize().height;
        
        
/*设置pSelectedSprite的位置*/        
pSelectedSprite->setPosition(ccp(dW / 2.0f,dH / 2.0f));


/*把精灵添加到菜单项pCloseItem中*/
CCMenuItemSprite *pCloseItem = CCMenuItemSprite::create(pNormalSprite,pSelectedSprite,this,menu_selector(HelloWorld::menuCloseCallback));
CC_BREAK_IF(!pCloseItem);
//end////////////////////////////////////////////////////////

/*设置菜单项的位置。*/
pCloseItem->setPosition(ccp(100,100));

/*添加菜单项到菜单*/
CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
pMenu->setPosition(CCPointZero);
CC_BREAK_IF(! pMenu);
        
// Add the menu to HelloWorld layer as a child layer.
this->addChild(pMenu, 1);

5、更进一步

上述代码虽然解决了中心放大的问题,但是仍存在一些缺陷。Cocos2d-x引擎处理后,pCloseItem对象的尺寸(content size)与pNormalSprite的尺寸是一样大的。即pSelected的尺寸 大于 pCloseItem对象的尺寸。当我们需要根据菜单项的大小来确定位置的时候,上面这种设置就会出现问题,比如我想把菜单项放在屏幕的左下角,如果直接将位置设置为

pCloseItem->setPosition(ccp(w/2,h/2));//w,h分别是从pCloseItem获得的宽和高

那么菜单项被按下后selected图片会超出屏幕。
要解决这个问题需要两个步骤:
1、pSelectedSprite保持默认位置,而对pNormalSprite的位置进行设置。
2、将pCloseItem对象的尺寸设置为pSelectedSprite的尺寸。

例子:

CCSprite *pNormalSprite = CCSprite::create(path);       //path为图片路径
CCSprite *pSelectedSprite = CCSprite::create(path);

//得到dW和dH
float dW = pSelectedSprite->getContentSize().width - pNormalSprite->getContentSize().width; 
float dH = pSelectedSprite->getContentSize().height - pNormalSprite->getContentSize().height;

//更改位置
pNormalSprite->setPosition(ccp(dW / 2.0f,dH / 2.0f));

//将菜单项的contentSize设置为selectedSprite对象的大小
CCMenuItemSprite *pItemSprite = CCMenuItemSprite::create(pNormalSprite,pSelectedSprite,this,menu_selector(MainScene::onMenuEnd));

CCSize size = pSelectedSprite->getContentSize();
pItemSprite->setContentSize(size);

本文疏漏错误之处,欢迎大家指正!从而对博文不断改进,更好地为大家服务!

转载请注明出处:

http://www.cnblogs.com/tangyikejun/p/3842000.html 

https://www.zybuluo.com/tangyikejun/note/21953




知识共享许可协议
作者:tangyikejun
本文采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

原文地址:https://www.cnblogs.com/tangyikejun/p/3842000.html