2016年6月30日 星期四

0630 cocos2d-x 滾動畫面製作

cocos2dx基礎篇(16)——滾動視圖CCScrollView
原創作品,允許轉載,轉載時請務必以超鏈接形式標明文章 原始出處 、作者信息和本聲明。否則將追究法律責任。http://shahdza.blog.51cto.com/2410787/1544983
【嘮叨】
    本節要講講滾動視圖CCScrollView,相信玩過手游的同學們應該對它不會陌生吧。
    例如:憤怒的小鳥的遊戲場景裡大大的地圖,手機的屏幕肯定無法完全顯示的,所以需要通過觸摸滾動才能顯示大地圖的其他區域;排行榜中上下滑動來查看其他玩家的排名;以及手機上主界面左右滑動來切換界面等等。
    如下圖為屏幕滾動,切換手機的界面。
wKioL1P7LHGh4r-zAAEl3irSbeQ272.gif

【致謝】

【Demo下載】

【3.x】
    (1)去掉 「CC」
    (2)滾動方向
        > CCScrollViewDirection 改為強枚舉 ScrollView::Direction
1
2
3
4
5
//
    HORIZONTAL     //只能橫向滾動
    VERTICAL       //只能縱向滾動
    BOTH           //橫向縱向都能滾動,默認方式
//
    (3)其他變化不大。



【CCScrollView】
    滾動視圖類CCScrollView繼承於CCLayer,故它會忽略錨點的設置,其錨點始終為(0,0)。而我們知道CCLayer繼承了觸控事件CCTouch相關的函數。而CCScrollView也繼承了觸控函數,並將屏幕觸控事件的四個函數ccTouchesBegan、ccTouchesMoved、ccTouchesEnded、ccTouchesCancelled進行了重寫並實現了有關觸摸移動相關的操作(其內部的實現代碼自己看cocos2dx的源碼)。這也就是為什麼滾動視圖CCScrollView的屏幕可以進行上下左右滾動的原因了。
    值得注意的是:既然CCScrollView也是一個CCLayer圖層,我們都知道觸控滾動的不是CCLayer圖層,而是添加在圖層上的那些對象。比如CCSprite精靈、以及圖層上的CCLayer等等。為了方便實現CCScrollView的滾動效果,cocos2dx引擎規定在使用CCScrollView時,需要在它的上面添加一個用於觸控滾動的容器Container,一般容器都選用CCLayer類或其擴展類(如CCLayerColor等)。而觸控事件的四個函數也是針對容器Container進行操作的。
    也就是說CCScrollView實現的視圖滾動,在真正意義上說是對容器Container進行滾動。
    接下來就來講講它的使用方法吧!

1、引入頭文件和命名空間
1
2
3
4
//
    #include "cocos-ext.h"
    using namespace cocos2d::extension;
//

2、創建方式
    說明:有兩種創建方式。對於默認的創建方式create(),會自動創建CCLayer作為滾動視圖的容器,且滾動視圖的可視區域的大小默認為200*200。而第二種則是可以自定義選擇哪個CCLayer作為容器。
    值得注意的是:創建滾動視圖之後,對於添加子節點操作scrollView->addChild(sp),實際上是將sp添加到容器container中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//
class CCScrollView : public CCLayer
/**
 *     2種創建方式
 */
    //會自動創建CCLayer作為容器
    static CCScrollView* create();
    //size:     滾動視圖的可視區域大小
    //container:自定義滾動視圖的CCLayer容器
    static CCScrollView* create(CCSize size, CCNode* container = NULL);
    //舉例
    CCLayer* scrollLayer = CCLayer::create();
    CCScrollView* scrollView = CCScrollView::create(CCSizeMake(150, 100), scrollLayer);
//

3、常用操作
    設置容器、尺寸大小、容器的偏移量、允許滾動的方向、放縮、以及其他屬性的判斷。
    注意:因為容器與滾動視圖的錨點均為(0,0)。所以容器的偏移量,指容器左下角坐標相對滾動視圖左下角坐標的偏移。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//
/**
 *     容器相關操作
 *     setContainer , setContentSize , setContentOffset
 */
    //設置滾動視圖的容器
    void setContainer(CCNode* pContainer);
    CCNode* getContainer();
    //設置容器Container的尺寸大小
    virtual void setContentSize(const CCSize & size);
    virtual const CCSize& getContentSize() const;
    //設置容器相對滾動視圖的偏移量
    //animated為是否附帶滑動的動作效果,還是直接設置為新的偏移量
    //默認滑動動作為0.15秒,從舊位置滑動到新位置.
    void setContentOffset(CCPoint offset, bool animated = false);
    void setContentOffsetInDuration(CCPoint offset, float dt); 
    CCPoint getContentOffset();
/**
 *     滾動視圖相關操作
 *     setViewSize , setDirection , setZoomScale ,
 *     isDragging , isTouchMoved , setBounceable , setTouchEnabled
 */
    //設置滾動視圖可視區域的大小
    void setViewSize(CCSize size);
    CCSize getViewSize();
    //設置滾動視圖允許滾動的方向
    //CCScrollViewDirection:
    //      kCCScrollViewDirectionBoth              橫向縱向都能滾動,默認方式
    //      kCCScrollViewDirectionHorizontal        只能橫向滾動
    //      kCCScrollViewDirectionVertical          只能縱向滾動
    virtual void setDirection(CCScrollViewDirection eDirection);
    CCScrollViewDirection getDirection();
    //放縮滾動視圖大小
    //好像有bug,建議不要使用了!
    void setZoomScale(float s);
    void setZoomScale(float s, bool animated);
    float getZoomScale();
    void setZoomScaleInDuration(float s, float dt);
    bool isDragging();                     //用戶是否正在CCScrollView中操作
    bool isTouchMoved();                   //用戶是否在CCScrollView中移動
    void setBounceable(bool bBounceable);  //是否開啟彈性效果 
    bool isBounceable();                   //是否具有彈性效果
    void setTouchEnabled(bool e);          //是否開啟觸摸
//

4、事件委託代理接口類CCScrollViewDelegate
    CCScrollViewDelegate類主要是用來偵聽CCScrollView的事件,並設置事件的回調響應函數。
    使用方法:在創建CCScrollView類的CCLayer類中,讓CCLayer繼承CCScrollViewDelegate,並重寫如下兩個事件回調響應函數。
1
2
3
4
//
    virual void scrollViewDidScroll(CCScrollView * view);   //有滾動時的響應函數
    virual void scrollViewDidZoom(CCScrollView * view);     //有縮放時的響應函數
//

5、委託代理
1
2
3
4
5
6
7
8
9
10
//
    //設置滾動視圖的事件委託代理對象,一般為this
    //並且CCLayer必需要繼承代理接口類CCScrollViewDelegate
    void setDelegate(CCScrollViewDelegate* pDelegate);
    CCScrollViewDelegate* getDelegate();
    //舉例:
    //scrollView->setDelegate(this);
//

6、關於尺寸大小
    CCScrollView的使用過程中涉及到兩個尺寸大小。
    (1)滾動視圖的尺寸大小:即可視區域的大小。使用setViewSize()進行設置。
    (2)容器的尺寸大小:使用setContentSize()進行設置。
    例如設置滾動視圖尺寸大小為100*100,容器的尺寸大小為1000*1000。那麼每次對視圖進行滾動,都只能看到容器100*100的某部分區域。
    具體圖文解說可以參照cocos-孤狼大神寫的:和屌絲一起學cocos2dx-CCScrollView

7、關於觸摸滾動
    使用setDirection()可以設置滾動的方向。主要有三個類型:
    (1)橫向縱向都能滾動    kCCScrollViewDirectionBoth              
    (2)只能橫向滾動        kCCScrollViewDirectionHorizontal        
    (3)只能縱向滾動        kCCScrollViewDirectionVertical          
    另外setTouchEnabled()是用來設置是否開啟觸控事件的。所以若設置為false。那麼即使setDirection()了,也無法滾動視圖。

8、使用技巧
    (1)創建CCScrollView,和容器CCLayer;並設置滾動視圖的容器為該容器。
    (2)設置容器的尺寸大小setContentSize;滾動視圖(可視區域)的尺寸大小setViewSize。
    (3)將各種精靈、菜單、按鈕等加入到容器中。
    (4)設置委託代理setDelegate(this),並實現回調函數。



【代碼實戰】
    這裡例舉了滾動視圖CCScrollView的三種用途。
1
2
3
4
5
//
    void test1();     //測試圖片滾動
    void test2();     //測試只能縱向滾動
    void test3();     //測試背包翻頁
//

1、資源圖片
    第一組:
wKioL1P7dF3BNzBAAAddWYzXKxY984.jpg
    第二組:
wKioL1P7dNmj0RMeAAAjK9teRfE282.jpg    wKiom1P7c8GDVKW8AAAjtKSDM-M911.jpg    wKioL1P7dNmh99oMAAAjKsNJ2mA727.jpg    wKioL1P7dNmgUrZWAAAj3a3fdFY451.jpg
    第三組:
wKiom1P7c4-BNhddAAATWetOdzQ115.jpg    wKioL1P7dKahSmKMAAATDlDPr7M853.jpg
wKioL1P7dKfRh-XpAAATIvbAoeQ026.jpg    wKiom1P7c4-yKualAAAU7Ih-51U755.jpg    wKiom1P7c4-CHawmAAANgkMX34Q085.jpg

2、引入頭文件和命名空間
1
2
3
4
//
    #include "cocos-ext.h"
    using namespace cocos2d::extension;
//

3、繼承CCScrollViewDelegate,重寫事件偵聽函數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//
    class HelloWorld : public cocos2d::CCLayer,public CCScrollViewDelegate
    {
    public:
        virtual bool init();  
        static cocos2d::CCScene* scene();
        void menuCloseCallback(CCObject* pSender);
        CREATE_FUNC(HelloWorld);
        void test1(); //測試圖片滾動
        void test2(); //測試只能縱向滾動
        void test3(); //測試背包翻頁
        int pageNumber;          //背包第幾頁
        CCMenuItemImage* pBack;  //往前翻頁
        CCMenuItemImage* pFront; //往後翻頁
        void scrollImage(CCObject* sender); //test3的背包翻頁
        void scrollViewDidScroll(CCScrollView* view); //滾動時響應的回調函數
        void scrollViewDidZoom(CCScrollView* view);   //放縮時響應的回調函數
    };
//

4、委託代理回調函數
    在控制台輸出LOG。
1
2
3
4
5
6
7
8
9
10
//
    void HelloWorld::scrollViewDidScroll(CCScrollView* view) 
    {
        CCLOG("ScrollView Moved!");
    }
    void HelloWorld::scrollViewDidZoom(CCScrollView* view) 
    {
        CCLOG("ScrollView Scaled");
    }
//

5、測試圖片滾動test1()
    屏幕大小:480*320。滾動視圖大小:480*320。容器大小:960*600。
    開啟彈性效果setBounceable。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//
    void HelloWorld::test1()
    {
        CCSize visableSize = CCSizeMake(480, 320); //屏幕大小
        CCSize mysize = CCSizeMake(960,600);       //容器大小
    //創建容器、設置大小
        CCLayerColor* scrollLayer = CCLayerColor::create( ccc4(255,255,255,255) );
        scrollLayer->setContentSize(mysize);
         
    //容器中的東西
        CCSprite* bg = CCSprite::create("war.png");
        bg->setPosition( ccp(960/2.0, 600/2.0) );
        scrollLayer->addChild(bg);
    //創建滾動視圖CCScrollView
        CCScrollView* scrollView = CCScrollView::create();
        this->addChild(scrollView, 0, 1);
         
        //屬性設置
        scrollView->setContainer(scrollLayer);  //設置容器
        scrollView->setViewSize( visableSize ); //可視區域大小
        scrollView->setBounceable(true);        //是否具有彈性
         
        //委託代理
        scrollView->setDelegate(this);
    }
//

6、測試只能縱向滾動test2()
    屏幕大小:480*320。滾動視圖大小:150*100。容器大小:150*220。
    將滾動視圖設置到屏幕中心位置,並設置滾動方向setDirection,只能縱向滾動。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//
    void HelloWorld::test2()
    {
        CCSize visableSize = CCSizeMake(480, 320); //屏幕大小
        CCSize mysize = CCSizeMake(150,220);       //容器大小
    //創建容器、設置大小
        CCLayerColor* scrollLayer = CCLayerColor::create( ccc4(255,255,255,255) );
        scrollLayer->setContentSize(mysize);
    //容器中添加四個按鈕
        for(int i = 1; i <= 4; i++) 
        {
            char file[20];
            sprintf(file, "btn%d.png", i);
            CCSprite* btn = CCSprite::create(file);
            btn->setPosition( ccp(mysize.width/2, 220 - 50*i) );
            scrollLayer->addChild(btn);
        }
    //創建滾動視圖CCScrollView
        //可視區域大小150*100 、 容器為scrollLayer
        CCScrollView* scrollView = CCScrollView::create(CCSizeMake(150, 100), scrollLayer);
        scrollView->setPosition( visableSize/2 - ccp(150/2.0, 100/2.0) );
        this->addChild(scrollView, 0, 2);
         
        //設置為只能縱向滾動
        scrollView->setDirection(kCCScrollViewDirectionVertical);
        //委託代理
        scrollView->setDelegate(this);
    }
//

7、測試背包翻頁test3()
    屏幕大小:480*320。滾動視圖大小:100*80。容器大小:300*80。
    關閉觸控事件setTouchEnabled(false),創建兩個按鈕,實現只能通過按鈕進行左右翻頁。
    翻頁原理:通過設置容器的偏移值setContentOffset。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
//
    void HelloWorld::test3()
    {
        CCSize visableSize = CCSizeMake(480, 320); //屏幕大小
        CCSize mysize = CCSizeMake(300,80);        //容器大小
    //創建容器、設置大小
        CCLayerColor* scrollLayer = CCLayerColor::create( ccc4(255,255,255,255) );
        scrollLayer->setContentSize(mysize);
    //容器中添加三個圖片
        for(int i = 1; i <= 3; i++) 
        {
            char file[20];
            sprintf(file, "sp%d.png", i);
            CCSprite* sp = CCSprite::create(file);
            sp->setPosition( ccp(100*i - 50, 40) );
            scrollLayer->addChild(sp);
        }
    //創建滾動視圖CCScrollView
        //可視區域大小100*80 、 容器為scrollLayer
        CCScrollView* scrollView = CCScrollView::create(CCSizeMake(100, 80), scrollLayer);
        scrollView->setPosition( visableSize/2 - ccp(100/2.0, 0) );
        this->addChild(scrollView, 0, 3);
        //屬性設置
        scrollView->setTouchEnabled(false); //關閉觸碰事件,無法觸摸滾動
        //委託代理
        scrollView->setDelegate(this);
    //創建背包翻頁按鈕
        //前翻pBack、後翻pFront
        pBack = CCMenuItemImage::create("b1.png""b2.png""b3.png"this, menu_selector(HelloWorld::scrollImage) );
        pFront = CCMenuItemImage::create("f1.png""f2.png""f3.png"this, menu_selector(HelloWorld::scrollImage) );
        pBack->setPosition( ccp(visableSize.width/2 - 100, 60) );
        pFront->setPosition( ccp(visableSize.width/2 + 100, 60) );
        CCMenu* pMenu = CCMenu::create(pBack, pFront, NULL);
        pMenu->setPosition(CCPointZero);
        this->addChild(pMenu, 0, 100);
        pBack->setEnabled(false);
        pageNumber = 0; //第0頁
    }
    //實現翻頁效果scrollImage
    void HelloWorld::scrollImage(CCObject* sender)
    {
        CCScrollView* scrollView = (CCScrollView*)this->getChildByTag(3);
        if(sender == pBack && pBack->isEnabled() )
        {
            pageNumber = max(0, pageNumber-1); //前翻
        }
        else if( pFront->isEnabled() )
        {
            pageNumber = min(2, pageNumber+1); //後翻
        }
        //設置容器相對滾動視圖的偏移量
        scrollView->setContentOffset(ccp(-100 * pageNumber, 0), true);
        pBack->setEnabled( pageNumber != 0);
        pFront->setEnabled( pageNumber != 2);
    }
//

8、運行結果

    8.1、背景滾動、附帶彈性效果
wKioL1P7fKXQMNuRABJI5nik47U808.gif
        
    8.2、只能縱向滾動,附帶彈性效果
wKiom1P7e42SMvMqAAJPJRgzfNw274.gif

    8.3、背包翻頁、無法觸摸滾動、通過按鈕進行翻頁
wKiom1P7e42xh9vNAACstxmMFVE125.gif


本文出自 「夏天的風」 博客,請務必保留此出處http://shahdza.blog.51cto.com/2410787/1544983

沒有留言:

張貼留言

cocos2dx-lua 建立滑鼠監聽

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