CCScrollView for cocos2d-x that works?
Asked Answered
A

2

5

Edit: With enough rewriting, and commenting, I have it running, will post final below for others.

Edit2: I've been more updating my own version, and I've learned the original coder was not very good with C++, you may want to go over everything in there before using it, check out comments below post

The currently available CCScrollView for cocos2d-x suffers from one major flaw: It's messed up.

Specifically, the cpp function headers do not match the .h file's. The cpp file refers to UIEvent and NSMutableArray, not X-Platform.

The scroll view itself must have an array added, which limits your ability to use a for loop to create your menu items (if creating menu items), since you can't use a mutable one, and they don't subclass each other like iOS so you can't just use a mutable then say CCArray * array = mutable->getMutableArray() or similar.

Also, the defines are outdated (though fixable through adding the CCX_SAFE_DELETE via the translation rules on the cocos2d-x site), and a variety of random templates trying to create NS and UI objects that are not even within the project for I have no clue why.

The basic idea is, aside from the addition of using mutable arrays, this class is way too messed up to bother translating to C++. I don't believe the author compiled the version he has up, as the headers don't match. I thought I downloaded both (there's 2 of each) the cpp and .h files, and both have UIEvent instead of CC along with the other issues.

Note: I have fixed a variety of the above, and changed SelectorProtocol to CCObject in various places, but it's just getting overwhelming.

Perhaps I should use the Parallax node instead?

This is just ridiculous, perhaps it's great for Cocos2d but it's not working on c2d-X. Anyway, I'll be recoding and searching, thanks for any suggestions!

Edit: Here's the classes I'm now using. Not done editing, but these will get anyone started, and compiling on more than just iPhone

Header:

#ifndef __CCSCROLLLAYER__
#define __CCSCROLLLAYER__
//  CCScrollLayer.h
//
//  Copyright 2010 DK101
//  http://dk101.net/2010/11/30/implementing-page-scrolling-in-cocos2d/
//
//  Copyright 2010 Giv Parvaneh.
//  http://www.givp.org/blog/2010/12/30/scrolling-menus-in-cocos2d/
//
//  Copyright 2011 Stepan Generalov
//
//  Copyright 2011 Eli Yukelzon
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.

// Original source: https://github.com/cocos2d/cocos2d-iphone-extensions/tree/master/Extensions/CCScrollLayer 
// Last updated: October 1, 2011 

#include "cocos2d.h"

namespace cocos2d {


    class CCScrollLayer;


    class CCScrollLayerDelegate
    {
    public:
        /** Called when scroll layer begins scrolling.
         * Usefull to cancel CCTouchDispatcher standardDelegates.
         */
        virtual void scrollLayerScrollingStarted(CCScrollLayer* sender) {}

        /** Called at the end of moveToPage:
         * Doesn't get called in selectPage:
         */
        virtual void scrollLayerScrolledToPageNumber(CCScrollLayer* sender, unsigned int page) {}
    };

    /* 
     It is a very clean and elegant subclass of CCLayer that lets you pass-in an array 
     of layers and it will then create a smooth scroller. 
     Complete with the "snapping" effect. You can create screens with anything that can be added to a CCLayer.

     */ 
    class CCScrollLayer :   public CCLayer
    {

        int currentScreen; //added
        int totalScreens;
        float scrollWidth;
        float scrollHeight;
        float startWidth;
        float startHeight;
        int startSwipe;

    public:
        //CCScrollLayer();
        ~CCScrollLayer();

        static CCScrollLayer* nodeWithLayers(CCArray* layers, int widthOffset); 

        bool initWithLayers(CCArray* layers, int widthOffset); 

        /** Updates all pages positions & adds them as children if needed.
         * Can be used to update position of pages after screen reshape, or 
         * for update after dynamic page add/remove. 
         */
        void updatePages();

        /** Adds new page and reorders pages trying to set given number for newly added page.
         * If number > pages count - adds new page to the right end of the scroll layer.
         * If number <= 0 - adds new page to the left end of the scroll layer. 
         * @attention Designated addPage method. 
         */
        void addPage(CCLayer* aPage, unsigned int pageNumber);

        /** Adds new page to the right end of the scroll layer. */
        void addPage(CCLayer* aPage);

        /** Removes page if it's one of scroll layers pages (not children)
         * Does nothing if page not found.
         */
        void removePage(CCLayer* aPage);

        /** Removes page with given number. Doesn nothing if there's no page for such number. */
        void removePageWithNumber(unsigned int pageNumber);

        /* Moves scrollLayer to page with given number & invokes delegate
         * method scrollLayer:scrolledToPageNumber: at the end of CCMoveTo action. 
         * Does nothing if number >= totalScreens or < 0.
         */
        void moveToPage(unsigned int pageNumber);

        /* Immedeatly moves scrollLayer to page with given number without running CCMoveTo. 
         * Does nothing if number >= totalScreens or < 0.
         */
        void selectPage(unsigned int pageNumber);

        CC_SYNTHESIZE(CCScrollLayerDelegate*, m_pDelegate, Delegate);

        /** Calibration property. Minimum moving touch length that is enough
         * to cancel menu items and start scrolling a layer. 
         */
        CC_SYNTHESIZE(CGFloat, m_fMinimumTouchLengthToSlide, MinimumTouchLengthToSlide);

        /** Calibration property. Minimum moving touch length that is enough to change
         * the page, without snapping back to the previous selected page.
         */
        CC_SYNTHESIZE(CGFloat, m_fMinimumTouchLengthToChangePage, MinimumTouchLengthToChangePage);

        /** If YES - when starting scrolling CCScrollLayer will claim touches, that are 
         * already claimed by others targetedTouchDelegates by calling CCTouchDispatcher#touchesCancelled
         * Usefull to have ability to scroll with touch above menus in pages.
         * If NO - scrolling will start, but no touches will be cancelled.
         * Default is YES.
         */
        CC_SYNTHESIZE(bool, m_bStealTouches, StealTouches);

        /** Whenever show or not white/grey dots under the scroll layer.
         * If yes - dots will be rendered in parents transform (rendered after scroller visit).
         */
        CC_SYNTHESIZE(bool, m_bShowPagesIndicator, ShowPagesIndicator);

        /** Position of dots center in parent coordinates. 
         * (Default value is screenWidth/2, screenHeight/4)
         */
        CC_SYNTHESIZE_PASS_BY_REF(CCPoint, m_tPagesIndicatorPosition, PagesIndicatorPosition);

        /** Total pages available in scrollLayer. */
        unsigned int getTotalScreens() const;

        /** Current page number, that is shown. Belongs to the [0, totalScreen] interval. */
        CC_SYNTHESIZE_READONLY(unsigned int, m_uCurrentScreen, CurrentScreen);

        /** Offset, that can be used to let user see next/previous page. */
        CC_SYNTHESIZE(CGFloat, m_fPagesWidthOffset, PagesWidthOffset);

        /** Offset that can be used to let user see empty space over first or last page. */
        CC_SYNTHESIZE(CGFloat, m_fMarginOffset, MarginOffset);

        /** Array of pages CCLayer's  */
        CC_SYNTHESIZE_READONLY(CCArray*, m_pLayers, Pages);
    protected:
        // The x coord of initial point the user starts their swipe.
        CGFloat m_fStartSwipe;

        // Internal state of scrollLayer (scrolling or idle).
        int m_iState;
        bool m_bStealingTouchInProgress;
        // Holds the touch that started the scroll
        CCTouch* m_pScrollTouch;

        //void visit();
        //void moveToPageEnded();
        unsigned int pageNumberForPosition(const CCPoint& position);
        CCPoint positionForPageWithNumber(unsigned int pageNumber);
        void claimTouch(CCTouch* pTouch);
        void cancelAndStoleTouch(CCTouch* pTouch, CCEvent* pEvent);

        //void registerWithTouchDispatcher();
        bool ccTouchBegan(CCTouch* pTouch, CCEvent* pEvent);
        void ccTouchMoved(CCTouch* pTouch, CCEvent* pEvent);
        void ccTouchEnded(CCTouch* pTouch, CCEvent* pEvent);
        //void ccTouchCancelled(CCTouch* pTouch, CCEvent* pEvent);
        };
} //end namespace

#endif

CPP

//  CCScrollLayer.cpp
//  Museum
//
//  Created by GParvaneh on 29/12/2010.
//  Copyright 2010. All rights reserved.
//  Ported to C++ by Lior Tamam on 03/04/2011
#include "CCScrollLayer.h"

using namespace cocos2d;

CCScrollLayer* CCScrollLayer::nodeWithLayers(CCArray*  layers, int widthOffset)
{   
    CCScrollLayer *pRet = new CCScrollLayer();
    if (pRet && pRet->initWithLayers(layers, widthOffset))
    {
        pRet->autorelease();
        return pRet;
    }
    CCX_SAFE_DELETE(pRet);
    return NULL;
}

bool CCScrollLayer::initWithLayers(CCArray* layers, int widthOffset)
{   
    if (CCLayer::init())
    {       
        // Make sure the layer accepts touches
        CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this,0,true);

        // Set up the starting variables
        //if(!widthOffset)
        {
        //  widthOffset = 0;
        }   
        currentScreen = 1;

        // offset added to show preview of next/previous screens
        scrollWidth  = (int)CCDirector::sharedDirector()->getWinSize().width - widthOffset;
        scrollHeight = (int)CCDirector::sharedDirector()->getWinSize().height;
        startWidth = scrollWidth;
        startHeight = scrollHeight;

        // Loop through the array and add the screens
        unsigned int i;
        for (i=0; i<layers->count(); i++)
        {
            CCLayer* l = (CCLayer*)layers->objectAtIndex(i);
            //l->setAnchorPoint(ccp(0,0));
            //l->setPosition(ccp((i*scrollWidth),0));
            addChild(l);            
        }

        // Setup a count of the available screens
        totalScreens = layers->count();
        return true;    
    }
    else
    {
        return false;
    }   
}

void CCScrollLayer::setMaximumScrollHeight(float maxHeight)
{
    //Make the offset match expected pixels (include the current screen if at ccp(0,0)
    maxHeight -= CCDirector::sharedDirector()->getWinSize().height;
    maximumScrollHeight = maxHeight;
}

 CCScrollLayer::~CCScrollLayer()
{
    CCTouchDispatcher::sharedDispatcher()->removeDelegate(this);
    CCLayer::onExit();
}

bool CCScrollLayer::ccTouchBegan(CCTouch *touch, CCEvent *withEvent)
{
//  
//  CCPoint touchPoint = touch->locationInView();
//  touchPoint = CCDirector::sharedDirector()->convertToGL(touchPoint);
//  
//  startSwipe = (int)touchPoint.y;
    return true;
}

void CCScrollLayer::ccTouchMoved(CCTouch *touch, CCEvent *withEvent)
{   
    CCPoint touchPoint = touch->locationInView();
    CCPoint prevPoint = touch->previousLocationInView();

    touchPoint = CCDirector::sharedDirector()->convertToGL(touchPoint);
    prevPoint = CCDirector::sharedDirector()->convertToGL(prevPoint);

    CCPoint difference = ccp( touchPoint.x - prevPoint.x , touchPoint.y - prevPoint.y);
    CCPoint currentPos = this->getPosition();

    currentPos = ccp( currentPos.x, currentPos.y+difference.y);

    if (currentPos.y > maximumScrollHeight) 
    {
        currentPos.y = maximumScrollHeight;
        //this->setPositionY(maximumScrollHeight);
    }
    else if (currentPos.y < 0)
    {
        currentPos.y = 0;
       // this->setPositionY(0);
    }
    this->setPosition(currentPos);
}

/*
void CCScrollLayer::ccTouchEnded(CCTouch *touch, CCEvent *withEvent)
{

    //CCPoint touchPoint = touch->locationInView();
    //touchPoint = CCDirector::sharedDirector()->convertToGL(touchPoint);

    int newX = (int)touchPoint.x;

    if ( (newX - startSwipe) < -scrollWidth / 3 && (currentScreen+1) <= totalScreens )
    {
    //  this->moveToNextPage();
    }
    else if ( (newX - startSwipe) > scrollWidth / 3 && (currentScreen-1) > 0 )
    {
    //  this->moveToPreviousPage();
    }
    else
    {
    //  this->moveToPage(currentScreen);        
    }   

}
*/
Averett answered 26/4, 2012 at 20:38 Comment(4)
I can't answer my own question yet, will move answer when it's possible.Averett
REMEMBER TO MOVE the define for CCX_SAFE_DELETE() FROM HERE cocos2d-x.org/projects/cocos2d-x/wiki/… to your ccMacros.h areaAverett
In the cpp file, under initWithLayers(), you'll want to erase or comment //l->setAnchorPoint(ccp(0,0)); and //l->setPosition(ccp((i*scrollWidth),0)); to get positioning to work. Also, delete the if !widthOffset, it either resets itself to 0 or is what it is, that check has no worth. Probably issue with porting from Obj > after this, it'll start to look right. Also, erasing the paging stuff if you just want a scrolling viewAverett
I left a present, the final version now has smooth animations. I won't be editing this anymore, you can probably go from this point. Note: You may have to erase a few function headers to get the linker to compile correctlyAverett
A
4

Check out the forums on Cocos2d-x's site for the latest one. They're being reworked right now by the author based on this. http://www.cocos2d-x.org/boards/18/topics/1090?r=10835#message-10835

Averett answered 3/5, 2012 at 23:8 Comment(1)
One last thing: The 2d-x scroll view actually expects an array of pages (top level nodes). Keep that in mind if you rewrite this or use whichever is on the site (other than my version). Though my version will work as is, it's not suited for complexityAverett
C
9

Reviving an old thread to add new information, for anyone who found this through a search engine: CCScrollView is now part of the GUI extension and seems to work fairly well. There should be no more need for the implementations referenced above.

Cespitose answered 27/7, 2013 at 17:52 Comment(4)
@StephenJ Can you mark it as accepted answer? This solves the problem that you mentioned. Moreover it links to something native to 2d-x.Alternative
There are multiple problems with that even though you are correct currently. 1st, I've been downvoted before simply because a "newer answer" is now correct. 2nd, I may or not be a member at any point in time, from death, injury, or just moving on. Anyone can, so I believe the moderators should find a more suitable solution for when this kind of stuff happens. I will say here though, this is the current correct answer!Averett
I think we, as a community, should be trying to make sure that the most relevant and up to date information is at the top. Unfortunately that sometimes means losing some votes/reputation if a more up to date answer comes along. I agree that the system is not perfect, but it never will be.Cespitose
I've come back to this... I'm simultaneously torn on this idea because 1) you're right, 2) version updates... eg: all the Swift posts thanks to 5 versions of Swift, of which they tried to find a solution to similar with OpenGL. I believe they were recommended to tag their questions with GL versions or something. Eg: I had the right answer before they integrated my code and modified it... but afterwards, you had the right answer. I'm thinking of editing this and tagging it with an appropriate tag, if I can find somethingAverett
A
4

Check out the forums on Cocos2d-x's site for the latest one. They're being reworked right now by the author based on this. http://www.cocos2d-x.org/boards/18/topics/1090?r=10835#message-10835

Averett answered 3/5, 2012 at 23:8 Comment(1)
One last thing: The 2d-x scroll view actually expects an array of pages (top level nodes). Keep that in mind if you rewrite this or use whichever is on the site (other than my version). Though my version will work as is, it's not suited for complexityAverett

© 2022 - 2024 — McMap. All rights reserved.