Introducing CCKit

While working on our new Cocos2D-based project we’ve talked about in previous posts, we came to the point where we needed to implement the Cocos equivalent of a UIScrollView. While we found a few community-created solutions, none of them really matched the intuitiveness and fluidity of Apple’s own UIScrollView.

What I’m going to talk about in this #iDevBlogADay post is a new set of classes I’m calling CCKit. The purpose of the library is to bridge the gap between Cocos2D and Apple’s UIKit classes. The library includes classes like CCScrollLayer (UIScrollView emulation) and CCTableLayer (UITableView emulation) which should give very close approximations to the UIKit equivalents. Additionally, the library is open source and hosted on GitHub, so feel free to include it in your own projects and even contribute if you’d like.

CCScrollLayer

The CCScrollLayer class (and both CCTableLayer and CCTableLayerCell classes) are derived from code written by Sangwoo Im in his CCTableViewSuite. The original code has provided a lot of Cocos2D-based games with good UITableView approximations. While the table view implementation feels pretty good, I felt that the scroll view implementation could go a bit further.

The CCScrollLayer class in CCKit supports nearly all of the features of Apple’s UIScrollView class, including bouncing, deceleration, and pinch-to-zoom. There are a few features missing (such as paging and directional lock) that will be added over time. I spent a lot of time playing around with values trying to get the bouncing and deceleration to feel correct. The zoom also properly mimics zooming in and out from the centroid of the two touches on the screen instead of just from the center of the screen (which is a personal pet peeve of mine).

Panning and zooming are implemented with gesture recognizers. I apologize to those wanting to deploy for targets below 3.2, but the benefits of using gesture recognizers are too numerous. For one, you can use your own gesture recognizers in cooperation with the recognizers for the scroll layer, and even set up dependencies between them (i.e., don’t pan if a long press is detected first).

Other than the aforementioned features, a CCScrollLayer works pretty much like any other CCLayer, which means you can add all of your sprites (and even other layers) to it. Here’s how to set one up:

CCScrollLayer *scrollLayer = [CCScrollLayer scrollLayerWithViewSize:[[CCDirector sharedDirector] winSize]];
scrollLayer.contentSize = CGSizeMake(5000, 5000);
 
// Add whatever you want to the scroll layer using addChild:
 
// Add the layer to the scene.
[scene addChild:scrollLayer];

CCTableLayer

CCTableLayer is still a work-in-progress, and as such isn’t ready for primetime yet. We need a UITableView implementation for our game, though, so it should be coming soon.

CCGestureRecognizer

This class was originally written by Joe Allen. Most of my changes involved cleaning up the public interface so only the functionality necessary to use the class was exposed. The original implementation also required modifying code in CCNode. I’ve removed that requirement by putting the changes in a category extension.

The class essentially acts as a wrapper for a UIGestureRecognizer. In fact, the only real functionality this class provides is the ability for your gesture recognizers to respond to node touches instead of just view touches. Now, for instance, you can set up UITapGestureRecognizers on your sprites and have each sprite respond to the tap only if it was touched.

Here’s how to set one up:

- (void)onEnterTransitionDidFinish
{
   [super onEnterTransitionDidFinish];
 
   UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] init];
 
   // Set up the tap gesture recognizer like you normally would.
 
   // You'll want to retain ccRecognizer for later use.
   CCGestureRecognizer *ccRecognizer = [CCGestureRecognizer recognizerWithRecognizer:tapGestureRecognizer target:self action:@selector(handleTapGesture:)];
   [self addGestureRecognizer:ccRecognizer];
}
 
- (void)onExit
{
   [super onExit];
 
   [self removeGestureRecognizer:ccRecognizer];
}
 
- (void)handleTapGesture:(UITapGestureRecognizer *)gestureRecognizer
{
   // Do something when this sprite/node is tapped on!
}

If you look in the CCScrollLayer.m file, you’ll see that it’s using the CCGestureRecognizer class to set up its UIPanGestureRecognizer and UIPinchGestureRecognizer.

More To Come

For the time being, the code is made with ARC in mind. If you try to run this in a non-ARC project, you’ll probably leak memory everywhere. Apple has made it clear that ARC is the future of iOS development. There’s going to be a dearth of ARC-compatible source code samples when iOS 5 is made public, so I’m hoping we can start filling that void.

As mentioned before, this library is a work-in-progress and will be added to on a constant basis. I can tell you that from our end, we’ll add things as we need them in our own games. However, if you have something you’d like to contribute, then feel free to send a pull request. Just remember that the library is solely for mimicking or allowing access to Apple’s UIKit functionality in Cocos2D.

Tags: , , ,

  • joshk

    excellent idea! looking forward to trying it out.

  • http://ablfx.com Alex

    Sounds great! Thx for this!

  • moosc

    Excelent job !!

    Suggestion, why not a merge with cocos2d-extensions?
    http://www.cocos2d-iphone.org/archives/1506

    • Jerrod Putman

      @moosc: Actually, I may eventually do that when the whole library is a bit more robust (i.e., CCTableLayer actually works). Thanks for the suggestion!

  • http://lasseklein.com Lasse

    Thank you for this addition!

    CCScrollLayer is more or less exactly what I was looking for, since it mimics UIScrollView better than any of the other alternatives I have found.

    The only thing I’m missing is the possibility to let go and toss the layer ahead with deceleration after a while as in Apple’s scroll views. Are you planning to add this?

    • Jerrod Putman

      In theory, it should already be doing this. I’ll have a look this week and see if something got broken.

    • 0xl4u

      This happens when the scroll is only in one-dimension.

  • colinator

    Hey, nice work! I’ve been working with CCScrollLayer, and I’ve got a few bugs (maybe I’m just using it wrong):
    - it doesn’t do well with retina/non retina
    - even though I have bounces turned off, sometimes I can get it to bounce when I ‘throw’ the scroll view in certain conditions
    - the bit about throwing the scroll view doesn’t seem to work that well. Not sure how to describe this, but I feel it should travel farther than it does.
    - triggering the throw/scroll is also a bit strange: for example, if the scroller is twice as tall as the screen, and it’s scrolled such that it’s almost, but not quite, at the bottom, then large swipes don’t seem to trigger a scroll.

    But great work! I feel there’s so much demand for this thing that when it gets fully optimized it’ll be a huge hit!

    • http://www.facebook.com/profile.php?id=100000494067208 Ricardo

      Thank you for your effrot of providing details video and description! I followed all steps, but I couldn’t compile that in xcode 4 — I got 20 errors as the cocos2d library or head projects couldn’t find. Is it possible for you to also cover how to do that XCode4?Thanks in advanced!

  • Nice! This is exactly what I’m looking for. Too bad it’s ARC-only. I think that is very limiting, and would it really be so much work to just do the proper memory management for backwards-compatibility? IMHO it’s way too early to assume iOS5 and ARC…

  • Pingback: T?? ? Techpot » Blog Archive » iOS??????????

  • http://twitter.com/bobmoff Fille

    Awesome work I must say. The only tiny thing I have noticed is that the scroll view does not sometimes respond when flicking very short and fast. Other then that it looks behaves very close to the “real” thing.

  • Mohsin Yaqoob Khan

    Very nice library… I was looking for the scroll , it provided me.