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()函數中修改即可查看效果(當然要先把圖放進去!)。
//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的尺寸。
要解決這個問題需要兩個步驟:
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);
沒有留言:
張貼留言