Original CCScrollLayer by DK101 & Giv Parvaneh
Added ability to swipe above targetedTouchDelegates.
Mac not supported. Tested with 1.0.0-rc3
https://github.com/cocos2d/cocos2d-iphone-extensions/tree/develop/Extensions/CCScrollLayer
A fast, easy to use, free, and community supported 2D game engine
Original CCScrollLayer by DK101 & Giv Parvaneh
Added ability to swipe above targetedTouchDelegates.
Mac not supported. Tested with 1.0.0-rc3
https://github.com/cocos2d/cocos2d-iphone-extensions/tree/develop/Extensions/CCScrollLayer
Both authors are cool with MIT License for CCScrollLayer - green light for using it in extensions repo.
Also: found something similar: https://github.com/tomohisa/scrollmenu - will check it out later.
CCScrollLayer is now a part of cocos2d-iphone-extensions repo:
https://github.com/cocos2d/cocos2d-iphone-extensions/tree/develop/Extensions/CCScrollLayer
After release it will be in the master branch:
https://github.com/cocos2d/cocos2d-iphone-extensions/Extensions/CCScrollLayer
Please let's treat cocos2d-iphone-extensions as the new home for this extension and send all pull requests there.
If you're not famillar with git - you can register on GitHub and create issue with a link to your patch/extension.
Thanks!
This is a great class and has plenty of uses. I did encounter one issue. Artifacts were displaying on the dots (page indicators) on this class. To fix this issue change the following code in CCScrollerLayer.m.
This is the old code:
// Set GL Values - old
glEnable(GL_POINT_SMOOTH);
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
glPointSize(6.0f * CC_CONTENT_SCALE_FACTOR());
Change it to this and you will have perfectly smooth circles:
// Set GL Values - new
glEnable(GL_POINT_SMOOTH);
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glPointSize( 6.0 );Perfect!
Merged in https://github.com/cocos2d/cocos2d-iphone-extensions/commit/6f88fd49fa53f7ceaf5a449d4a0e59173980907b
Thanks a Lot!
P.S.
I've mentioned you in AUTHORS.cocos2d-extensions - let me know if it needs correction.
I'm having a problem with memory management using this class and would like some advice on how to handle it. I am using this class as an index page. My app currently needs about 30-40 entries for the scroll. The problem is when I exit the index page scene any memory used by that scene is not released.
How can I force everything to be released?
This is how I am adding the CCScrollLayer to the scene:
///////////////////////////////////
// ADD THE SCROLLING MENU TO THE SCENE
////////////////////////////////////////////////
CCScrollLayer *scroller = [[CCScrollLayer alloc] initWithLayers:[NSMutableArray arrayWithObjects: pageCover, page1, page2, page3, page4, page5, page6, page7, page8, page9, page10, page11, page12, page13, page14, page15, page16, page17, page18, page19, page20, page21, page22, page23, page24, page25, page26, page27, page28, page29, page30, page31, page32, page33, nil] widthOffset: 612 ];
[self addChild:scroller z: 3];
Here is an example of an entry in the array:
/////////////////////////////////////////////////
// PAGE 33
////////////////////////////////////////////////
// create a blank layer for page
CCLayer *page33 = [[CCLayer alloc] init];
// create a custom font menu for page
CCMenuItemImage * item33 =[CCMenuItemImage itemFromNormalImage:@"Index33.png" selectedImage: @"Index33.png" target:self selector:@selector(loadPage33)];
CCMenu *menu33 = [CCMenu menuWithItems: item33, nil];
menu33.position = ccp(screenSize.width/2, screenSize.height/2);
// add menu to page
[page33 addChild:menu33];
EDIT TO PROVIDE A SOLUTION: This is an easy fix. Simply define your *scroller in your .h file and also make sure to call CCScrollerLayer.h in your .h file. Then in dealloc call [scroller release];
I just imported this class into my project.
When building I keep getting various warnings and errors such as:
redefinition of d
implicit declaration of function CC_CONTENT_SCALE_FACTOR
and
touch undeclared
I'm using cocos2d 0.99.5...
I've started to use CCScrollLayer and find it is really quite good. Is there a way to set the starting page of the scroll layer before if displays to the screen?
Usage scenario:
- CCScrollLayer presents chapter selection for a game.
- Chapter 5 is selected by player, the section is recorded to xml and another scene is is loaded with appropriate levels from xml.
- User presses back button to return to chapter selection.
- User is presented with the CCScrollLayer, defaulting to page 1 (chapter 1).
I can read in the selected chapter from xml, I would like to apply it to the CCScrollLayer so it defaults to the page representing the previously selected chapter.
I can add...
-(void) moveToPage:(int)page;
...to the interface declaration of CCScrollLayer.h and while it does what I want, it animates the transition from chapter 1 to 5, which isn't quite right.
I'll keep digging around however I think it should be just a matter of popping something like...
-(void) startAtPage:(int)page;
... and the relevant code to the .m
Anyway, just a feature suggestion to this great class. If I can write the startAtPage myself I'll post the code :)
Cheers
Ok I've modified CCScrollLayer to include the features I talk about in my previous post.
Here's a summary of the changes.
1) Changed/Added the following the CCScrollLayer.h
+(id) nodeWithLayers:(NSArray *)layers widthOffset: (int) widthOffset startScreen: (int) startScreen;
-(id) initWithLayers:(NSArray *)layers widthOffset: (int) widthOffset startScreen: (int) startScreen;
-(void) jumpToPage:(int)page;
2) Changed/Added the following the CCScrollLayer.m init with the following
+(id) nodeWithLayers:(NSArray *)layers widthOffset: (int) widthOffset startScreen: (int) startScreen
{
return [[[self alloc] initWithLayers: layers widthOffset:widthOffset startScreen:startScreen] autorelease];
}
-(id) initWithLayers:(NSArray *)layers widthOffset: (int) widthOffset startScreen: (int) startScreen
{
...
currentScreen_ = startScreen;
...
[self jumpToPage:currentScreen_];
}
You can download them from my website below:
http://www.iheals.net/files/CCScrollLayer.h
http://www.iheals.net/files/CCScrollLayer.m
Note that the usage is now slightly different, for example:
CCScrollLayer *scroller = [[CCScrollLayer alloc] initWithLayers:layers widthOffset: 230 startScreen:3];
[self addChild:scroller];
[scroller release];@Timbo, thanks for sharing! But this was already implemented in the develop branch...
Sorry for this. I need to mention somewhere, that before adding something or changing you should check the develop branch.
moveToPage is used to move with animation, and selectPage is analog of your's jumpToPage.
Please try them, maybe there's something you would like to change in the develop branch.
Stepan, no worries on that at all. I will check the dev branch first next time.
I've tried the newest version however it doesn't behave quite the way I'm after. As the init still sets the start page to 0 you see it flip through each page to get to the page specified by moveToPage.
Even if I set the start page within the init I still need to do the following
self.position = ccp(-((page-1)*scrollWidth_),0);
otherwise you see the wrong page displayed until you move the CCScrollLayer with your finger.
The only down side to the change I need is that you have to specify a startPage even when you probably don't want to (messy).
If I want to suggest changes in the develop branch, what's the correct way to do that? I'll poke around the forums in the mean time in order to find out.
Thanks for you time
I love to work with the GitHub and all aspects of it: Issues, Comments, Pull Requests, etc...
So feel free to use any of them.
There's
/* Immediately moves scrollLayer to page with given number without running CCMoveTo.
Does nothing if number >= totalScreens or < 0.
*/
-(void) selectPage:(int)page;
Just init, and then invoke selectPage with pageNumber you want to display - no moving will be done - it will look like it was inited with page you've provided.
P.S.
Oh, and be warned - in the develop branch CCScrollLayer uses standard page numbering, where 0 means first page, and totalCount-1 means last.
Thanks, I'm looking into it now with the dev branch.
I noticed a minor unrelated issue within -(void) selectPage:(int)page that
CCLOGERROR(@"CCScrollLayer#moveToPage: %d - wrong page number, out of bounds. ");
should probably be
CCLOGERROR(@"CCScrollLayer#selectPage: %i - wrong page number, out of bounds. ", page);
I'll do some further testing
Thanks again :)
Just to follow up on the previous post, the page numbering you warned of in the develop branch class was what threw me.
Here's my final usage in case it helps anyone else, (which uses the latest dev branch of CCScrollLayer)
// load gamedata (so you can get selected stage)
GameData *gameData = [GameDataParser loadGameData];
// ensure scroller is on selected stage
CCScrollLayer *scroller = [[CCScrollLayer alloc] initWithLayers:layers
widthOffset:230];
// load selectedPage from selectedStage
[scroller selectPage:(gameData.selectedStage - 1)];
[self addChild:scroller];
Cheers
Thanks for updating and maintaining the CCScrollLayer class, it works wonderfully!
Not sure if it would be useful to anyone else, but I found it useful to be notified every time the page changed and added a simple delegate to the class. I didn't know how else to do it, other than constantly polling the currentScreen value.
@Stepan, first of all, thanks for great extensions! Is there a clean way to stop CCScrollLayer from handling multiple touches? Layers added to the scroll are very jumpy with two fingers on the screen.
@wilczarz - You would need to add something to monitor the hash values of the touches, and then make sure you are looking at the first touch you responded to.
Touches are not always passed in the order they were received, that's why you see the jumping. So you would want to use a look up dictionary and check to see if the have any touches you are already monitoring, if you are you need to focus on that touch until it's done and have your code ignore the other touches.
In the touch end, you want to remove the focused touch, and then look at other touches if there are there, and reset to that touches point, and continue scrolling as if it just touched the screen.
It's a little work to set up, I have base classes that are wrappers that will wrap the touch events with a dictionary hash so I can maintain a touch. You would probably need to add something similar to the scroll layer so it will focus on a single touch.
@wilczarz
Probably you can save scrollingTouch_ in https://github.com/cocos2d/cocos2d-iphone-extensions/blob/master/Extensions/CCScrollLayer/CCScrollLayer.m#L223
And test touch == scrollingTouch in https://github.com/cocos2d/cocos2d-iphone-extensions/blob/master/Extensions/CCScrollLayer/CCScrollLayer.m#L231 to decide - change position or not.
Feel free to open issue, or send a pull request.
Thanks!
@Stepan, I made this little modification to CCSscrollLayer and the scrolling experience is way better IMO. How can I give you the code if I don't use git?
Mail me it, or leave it here.
Ok I will only paste the snippets. I added this to CCScrollLayer.h:
// Holds the touch that started the scroll
UITouch *scrollTouch_;
and in CCScrollLayer.m:
* at the beginning of ccTouchBegan:
if( scrollTouch_ == nil ) {
scrollTouch_ = touch;
} else {
return NO;
}
* at the beginning of ccTouchMoved:
if( scrollTouch_ != touch ) {
return;
}
* at the beginning of ccTouchEnded:
if( scrollTouch_ == touch ) {
scrollTouch_ = nil;
}
Hope this helps! Cheers!
Merged in develop branch. Thanks!
BTW, i'm now working on Mac Support for CCScrollLayer.
Changes:
More properties, flexibility, delegate, etc... Check develop branch for latest changes.
Mac support (Mouse, Mouse Wheel) added.
Dynamic Pages Controls (Add/Remove pages methods) added - needs testing.
Pleae try it and let me know. Thanks!
Release branch will be created for intensive testing after closing CCBigImage transform issue (ability to rotate/scale).
https://github.com/cocos2d/cocos2d-iphone-extensions/tree/develop
@Stepan, I found a bug with this modification of mine. If you interrupt the touch in the middle of the swipe, the touch is never set to nil and the scene "freezes" in the last scroll postition. You can test this by answering a phonecall while holding the swipe touch.
I tried adding ccTouchCancelled method to release the touch, but somehow the animation is no longer visible (only start/end positions). These attempts have failed:
-(void)ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event {
[self ccTouchEnded:touch withEvent:event];
}
-(void)ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event {
if( scrollTouch_ == touch ) {
scrollTouch_ = nil;
}
}
Any ideas?
Try this:
-(void)ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event
{
scrollTouch_ = nil;
[self selectPage: currentScreen_];
}
Feel free to open an issue on the GitHub if this doesn't help.
Thanks!
This doesn't work because in ccTouchMoved you call cancelAndStoleTouch, which eventually calls ccTouchCancelled. Therefore scrollTouch_ is immiedately set to nil, and that's why there is no animation.
Since scroll layer is my only touch receiver, I commented out
//[self cancelAndStoleTouch: touch withEvent: event];
but for the sake of the component these two must coexist somehow :)
I will open an issue for this tomorrow.
Ok the issue is up! https://github.com/cocos2d/cocos2d-iphone-extensions/issues/38
hello, nice extension, have any of you guys tried to tweak it to allow moving more than one layer (page) in a single swipe? based on the swipe speed of length maybe? Right now when you swipe it, it move only 1 page. I tried to do it myself long... time ago but didn't have good luck, if any of you have any ideas or already did this and want to share, maybe I would jump into it again :)
edit: nvm
You must log in to post.