顯示具有 縮放 標籤的文章。 顯示所有文章
顯示具有 縮放 標籤的文章。 顯示所有文章

2016年4月20日 星期三

0419 Cocos2dx 小技巧 ScrollView實現縮放效果

Cocos2dx 小技巧(十四)ScrollView實現縮放效果

http://blog.csdn.net/star530/article/details/25658725

前天有個網友問我一些關於scrollView的用法,由於在QQ上實在講不清,所以就利用晚上的時間寫這篇博客出來了。
本篇要實現的功能是用scrollView 拖動對象時,對象移動到某個固定範圍會有放大、縮小的效果。下面開始。


在進入正題前我先簡短的介紹下scrollView應該怎麼用吧(想必大家也都會用~~):
1、記得在頭文件裡包含 「../extensions/cocos-ext.h",順便聲明下作用域:USING_NS_CC_EXT;
2、在類的繼承裡 加上ScrollViewDelegate,如下:
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. class HelloWorld : public cocos2d::Layer,public ScrollViewDelegate  
3、在類的聲明中,加上三個scrollView的委託函數,如下:
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. void scrollViewDidScroll(ScrollView* view);  
  2. void scrollViewDidZoom(ScrollView* view);  
  3. void scrollViewMoveOver(ScrollView* view);  
4、實在不想繼續說廢話了,直接看實例吧。

先看頭文件:
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. #ifndef __HELLOWORLD_SCENE_H__  
  2. #define __HELLOWORLD_SCENE_H__  
  3.   
  4. #include "cocos2d.h"  
  5. #include "../extensions/cocos-ext.h"  
  6.   
  7. USING_NS_CC;  
  8. USING_NS_CC_EXT;  
  9.   
  10. class HelloWorld : public cocos2d::Layer,public ScrollViewDelegate  
  11. {  
  12. public:  
  13.     static cocos2d::Scene* createScene();//獲取歡迎畫面的Scene  
  14.     virtual bool init();    
  15.   
  16.     void menuCloseCallback(Ref* pSender);  
  17.       
  18.     CREATE_FUNC(HelloWorld);  
  19.   
  20.     //scroll 委託  
  21.     void scrollViewDidScroll(ScrollView* view);  
  22.     void scrollViewDidZoom(ScrollView* view);  
  23.     void scrollViewMoveOver(ScrollView* view);  
  24.   
  25. private:  
  26.     Vector<Sprite*> sp_vec;//聲明一個容器  
  27. };  
  28. #endif // __HELLOWORLD_SCENE_H__  

下面看定義
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. bool HelloWorld::init()  
  2. {     
  3.     //首先創建scrollView  
  4.     auto scroll_layer = Layer::create();//創建scrollView中的容器層  
  5.     scroll_layer->setPosition(Point::ZERO);  
  6.     scroll_layer->setAnchorPoint(Point::ZERO);  
  7.     scroll_layer->setContentSize(Size(600,300));//設置容器層大小為(600,300)  
  8.   
  9.     auto scrollView = ScrollView::create(Size(400,300),scroll_layer);//創建scrollView,顯示窗口大小為(400,300)  
  10.     scrollView->setDelegate(this);//設置委託  
  11.     scrollView->setDirection(ScrollView::Direction::HORIZONTAL);//設置滾動方向為水平  
  12.     scrollView->setPosition(Point(300,200));  
  13.     this->addChild(scrollView,2);  
  14.   
  15.     //創建三個對象  
  16.     auto boy = Sprite::create("boy.png");//沒錯,主角又是我們熟悉的那仨。多麼溫馨。  
  17.     boy->setPosition(Point(150,100));  
  18.     scroll_layer->addChild(boy,2);  
  19.   
  20.     auto girl = Sprite::create("girl_1.png");  
  21.     girl->setPosition(Point(300,100));  
  22.     scroll_layer->addChild(girl,2);   
  23.   
  24.     auto girl3 = Sprite::create("girl_3.png");  
  25.     girl3->setPosition(Point(450,100));  
  26.     scroll_layer->addChild(girl3,2);   
  27.    
  28.     sp_vec.pushBack(boy);//將三個對象放入容器中  
  29.     sp_vec.pushBack(girl);  
  30.     sp_vec.pushBack(girl3);  
  31.   
  32.        return true;  
  33. }  

接下來看下scrollView的委託函數,這裡只要看scrollViewDidScroll 就好了。實現效果是對象在某個坐標範圍內移動時會有縮放效果。
[cpp] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. void HelloWorld::scrollViewDidScroll(ScrollView* view)  
  2. {  
  3.     //在scrollView拖動時響應該函數  
  4.   
  5.     auto offsetPosX = (view->getContentOffset()).x;//獲得偏移X坐標(向右移動,偏移量為正數,向左則為負數)  
  6. //  CCLOG("offset pos is %f , %f",offsetPos.x,offsetPos.y);  
  7.   
  8.     //for 循環遍歷容器中的每個精靈  
  9.     for( auto e : sp_vec )  
  10.     {  
  11.         auto pointX = e->getPositionX();//獲得當前對象的X坐標(不管怎麼滾動,這個坐標都是不變的)  
  12.         float endPosX = pointX + offsetPosX;//將精靈的 X坐標 + 偏移X坐標  
  13.   
  14.         //當endPosX在 150~250 範圍,則對象的大小從左向右遞增  
  15.         if( endPosX > 150 && endPosX < 250 )  
  16.         {  
  17.             float x = endPosX / 150;//放大倍數為 endPosX / 150;  
  18.             e->setScale(x);  
  19.             CCLOG("x = %f",x);  
  20.         }  
  21.         //當endPosX在 250~350 範圍,則對象的大小從左向右遞減  
  22.         else if( endPosX > 250 && endPosX < 350 )   
  23.         {  
  24.             //下面這個公式不好解釋,我就這麼說吧:  
  25.             //假設 endPosX = 200,那麼放大倍數應該是 200 / 150 = 1.33左右,那麼當endPosX = 300時,出於對稱的原理,我們以250為對稱中心,那麼  
  26.             //300 的放大倍數也應該是 1.33。這就是下面的公式由來  
  27.             float a = endPosX - 250;  
  28.             float b = 250 - a;  
  29.   
  30.             float x = b / 150;  
  31.             e->setScale(x);  
  32.         }  
  33.         else   
  34.         {  
  35.             //不是在上面的範圍,則設置為正常大小  
  36.             e->setScale(1.0f);  
  37.         }  
  38.     }     
  39. }  
  40. void HelloWorld::scrollViewDidZoom(ScrollView* view)  
  41. {  
  42.     //do something  
  43. }  
  44. void HelloWorld::scrollViewMoveOver(ScrollView* view)  
  45. {  
  46.     //do something  
  47. }  

恩,註釋寫的很清楚啦,但我還是要稍微補充一些東東:我們應該知道,對象放到滾動層上(如scroll_layer->addChild(boy)),那麼不管對象在scrollView上如何移動,它獲得的坐標都是不會變的(如boy->getPosition()是不變的數值),這種情況下,如果我們想實現對象在某個坐標範圍內會有縮放效果,那麼只是去獲取對象的坐標肯定是行不通的,所以肯定要找一個時刻在變化的」參照物」來利用下,該找什麼呢?沒錯,就是scrollView的偏移坐標(scrollView->getContentOffset())!只要scrollView移動一下,那麼它的 偏移量也隨之改變。我這裡就是利用對象的坐標與scrollView的偏移坐標之間不可告人的秘密,從而實現當前的目的。
下面看下運行效果。

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...