天天看点

Cocos2dx中利用双向链表实现无限循环滚动层

       [Qboy原创]

         在Cocos2dX 3.0

中已经实现一些牛逼的滚动层,但是对于有一些需要实现循环滚动的要求确没有实现,笔者在前段时间的一个做了一个游戏,需求是实现在少有的(13个)英雄中进行循环滚动层,即用户可以无限的向一个方向滚动,当到最后时,由前面的进行重复出现。

        如下图:

Cocos2dx中利用双向链表实现无限循环滚动层

为了满足以上需求,我第一反应就想到了采用大学数据结构中所学的双向链表。想想还真称靠谱诶。那就说干就干吧。

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; 

 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 =

    }

(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();

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*

        if(!canScroll){

            return;

        Point newPoint =

        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;

                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

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

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

            float minX = 1200;

            float y;

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

  minX = preX;

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

        if(pmoveFirst){

            pcurNode=pmoveFirst;

                float newX

= nPoint.x+deltaX;

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

(pcurNode!=pmoveFirst);

        if(owerner&&selNode){

owerner->dragMoveNode(selNode, touch);

        curPoint = newPoint;

    listener->onTouchEnded=[this](Touch*

touch,Event*){

owerner->dragEndNode(selNode, touch);

    listener->onTouchCancelled=[this](Touch*

_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);

 4、后续

在本例已大体体现了需求,如果有需要比如上下滚动的可以相应的进行调整修改,其他的需求进行酌情进行增减。另外,在本例中也没有实现IOS中滚动层滚动手势加速功能(目前也还没有想好,有思路的朋友可以告诉我哦)。