• cocos2dx循环滚动视图


    由于项目需求大厅里的牌子要循环滚动(tips:这样看起来东西比较多,其实是个挺搞笑的需求),cocos本身的控件不满足需求,所以就简单写了个。目前惯性减速不太好用,有更好解决方案的大拿给个提示啊!

    GitHub链接
    代码如下:

    //
    //  ScrollCircle.hpp
    //  ScrollSelector-mobile
    //
    //  Created by 徐家伟 on 2018/1/19.
    //
    
    #ifndef CycleScroll_hpp
    #define CycleScroll_hpp
    
    #include "cocos2d.h"
    #include "cocos-ext.h"
    #include <vector>
    
    #define MIN_SCROLL_SPEED 1
    #define MAX_SCROLL_SPEED 30
    
    class CycleScroll: public cocos2d::LayerColor
    {
        CycleScroll();
    public:
        static CycleScroll* create(cocos2d::Size &size, std::vector<cocos2d::Node*> nodes, float distance, float minScale = 1.0f);
        void ScrollTo(int index, float delay);
        void setDisplaySize(const cocos2d::Size &size);
        const cocos2d::Size& getDisplaySize() const;
    
    private:
        float minScale;
        float spaceDistance;
        int currentIndex;
        cocos2d::Size disSize;
        cocos2d::ClippingNode* clipNode;
        std::vector<cocos2d::Node*> nodes;
    
        // 减速使用
        bool dragging;
        bool autoScrolling;
        float scrollDistance;
        float startTime;
        cocos2d::Vec2 startPos;
    
        bool onTouchBegin(cocos2d::Touch *touch, cocos2d::Event *unused_event);
        void onTouchMove(cocos2d::Touch *touch, cocos2d::Event *unused_event);
        void onTouchEnd(cocos2d::Touch *touch, cocos2d::Event *unused_event);
        void updateNodePosX(float interval);
    
        virtual bool init();
        void initView();
        void initListener();
        void update(float dt);
        void deaccelerateScrolling(float dt);
    
        CREATE_FUNC(CycleScroll);
    };
    
    #endif /* ScrollCircle_hpp */
    
    #include "CyclyScroll.hpp"
    
    using namespace std;
    USING_NS_CC;
    
    CycleScroll::CycleScroll():autoScrolling(false),
                                dragging(false),
                                scrollDistance(0),
                                minScale(1),
                                spaceDistance(150),
                                currentIndex(0),
                                startTime(0)
    {}
    
    CycleScroll* CycleScroll::create(Size &size, vector<Node*> nodes, float distance, float minScale /*= 1.0f*/)
    {
        auto ret = CycleScroll::create();
        ret->nodes = nodes;
        ret->spaceDistance = distance;
        ret->minScale = minScale;
        ret->disSize = size;
        ret->initView();
        ret->scheduleUpdate();
        return ret;
    }
    
    void CycleScroll::initView()
    {
        this->setContentSize(this->disSize);
        auto clipSize = this->disSize;
        auto stencil = LayerColor::create(Color4B::RED, clipSize.width, clipSize.height);
        clipNode = ClippingNode::create(stencil);
        this->addChild(this->clipNode);
    
        unsigned long cnt = this->nodes.size();
        for(int i = 0; i< cnt; i++){
            if(this->nodes[i] != NULL){
                this->nodes[i]->setPosition(Vec2(this->nodes[i]->getContentSize().width/2 + i * spaceDistance, disSize.height/2));// TODO
                clipNode->addChild(this->nodes[i]);
            }
        }
    
        this->initListener();
        //    this->ScrollTo(0, 0);
    }
    
    void CycleScroll::setDisplaySize(const cocos2d::Size &size){
        LayerColor::setContentSize(size);
        clipNode->getStencil()->setContentSize(size);
    }
    
    const Size& CycleScroll::getDisplaySize() const{
        return this->disSize;
    }
    
    void CycleScroll::ScrollTo(int index, float delay){
        if(index < 0 || index >= this->nodes.size())
            return;
    
        Size contentSize = this->getContentSize();
    
        float distance = contentSize.width/2 - this->nodes[index]->getPositionX();
        for(auto i : this->nodes)
            i->runAction(MoveBy::create(delay, Vec2(distance, 0)));
    }
    
    bool CycleScroll::init()
    {
        return LayerColor::initWithColor(Color4B(0,0,0,0));
    }
    
    void CycleScroll::initListener()
    {
        auto listener = EventListenerTouchOneByOne::create();
        listener->onTouchBegan = CC_CALLBACK_2(CycleScroll::onTouchBegin, this);
        listener->onTouchMoved = CC_CALLBACK_2(CycleScroll::onTouchMove, this);
        listener->onTouchEnded = CC_CALLBACK_2(CycleScroll::onTouchEnd, this);
        _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
    }
    
    bool CycleScroll::onTouchBegin(cocos2d::Touch *touch, cocos2d::Event *unused_event){
        dragging = true;
        scrollDistance = 0;
        startTime = clock();
        startPos = touch->getLocation();
        return true;
    }
    
    void CycleScroll::onTouchMove(cocos2d::Touch *touch, cocos2d::Event *unused_event){
        float disX = touch->getDelta().x;
        this->updateNodePosX(disX);
    }
    
    void CycleScroll::onTouchEnd(cocos2d::Touch *touch, cocos2d::Event *unused_event){
    //    float startDistance = touch->getLocation().distance(touch->getStartLocation());
    //
    //    if(startDistance < 10) // click
    //    {
    //
    //    }
    
        // 处理减速
        dragging = false;
        auto prePos = touch->getPreviousLocation();
        auto curPos = touch->getLocation();
        scrollDistance = curPos.distance(prePos);
        int direction = curPos.x > startPos.x?1:-1;
    
        scrollDistance = scrollDistance <= MAX_SCROLL_SPEED?scrollDistance : MAX_SCROLL_SPEED;
        scrollDistance = scrollDistance * direction;
        CCLOG("end:%f, pre:%f", curPos.x, prePos.x);
    
        float longDisance = curPos.distance(startPos);
        float elapsedTime = (clock() - startTime) / 1000; //毫秒
        CCLOG("long:%f, t:%f", longDisance, elapsedTime);
        if (elapsedTime < 50 && scrollDistance < 10 && longDisance >= 10){
            scrollDistance = longDisance<=MAX_SCROLL_SPEED?longDisance:MAX_SCROLL_SPEED;
            scrollDistance *= direction;
        }
        if (fabs(scrollDistance) > MIN_SCROLL_SPEED){
            autoScrolling = true;
        }
    }
    
    void CycleScroll::updateNodePosX(float interval){
        int length = (int)nodes.size();
        for (int i=0; i<length; i++){
            auto node = this->nodes[i];
            node->setPositionX(node->getPositionX() + interval);
        }
    }
    
    void CycleScroll::deaccelerateScrolling(float dt){
        if (dragging)
        {
            autoScrolling = false;
            return;
        }
        CCLOG("sc:%f", scrollDistance);
        scrollDistance *= 0.95;
        if (fabs(scrollDistance) < MIN_SCROLL_SPEED){
            autoScrolling = false;
            startTime = 0;
        }
        this->updateNodePosX(scrollDistance);
    }
    
    void CycleScroll::update(float dt)
    {
        int length = (int)nodes.size();
        float newPosX = 0;
        auto s = 0.5;
        auto mid = this->disSize.width/2;
    
        for (int i=0; i<length; i++){
            auto node = this->nodes[i];
            auto curPosX = node->getPositionX();
    
            if (curPosX < -node->getContentSize().width/2){
                int beforeIndex = i-1;
                beforeIndex = beforeIndex>=0?beforeIndex:length-1;
                newPosX = nodes[beforeIndex]->getPositionX() + this->spaceDistance;
                if (curPosX != newPosX){
                    node->setPositionX(newPosX);
                    curPosX = newPosX;
                }
            }else if (curPosX > this->disSize.width + node->getContentSize().width/2){
                int afterIndex = i+1;
                afterIndex = afterIndex<=length-1?afterIndex:0;
                newPosX = nodes[afterIndex]->getPositionX() - this->spaceDistance;
                if (curPosX != newPosX){
                    node->setPositionX(newPosX);
                    curPosX = newPosX;
                }
            }
    
            if (curPosX <= mid){
                s = curPosX / mid;
            } else{
                s = (this->disSize.width-curPosX) / mid;
            }
            s *= 1.2;
            s = s<=1?s:1;
            s = s>=this->minScale?s:this->minScale;
            node->setScale(s);
        }
    
        if (autoScrolling){
            this->deaccelerateScrolling(dt);
        }
    }
    
  • 相关阅读:
    编写高质量代码建议17代码错误调试
    同步和异步的不同场景的概念理解
    kafka版本0.8.2.0-Producer Configs之request.required.acks
    linux的grep命令
    jetty服务器访问系统的域名
    linux工具问题,tail -f 失效
    memcached并发处理
    python爬虫scrapy的Selectors参考文档
    访问nginx提示gateway timeout 504 ,发现总是当调用时间超过30s时提示504错误
    重构再次理解
  • 原文地址:https://www.cnblogs.com/skyxu123/p/9543796.html
Copyright © 2020-2023  润新知