@tangyikejun
2014-08-09T00:16:05.000000Z
字数 3063
阅读 4300
已发布
配置环境:win7+Cocos2d-x.2.0.3+VS2012
目标读者:已经了解Cocos2d-x中的坐标系统,精灵和图片的关系。并知道OOP中类和对象的关系。
实现一个按键效果,按下去之前显示normal.png的图,按下去之后显示selected.png的图。selected.png尺寸大于normal.png。效果图如下:
笔者在这个问题上纠结了一天半,尝试了各种方法,一直以为是自己错误使用菜单类导致不能居中放大。之后查看了源码,源码用两个精灵保存前后两张图片,并设置其锚点为(0,0),因此按键前后的图片都是以左下角点为原点绘制,无法到达居中放大的效果。
我们先罗列出绘制一个按键所涉及的类,CCMenu、CCMenuItemSprite、CCSprite。它们在结点树上依次是爷爷、父亲、儿子的关系,当然你也可以认为是外婆、母亲、女儿的关系,随便。上述三个类中,CCMenu和CCSprite的锚点坐标都是(0,0),CCMenuItemSprite的锚点为(0.5,0.5),不建议更改这一默认设置。默认设定CCMenuItemSprite的大小和CCSprite的大小一致。当你没有抚摸屏幕的时候界面是这样的:
;
在这个图中,只对CCMenuItemSprite的位置进行了设置,其他对象的位置都是默认值。可以看到CCMenu对象的默认位置(position)为(0,0)。CCSprite的位置与CCMenuItemSprite的位置一致,即CCSprite的位置默认也是(0,0)。
接下来我们通过实际的例子来讨论,本例中一些类和对象的关系如下表:
类 | 对象 | 对应图片 |
---|---|---|
CCSprite | pNormalSprite | normal.png |
CCSprite | pSelectedSprite | selected.png |
CCMenuItemSprite | pCloseItem | 无 |
现在我们只把注意力放在CCMenuItemSprite和CCSprite这两个类上。对于本例,pNormalSprite和pSelectedSprite两个对象的默认锚点和位置均为(0,0),也就是说均以pCloseItem的左下角点作为原点。为了达到中心放大的目的,只需要重新设置pSelectedSprite的位置即可,见下图伪代码:
具体的代码如下,直接在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);
上述代码虽然解决了中心放大的问题,但是仍存在一些缺陷。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);