[关闭]
@tangyikejun 2014-08-09T00:16:05.000000Z 字数 3063 阅读 4300

Cocos2d-x 点击菜单按键居中放大


已发布

配置环境: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()函数中修改即可查看效果(当然要先把图放进去!)。

  1. //start//////////////////下面这些代码都是通用的///////////////
  2. /*新建按键前后两个精灵*/
  3. CCSprite *pNormalSprite = CCSprite::create("normal.png");
  4. CC_BREAK_IF(!pNormalSprite);
  5. CCSprite *pSelectedSprite = CCSprite::create("selected.png");
  6. CC_BREAK_IF(!pSelectedSprite);
  7. /*计算两张图片的dW,dH*/
  8. float dW = pNormalSprite->getContentSize().width
  9. - pSelectedSprite->getContentSize().width;
  10. float dH = pNormalSprite->getContentSize().height
  11. - pSelectedSprite->getContentSize().height;
  12. /*设置pSelectedSprite的位置*/
  13. pSelectedSprite->setPosition(ccp(dW / 2.0f,dH / 2.0f));
  14. /*把精灵添加到菜单项pCloseItem中*/
  15. CCMenuItemSprite *pCloseItem = CCMenuItemSprite::create(pNormalSprite,pSelectedSprite,this,menu_selector(HelloWorld::menuCloseCallback));
  16. CC_BREAK_IF(!pCloseItem);
  17. //end////////////////////////////////////////////////////////
  18. /*设置菜单项的位置。*/
  19. pCloseItem->setPosition(ccp(100,100));
  20. /*添加菜单项到菜单*/
  21. CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
  22. pMenu->setPosition(CCPointZero);
  23. CC_BREAK_IF(! pMenu);
  24. // Add the menu to HelloWorld layer as a child layer.
  25. this->addChild(pMenu, 1);

5、更进一步

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

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

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

例子:

  1. CCSprite *pNormalSprite = CCSprite::create(path); //path为图片路径
  2. CCSprite *pSelectedSprite = CCSprite::create(path);
  3. //得到dW和dH
  4. float dW = pSelectedSprite->getContentSize().width - pNormalSprite->getContentSize().width;
  5. float dH = pSelectedSprite->getContentSize().height - pNormalSprite->getContentSize().height;
  6. //更改位置
  7. pNormalSprite->setPosition(ccp(dW / 2.0f,dH / 2.0f));
  8. //将菜单项的contentSize设置为selectedSprite对象的大小
  9. CCMenuItemSprite *pItemSprite = CCMenuItemSprite::create(pNormalSprite,pSelectedSprite,this,menu_selector(MainScene::onMenuEnd));
  10. CCSize size = pSelectedSprite->getContentSize();
  11. pItemSprite->setContentSize(size);

文章亦可见于
http://www.cnblogs.com/tangyikejun/p/3842000.html

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注