help with CCParallaxScrollNode

Hey, i’ve tried to use CCParallacScrollNode: https://github.com/jasonmarziani/CCParallaxScrollNode . Everything seems to be fine except, i think there are no deallocation, when e.g. i change the scene. Could you tell me, how to do this for this class, cause all my solutions come to errors. I have also seen a lot of Memory leaks through Xcode. So maybe, someone have experience with these classes and could share the edited code? Thank you.

i have port this code to cocos2d-x. if you need that i can share.

CCParallaxScrollNode.h

#ifndef _CCPARALLAX_SCROLL_NODE_H_
#define _CCPARALLAX_SCROLL_NODE_H_

#include "cocos2d.h"
//#include "CCParallaxScrollOffset.h"

namespace cocos2d {

    class CC_DLL CCParallaxScrollNode : public CCNode
    {
    private:
        ccArray *scrollOffsets;
        CCSpriteBatchNode *batch;
        bool init();
    public:
        ~CCParallaxScrollNode();
        //static CCParallaxScrollNode * node();
        static CCParallaxScrollNode * makeWithBatchFile(const char *batchFileName);
        void addChild(CCSprite *node, int z, const CCPoint &r, const CCPoint &p, const CCPoint &s);
        void addChild(CCSprite *node, int z, const CCPoint &r, const CCPoint &p, const CCPoint &s, const CCPoint &v);

        void addChild(CCNode *node, int z);

        void removeChild(CCSprite *node, bool cleanup);
        void removeAllChildrenWithCleanup(bool cleanup);
        void updateWithVelocity(const CCPoint &vel, ccTime dt);
        void updateWithYPosition(float y, ccTime dt);
        void addInfiniteScrollWithZ(int z, const CCPoint ∶, const CCPoint &pos, const CCPoint &dir, CCSprite *firstObject, ...);
        void addInfiniteScrollXWithZ(int z, const CCPoint ∶, const CCPoint &pos, CCSprite *firstObject, ...);
        void addInfiniteScrollYWithZ(int z, const CCPoint ∶, const CCPoint &pos, CCSprite *firstObject, ...);
        void addInfiniteScrollWithObjects(CCArray *objects, int z, const CCPoint ∶, const CCPoint &pos, const CCPoint &dir);

        void setScrollOffsets(ccArray *pScrollOffsets);
        void setBatch(CCSpriteBatchNode *pBatch);
        ccArray * getScrollOffsets();
        CCSpriteBatchNode * getBatch();

        //CC_SYNTHESIZE(ccArray *, scrollOffsets, ScrollOffsets);
        //CC_SYNTHESIZE(CCSpriteBatchNode *, batch, Batch)

        LAYER_NODE_FUNC(CCParallaxScrollNode);//какая-то хрень
    };

} // namespace cocos2d
#endif //__CCPARALLAX_SCROLL_NODE_H__

CCParallaxScrollNode.cpp

#include "CCParallaxScrollNode.h"
#include "CCParallaxScrollOffset.h"
#include 

#ifndef PTM_RATIO
#define PTM_RATIO 1//32
#endif

#ifndef SIGN
#define SIGN(x) ((x < 0) ? -1 : (x > 0))
#endif

#include "support/data_support/ccCArray.h"

namespace cocos2d {

    CCParallaxScrollNode::~CCParallaxScrollNode()
    {
        if (scrollOffsets) {
            ccArrayFree(scrollOffsets);
            scrollOffsets = 0;
        }
    }

    bool CCParallaxScrollNode::init()
    {
        bool ret = true;

        if (ret) 
        {
            scrollOffsets = ccArrayNew(5);
        }

        return ret;
    }

//  CCParallaxScrollNode * CCParallaxScrollNode::node()
//  {
//      CCParallaxScrollNode *pRet = new CCParallaxScrollNode();
//      pRet->autorelease();
//      return pRet;
//  }

    CCParallaxScrollNode * CCParallaxScrollNode::makeWithBatchFile(const char *batchFileName)
    {
        CCParallaxScrollNode *parallax = CCParallaxScrollNode::node();

        char *pngName = (char*)malloc(sizeof(char)*(strlen(batchFileName)+5));

        strcpy(pngName, batchFileName);
        *(pngName+strlen(batchFileName)) = 0;

        parallax->setBatch(CCSpriteBatchNode::batchNodeWithFile(strcat(pngName, ".png")));

        free(pngName);

        ((CCNode*)parallax)->addChild(parallax->batch);

        pngName = (char*)malloc(sizeof(char)*(strlen(batchFileName)+7));

        strcpy(pngName, batchFileName);
        *(pngName+strlen(batchFileName)) = 0;
        CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile(strcat(pngName, ".plist"));

        free(pngName);
        return parallax;
    }

    void CCParallaxScrollNode::updateWithVelocity(const CCPoint &vel, ccTime dt) {
        CCSize screen = CCDirector::sharedDirector()->getWinSize();

        CCPoint vel2 = ccpMult(vel, PTM_RATIO);

        for (int i=scrollOffsets->num - 1; i >= 0; i--) {
            CCParallaxScrollOffset *scrollOffset = (CCParallaxScrollOffset*)scrollOffsets->arr[i];
            CCNode *child = scrollOffset->getChild();

            CCPoint relVel = ccpMult(scrollOffset->getRelVelocity(), PTM_RATIO);
            CCPoint totalVel = ccpAdd(vel2, relVel);

            CCPoint offset = ccpCompMult(ccpMult(totalVel, dt), scrollOffset->getRatio());

            child->setPosition(ccpAdd(child->getPosition(), offset));

            if ( (vel2.x < 0 && child->getPosition().x + child->getContentSize().width < 0) ||
                (vel2.x > 0 && child->getPosition().x > screen.width) ) {

                child->setPosition(ccpAdd(child->getPosition(), ccp(-SIGN(vel2.x) * fabs(scrollOffset->getScrollOffset().x), 0)));
            }

            // Positive y indicates upward movement in cocos2d
            if ( (vel2.y < 0 && child->getPosition().y + child->getContentSize().height < 0) ||
                (vel2.y > 0 && child->getPosition().y > screen.height) ) {
                child->setPosition(ccpAdd(child->getPosition(), ccp(0, -SIGN(vel2.y) * fabs(scrollOffset->getScrollOffset().y))));
            }
        }
    }

    void CCParallaxScrollNode::updateWithYPosition(float y, ccTime dt)
    {   
        for (int i=scrollOffsets->num - 1; i >= 0; i--) {
            CCParallaxScrollOffset *scrollOffset = (CCParallaxScrollOffset*)scrollOffsets->arr[i];
            CCNode *child = scrollOffset->getChild();
            float offset = y * scrollOffset->getRatio().y;//ccpCompMult(pos, scrollOffset.ratio);
            child->setPosition(ccp(child->getPosition().x, scrollOffset->getOrigPosition().y + offset));
        }
    }

    void CCParallaxScrollNode::addChild(CCSprite *node, int z, const CCPoint &r, const CCPoint &p, const CCPoint &s, const CCPoint &v)
    {
        node->setAnchorPoint(ccp(0,0));
        CCParallaxScrollOffset *obj = CCParallaxScrollOffset::scrollWithNode(node, r, p, s, v);
        ccArrayAppendObjectWithResize(scrollOffsets, obj);
        if (batch) {
            batch->addChild(node, z);
        } else {
            ((CCNode*)this)->addChild(node, z);
        }
    }

    void CCParallaxScrollNode::addChild(CCSprite *node, int z, const CCPoint &r, const CCPoint &p, const CCPoint &s)
    {
        addChild(node, z, r, p, s, ccp(0,0));
    }

    void CCParallaxScrollNode::removeChild(CCSprite *node, bool cleanup)
    {
        for (int i=0; i < scrollOffsets->num; i++) {
            CCParallaxScrollOffset *scrollOffset = (CCParallaxScrollOffset*)scrollOffsets->arr[i];
            if(scrollOffset->getChild()->isEqual(node)) {
                ccArrayRemoveObjectAtIndex(scrollOffsets, i);
                break;
            }
        }
        if (batch) {
            batch->removeChild(node, cleanup);
        }
    }

    void CCParallaxScrollNode::addChild(CCNode *node, int z)
    {
        CCNode::addChild(node, z);
    }

    void CCParallaxScrollNode::removeAllChildrenWithCleanup(bool cleanup)
    {
        ccArrayRemoveAllObjects(scrollOffsets);
        if (batch) {
            batch->removeAllChildrenWithCleanup(cleanup);
        }
    }

    void CCParallaxScrollNode::addInfiniteScrollWithObjects(CCArray *objects, int z, const CCPoint ∶, const CCPoint &pos, const CCPoint &dir)
    {
        // NOTE: corrects for 1 pixel at end of each sprite to avoid thin lines appearing

        // Calculate total width and height
        float totalWidth = 0;
        float totalHeight = 0;
        for (int i = 0; i < objects->count(); i++) {
            CCSprite *object = (CCSprite *)(objects->objectAtIndex(i));
            totalWidth += object->getContentSize().width - 2;//1;
            totalHeight += object->getContentSize().height - 2;//1;
        }

        // Position objects, add to parallax
        CCPoint currPos = pos;
        for (int i = 0; i < objects->count(); i++) {
            CCSprite *object = (CCSprite *)(objects->objectAtIndex(i));
            addChild(object, z, ratio, currPos, ccp(totalWidth, totalHeight));
            CCPoint nextPosOffset = ccp(dir.x * (object->getContentSize().width - 2/*1*/), dir.y * (object->getContentSize().height - 2/*1*/));
            currPos = ccpAdd(currPos, nextPosOffset);
        }
    }

    void CCParallaxScrollNode::addInfiniteScrollWithZ(int z, const CCPoint ∶, const CCPoint &pos, const CCPoint &dir, CCSprite *firstObject, ...)
    {
        va_list args;
        va_start(args, firstObject);

        CCArray* argArray = CCArray::arrayWithCapacity(2);
        for (CCSprite *arg = firstObject; arg != 0; arg = va_arg(args, CCSprite*)) {
            argArray->addObject(arg);
        }
        va_end(args);

        addInfiniteScrollWithObjects(argArray, z, ratio, pos, dir);
    }

    void CCParallaxScrollNode::addInfiniteScrollXWithZ(int z, const CCPoint ∶, const CCPoint &pos, CCSprite *firstObject, ...)
    {
        va_list args;
        va_start(args, firstObject);

        CCArray* argArray = CCArray::arrayWithCapacity(2);
        for (CCSprite *arg = firstObject; arg != 0; arg = va_arg(args, CCSprite*)) {
            argArray->addObject(arg);
        }
        va_end(args);

        addInfiniteScrollWithObjects(argArray, z, ratio, pos, ccp(1, 0));
    }

    void CCParallaxScrollNode::addInfiniteScrollYWithZ(int z, const CCPoint ∶, const CCPoint &pos, CCSprite *firstObject, ...)
    {
        va_list args;
        va_start(args, firstObject);

        CCArray* argArray = CCArray::arrayWithCapacity(2);
        for (CCSprite *arg = firstObject; arg != 0; arg = va_arg(args, CCSprite*)) {
            argArray->addObject(arg);
        }
        va_end(args);

        addInfiniteScrollWithObjects(argArray, z, ratio, pos, ccp(0, 1));
    }

    void CCParallaxScrollNode::setScrollOffsets(ccArray *pScrollOffsets)
    {
        scrollOffsets = pScrollOffsets;
    }

    void CCParallaxScrollNode::setBatch(CCSpriteBatchNode *pBatch)
    {
        batch = pBatch;
    }

    ccArray * CCParallaxScrollNode::getScrollOffsets()
    {
        return scrollOffsets;
    }

    CCSpriteBatchNode * CCParallaxScrollNode::getBatch()
    {
        return batch;
    }

}// namespace cocos2d

CCParallaxScrollOffset.h

#ifndef _CCPARALLAX_SCROLL_OFFSET_H_
#define _CCPARALLAX_SCROLL_OFFSET_H_

#include "cocos2d.h"

namespace cocos2d {

    class CC_DLL CCParallaxScrollOffset : public CCObject
    {
    private:
        CCPoint scrollOffset, origPosition, relVelocity, ratio, position, currPosition;
        CCNode *child;
    public:
        ~CCParallaxScrollOffset();
        static CCParallaxScrollOffset * scrollWithNode(CCNode *node, const CCPoint &r, const CCPoint &p, const CCPoint &s);
        static CCParallaxScrollOffset * scrollWithNode(CCNode *node, const CCPoint &r, const CCPoint &p, const CCPoint &s, const CCPoint &v);
        bool initWithNode(CCNode *node, const CCPoint &r, const CCPoint &p, const CCPoint &s);
        bool initWithNode(CCNode *node, const CCPoint &r, const CCPoint &p, const CCPoint &s, const CCPoint &v);


//        CC_PROPERTY_PASS_BY_REF(CCPoint, scrollOffset, ScrollOffset);
//        CC_PROPERTY_PASS_BY_REF(CCPoint, origPosition, OrigPosition);
//        CC_PROPERTY_PASS_BY_REF(CCPoint, relVelocity, RelVelocity);
//        CC_PROPERTY_PASS_BY_REF(CCPoint, ratio, Ratio);
//        CC_PROPERTY_PASS_BY_REF(CCPoint, position, Position);
//        CC_PROPERTY_PASS_BY_REF(CCPoint, currPosition, CurrPosition);
//        
//        CC_PROPERTY(CCNode *, child, Child);

//        CC_SYNTHESIZE_PASS_BY_REF(CCPoint, scrollOffset, ScrollOffset);
//        CC_SYNTHESIZE_PASS_BY_REF(CCPoint, origPosition, OrigPosition);
//        CC_SYNTHESIZE_PASS_BY_REF(CCPoint, relVelocity, RelVelocity);
//        CC_SYNTHESIZE_PASS_BY_REF(CCPoint, ratio, Ratio);
//        CC_SYNTHESIZE_PASS_BY_REF(CCPoint, position, Position);
//        CC_SYNTHESIZE_PASS_BY_REF(CCPoint, currPosition, CurrPosition);
//        
//        CC_SYNTHESIZE_PASS_BY_REF(CCNode *, child, Child);

        void setScrollOffset(const CCPoint &val);
        void setOrigPosition(const CCPoint &val);
        void setRelVelocity(const CCPoint &val);
        void setRatio(const CCPoint &val);
        void setPosition(const CCPoint &val);
        void setCurrPosition(const CCPoint &val);
        void setChild(CCNode *val);
        const CCPoint & getScrollOffset() const;
        const CCPoint & getOrigPosition() const;
        const CCPoint & getRelVelocity() const;
        const CCPoint & getRatio() const;
        const CCPoint & getPosition() const;
        const CCPoint & getCurrPosition() const;
        CCNode * getChild() const;

    };

} // namespace cocos2d
#endif //__CCPARALLAX_SCROLL_NODE_H__

CCParallaxScrollOffset.cpp

#include "CCParallaxScrollOffset.h"

namespace cocos2d {

    CCParallaxScrollOffset::~CCParallaxScrollOffset()
    {

    }

    CCParallaxScrollOffset * CCParallaxScrollOffset::scrollWithNode(CCNode *node, const CCPoint &r, const CCPoint &p, const CCPoint &s)
    {
        CCParallaxScrollOffset *pobSprite = new CCParallaxScrollOffset();
        if (pobSprite && pobSprite->initWithNode(node, r, p, s))
        {
            pobSprite->autorelease();
            return pobSprite;
        }
        CC_SAFE_DELETE(pobSprite);
        return NULL;
    }

    CCParallaxScrollOffset * CCParallaxScrollOffset::scrollWithNode(CCNode *node, const CCPoint &r, const CCPoint &p, const CCPoint &s, const CCPoint &v)
    {
        CCParallaxScrollOffset *pobSprite = new CCParallaxScrollOffset();
        if (pobSprite && pobSprite->initWithNode(node, r, p, s, v))
        {
            pobSprite->autorelease();
            return pobSprite;
        }
        CC_SAFE_DELETE(pobSprite);
        return NULL;
    }

    bool CCParallaxScrollOffset::initWithNode(CCNode *node, const CCPoint &r, const CCPoint &p, const CCPoint &s)
    {
        return initWithNode(node, r, p, s, ccp(0,0));
    }

    bool CCParallaxScrollOffset::initWithNode(CCNode *node, const CCPoint &r, const CCPoint &p, const CCPoint &s, const CCPoint &v)
    {
        bool ret = true;

        if(ret) {
            child = node;
            ratio = r;
            scrollOffset = s;
            relVelocity = v;
            child->setPosition(p);
            origPosition = p;
            //currPosition = p;
            child->setAnchorPoint(ccp(0, 0));
        }
        return ret;
    }

    void CCParallaxScrollOffset::setScrollOffset(const CCPoint &val)
    {
        scrollOffset = val;
    }

    void CCParallaxScrollOffset::setOrigPosition(const CCPoint &val)
    {
        origPosition = val;
    }

    void CCParallaxScrollOffset::setRelVelocity(const CCPoint &val)
    {
        relVelocity = val;
    }

    void CCParallaxScrollOffset::setRatio(const CCPoint &val)
    {
        ratio = val;
    }

    void CCParallaxScrollOffset::setPosition(const CCPoint &val)
    {
        position = val;
    }

    void CCParallaxScrollOffset::setCurrPosition(const CCPoint &val)
    {
        currPosition = val;
    }

    void CCParallaxScrollOffset::setChild(CCNode *val)
    {
        child = val;
    }

    const CCPoint & CCParallaxScrollOffset::getScrollOffset() const
    {
        return scrollOffset;
    }

    const CCPoint & CCParallaxScrollOffset::getOrigPosition() const
    {
        return origPosition;
    }

    const CCPoint & CCParallaxScrollOffset::getRelVelocity() const
    {
        return relVelocity;
    }

    const CCPoint & CCParallaxScrollOffset::getRatio() const
    {
        return ratio;
    }

    const CCPoint & CCParallaxScrollOffset::getPosition() const
    {
        return position;
    }

    const CCPoint & CCParallaxScrollOffset::getCurrPosition() const
    {
        return currPosition;
    }

    CCNode * CCParallaxScrollOffset::getChild() const
    {
        return child;
    }

}// namespace cocos2d

Hi, I have seen your port and it looks wonderful, but, I have a question, I have checked that there is two methods to move the Parallax but I did not found one move the parallax using fingers. Also, do these classes support zoom in and zoom out?

Thanks!

Hi, i only ported that code to the C*+ and actually don’t know what void CCParallaxScrollNode::updateWithYPosition(float y, ccTime dt) method is doing there.
“Also, do these classes support zoom in and zoom out?” - no, these classes don’t support zooming.
“but I did not found one move the parallax using fingers” - i have added two methods to the @ CCParallaxScrollNode@ class maybe you find it useful when move the parallax using fingers.
<pre>
void CCParallaxScrollNode::updateWithOffset
{
CCSize screen = CCDirector::sharedDirector~~>getWinSize;
CCPoint offsetPTM = ccpMult;
for {
CCParallaxScrollOffset scrollOffset = scrollOffsets~~>arr[i];
CCNode *child = scrollOffset~~>getChild;
CCPoint offset = ccpMult), 1);
CCPoint newPos = ccpAdd, offset);
CCPoint oldPos = child
>getPosition;
if && .width < 0)) {
newPos.x = fabs.x);
} else if && ) {
newPos.x = fabs.x);
}
// Positive y indicates upward movement in cocos2d
if && .y + child
>getContentSize.height < 0)) {
newPos.y
= fabs.y);
} else if .y > screen.height)) {
newPos.y = fabs.y);
}
child
>setPosition;
}
}
void CCParallaxScrollNode::updateWithPosition
{
CCSize screen = CCDirector::sharedDirector~~>getWinSize;
float fractpartX, fractpartY, intpart, xScrollOffset, yScrollOffset;
for {
CCParallaxScrollOffset *scrollOffset = scrollOffsets~~>arr[i];
CCNode
child = scrollOffset~~>getChild;
CCPoint offset = ccpMult), 1);
CCPoint newPos = ccpAdd, offset);
CCPoint oldPos = child
>getPosition;
xScrollOffset = scrollOffset~~>getScrollOffset.x;
yScrollOffset = scrollOffset~~>getScrollOffset.y;
fractpartX = modff;
newPos.x = fractpartX*xScrollOffset;
fractpartY = modff;
newPos.y = fractpartY*yScrollOffset;
if && .width < 0)) {
newPos.x*= fabs(xScrollOffset);
} else if ((newPos.x > oldPos.x) && (newPos.x > screen.width)) {
newPos.x = fabs;
}
// Positive y indicates upward movement in cocos2d
if && .height < 0)) {
newPos.y += fabs;
} else if && ) {
newPos.y
= fabs(yScrollOffset);
}

child->setPosition(newPos.x, newPos.y);
}
}

now you can use either `pInfiniteParallax->updateWithVelocity(fingerDistancePerDt, dt);` or `m_pInfiniteParallax->updateWithOffset(curFingerPos-oldFingerPos);` or `m_pInfiniteParallax->updateWithPosition(curFingerPos);`