zoukankan      html  css  js  c++  java
  • 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中滚动层滚动手势加速功能(目前也还没有想好,有思路的朋友可以告诉我哦)。

  • 相关阅读:
    支付宝即时到账接口
    bootstrp-select插件使用
    仿百度收索模糊提醒
    web项目架构
    springmvc的图片上传与导出显示
    jsp前端实现分页代码
    eclipse内下载及配置maven插件(转)
    Maven pom文件常用配置,转载
    阶段回顾
    html涉及的技术梳理
  • 原文地址:https://www.cnblogs.com/qboy/p/3766634.html
Copyright © 2011-2022 走看看