2016年4月19日 星期二

0419 Cocos2d-x 點擊菜單按鍵居中放大

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、解決方案

接下來我們通過實際的例子來討論,本例中一些類和對象的關係如下表:
對象對應圖片
CCSpritepNormalSpritenormal.png
CCSpritepSelectedSpriteselected.png
CCMenuItemSpritepCloseItem
現在我們只把注意力放在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);

沒有留言:

張貼留言

cocos2dx-lua 建立滑鼠監聽

重要關鍵字  EVENT_MOUSE_SCROLL addEventListenerWithSceneGraphPriority      if IsPc() then --建立滑鼠監聽         local listener = cc.EventListenerMouse...