Cocos2dx中利用雙向鏈表實現無限循環滾動層


       [Qboy原創]

         在Cocos2dX 3.0 中已經實現一些牛逼的滾動層,但是對於有一些需要實現循環滾動的要求確沒有實現,筆者在前段時間的一個做了一個游戲,需求是實現在少有的(13個)英雄中進行循環滾動層,即用戶可以無限的向一個方向滾動,當到最后時,由前面的進行重復出現。

        如下圖:

 

      為了滿足以上需求,我第一反應就想到了采用大學數據結構中所學的雙向鏈表。想想還真稱靠譜誒。那就說干就干吧。

1、定義雙向鏈接表結構:

struct CycNode{//構建雙向鏈表結構

 CycNode* preNode;//前一個節點

 cocos2d::gui::ImageView* node; //所對應的Node

 CycNode* nextNode;//后一個節點 

};

 

2、定義回調函數

由於在本游戲中拖拽還有一些事件,所以需要向外暴露一些事件。定義如下:

class CycScrollDelegate{ 

public: 

 virtual void dragBeginNode(cocos2d::Node* node,cocos2d::Touch* touch) = 0; //開始拖拽時拖拽的節點

 virtual void dragMoveNode(cocos2d::Node* node,cocos2d::Touch* touch) = 0; //拖拽移動時拖拽的節點

 virtual void dragEndNode(cocos2d::Node* node,cocos2d::Touch* touch) = 0; //拖拽結束后拖拽的節點

};

其實以上事件都會在層的Touch事件中實現

3、定義實現類

.h文件:

class CycScrollView:public cocos2d::gui::Widget{

 CC_SYNTHESIZE(float, scrollHeight, ScrollHeight);//設置滾動時的高度限制 CC_SYNTHESIZE(CycScrollDelegate*, owerner, Owerner); 

private: 

 CycNode* pFirstCycNode; 

 cocos2d::Node* selNode; 

 Size winSize; 

 bool canScroll; 

public: 

 virtual void onExit(); 

 virtual bool init(); 

 CREATE_FUNC(CycScrollView);

public:

 void loadScrollView(std::vector<cocos2d::gui::ImageView*> listNode); //真實加載循環滾動條中的Vector文件

};

.cpp 文件 

(1)實現雙向鏈表,並將雙向鏈表構成環狀

    

    for (cocos2d::gui::ImageView* n: listNode) {//定義成雙向鏈表節點

        CycNode* cycnode = new CycNode();

        cycnode->node = n;

        n->setUserData(&cycnode);//將節點反向回雙向鏈表

        cycnode->preNode = pcycNode;

        if(pcycNode){

            pcycNode->nextNode = cycnode;

        }

        pcycNode = cycnode;

        if(pFirstNode==NULL){

            pFirstNode = cycnode;

        }

    }

    

(2)將節點設定相應的錨點和坐標,並添加到Widge上

    int index=0;

    

    for (cocos2d::gui::ImageView* n: listNode) {

        

        n->setAnchorPoint(Point::ZERO);

        n->setPosition(Point(index*C_WIDTH,0));

 

        addChild(n);

        

        index++;

    }

    

    canScroll = C_WIDTH*listNode.size()>winSize.width;//設定是否需要循環滾動,如果小於可視化大小的話,則不需要滾動。

    (3)注冊頁面的Touch事件,回調相應的Touch事件。

    auto listener = EventListenerTouchOneByOne::create();

    listener->setSwallowTouches(true);

    

    listener->onTouchBegan = [this](Touch* touch,Event* e){

        curPoint = touch->getLocation();

        curPoint = convertToNodeSpace(curPoint);

        selNode = nullptr;

        if(owerner){

            CycNode* pcurNode = pFirstCycNode;

            do {

                Size nodeSize = pcurNode->node->getSize();

                Point p = pcurNode->node->getPosition();

                Rect r = Rect(p.x, p.y, nodeSize.width, nodeSize.height);

                if(r.containsPoint(curPoint)){

                    selNode = pcurNode->node;

                    owerner->dragBeginNode(pcurNode->node, touch);

                    break;

                }

                pcurNode=pcurNode->nextNode;

            } while (pcurNode!=pFirstCycNode);

        }

        

        if(curPoint.y>0&&curPoint.y<scrollHeight){

            return true;

        }

 

        return false;

    };

    listener->onTouchMoved = [this](Touch* touch,Event* e){

        if(!canScroll){

            return;

        }

        Point newPoint = touch->getLocation();

        newPoint = convertToNodeSpace(newPoint);

        

        float deltaX = newPoint.x-curPoint.x;

        CycNode* pmoveFirst = NULL;

        CycNode* pcurNode = this->pFirstCycNode;

        int index = 0;

        float y;

        if(deltaX<0){//向左移

            float maxX = 0;

 

            do {

                Point nPoint = (pcurNode->node)->getPosition();

                float preX = nPoint.x;

                if(preX>maxX&&preX<=winSize.width){

                    pmoveFirst = pcurNode;

                    maxX = preX;

                    y=nPoint.y;

                }

                index++;

                pcurNode = pcurNode->nextNode;

            }while (pcurNode!=pFirstCycNode);

            

            pmoveFirst->nextNode->node->setPosition(Point(maxX+C_WIDTH,y));

 

        }

        

        

        if(deltaX>0){//向右移

            float minX = 1200;

            float y;

            do {

                Point nPoint = (pcurNode->node)->getPosition();

                float preX = nPoint.x;

                if(preX<minX&&preX>=0){

                    pmoveFirst = pcurNode;

                    minX = preX;

                    y=nPoint.y;

                }

                index++;

                pcurNode = pcurNode->nextNode;

            }while (pcurNode!=pFirstCycNode);

            

            pmoveFirst->preNode->node->setPosition(Point(minX-C_WIDTH,y));

 

        }

        if(pmoveFirst){

            pcurNode=pmoveFirst;

            do {

                Point nPoint = (pcurNode->node)->getPosition();

                float newX = nPoint.x+deltaX;

                (pcurNode->node)->setPosition(Point(newX,y));

                pcurNode = pcurNode->nextNode;

            }while (pcurNode!=pmoveFirst);

        }

 

        if(owerner&&selNode){

            owerner->dragMoveNode(selNode, touch);

        }

        

        curPoint = newPoint;

    };

    

    listener->onTouchEnded=[this](Touch* touch,Event*){

        Point newPoint = touch->getLocation();

        newPoint = convertToNodeSpace(newPoint);

        if(owerner&&selNode){

            owerner->dragEndNode(selNode, touch);

        }

    };

    listener->onTouchCancelled=[this](Touch* touch,Event*){

        Point newPoint = touch->getLocation();

        newPoint = convertToNodeSpace(newPoint);

        if(owerner&&selNode){

            owerner->dragEndNode(selNode, touch);

        }

    };

    

    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);

 

 4、后續

在本例已大體體現了需求,如果有需要比如上下滾動的可以相應的進行調整修改,其他的需求進行酌情進行增減。另外,在本例中也沒有實現IOS中滾動層滾動手勢加速功能(目前也還沒有想好,有思路的朋友可以告訴我哦)。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM