Tiny Defense: Using UIScrollView in Cocos2d by Sash

So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch.

Most of my time I was working on a solution to implementing scrollviews in cocos2d. Turns out this isn’t as straight forward as I thought, but I found a tutorial over at getsetgames.com which gave me a good place to start. I have to warn you, the code in that tutorial is pretty messy. I’ve cleaned it up a lot below.

The Problem

Cocos 2d has no equivalent to UIScrollView. You can’t even use the regular UIScrollview, since it doesn’t fit into the framework. This leaves you with two possible solutions:

  1. Reverse engineer the UIScroll View
    This would take a long time to get right. Apple has put a lot of polish into making the touch interactions perfect. There are a ton of edge cases and the code is not available to copy. Ouch.
  2. Implement an invisible UIScrollView
    And use its contentOffset property to position your CCNode. Much better!

The later solution is much cleaner and has a straight forward implementation. Basically it works like this. We subclass UIScrollView, make sure it is invisible, put it on top of Cocos2d so that the user is interacting with it, then take the scroll position and apply it to the stuff in cocos2D each frame. There are a few challenges that we will have a look at, but check out the code I wrote first:

Code: CCScrollView.h

#import "cocos2d.h"

@interface CCScrollView : UIScrollView

+ (CCScrollView *) makeScrollViewWithWidth:(int)width Height:(int)height;

- (void)setWidth:(int)width Height:(int)height;
- (int) getOffset;
- (CGPoint) getOffsetAsPoint;

@end

Code: CCScrollView.m

#import "CCScrollView.h"

@implementation CCScrollView

/*
* Returns a CCScrollView Object.
* You can treat this like a regular UIScrollView, but don't add subviews. Instead
* use the methods getOffset and getOffsetAsPoint to set the Y Position of the
* CCNode you want to scroll each frame
*/
+(CCScrollView *) makeScrollViewWithWidth:(int)width Height:(int)height
{
   CCScrollView * scrollView =
     [[CCScrollView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
   scrollView.contentSize = CGSizeMake(width, height);
   scrollView.showsHorizontalScrollIndicator = NO;
   scrollView.showsVerticalScrollIndicator = NO;
   [scrollView setUserInteractionEnabled:TRUE];
   [scrollView setScrollEnabled:TRUE];

   [[[CCDirector sharedDirector] openGLView] addSubview:scrollView];

   return scrollView;
}

/*
* Change the size of the scrollable area
*/
- (void)setWidth:(int)width Height:(int)height
{
   self.contentSize = CGSizeMake(width, height);
}

/*
* Returns the offset of the scrollview as a point
*/
- (CGPoint) getOffsetAsPoint
{
   CGPoint offset = [self contentOffset];
   offset = [[CCDirector sharedDirector] convertToGL: offset];
   offset.y *= -1;
   offset.x *= -1;

   return offset;
}

/*
* Returns the Y co-ordinate of the offset of the ScrollView
*/
- (int) getOffset
{
   CGPoint offset = [self getOffsetAsPoint];
   return offset.y;
}

- (void) dealloc
{
   [self removeFromSuperview];
   [super dealloc];
}

/*
* Override touch functions
* This allows Cocos2d to process touches
*/
-(void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event
{
   if (!self.dragging)
      [[[CCDirector sharedDirector] openGLView] touchesBegan:touches withEvent:event];

   [super touchesBegan: touches withEvent: event];
}

-(void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event
{
   if (!self.dragging)
      [[[CCDirector sharedDirector] openGLView] touchesEnded:touches withEvent:event];

   [super touchesEnded: touches withEvent: event];
}
@end

Code: Implementation.m

//
//  Implementation.m
//  TinyDefense
//
//  Created by Sasha MacKinnon on 21/09/11.
//  Copyright 2011 Bit Battalion. All rights reserved.
//

#import "Implementation.h"

@implementation Implementation

+ (CCScene *) scene
{
    CCScene * s = [CCScene node];
    Implementation * l = [Implementation node];
    [s addChild:l];

    return s;
}

- (id)init
{
    if (self = [super init])
    {
        gameNode = [[CCNode alloc] init];

        //add the background to the game
        background = [CCSprite spriteWithFile:@"background.png"];
        background.position = ccp(160, 480);
        [gameNode addChild:background];
        [self addChild: gameNode];

        //set up scrolling
        scrollView = [CCScrollView makeScrollViewWithWidth:320 Height:960];

        [self schedule:@selector(enterFrame:)];
    }

    return self;
}

- (void) enterFrame: (ccTime) dt
{
    gameNode.position = ccp(0, [scrollView getOffset]);
}
@end

Setting up the UIScrollView

We want an easy way to create scroll views without having to go through the hassle of manually allocing and setting properties every time w need a new one. The makeScrollViewWithWidth method does just this. It:

  • creates the scroll view,
  • sets its content size to the arguments
  • adds itself to the OpenGLView, so it appears on the screen
+(CCScrollView *) makeScrollViewWithWidth:(int)width Height:(int)height
{
    CCScrollView * scrollView =
       [[CCScrollView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
    scrollView.contentSize = CGSizeMake(width, height);
    scrollView.showsHorizontalScrollIndicator = NO;
    scrollView.showsVerticalScrollIndicator = NO;
    [scrollView setUserInteractionEnabled:TRUE];
    [scrollView setScrollEnabled:TRUE];

    [[[CCDirector sharedDirector] openGLView] addSubview:scrollView];

    return scrollView;
}

The contentOffset Property

Next we need is to be able to access the position of our ScrollView after the user has scrolled. Since CCScrollView is a subclass of UIScrollView, we could access the “contentOffset” property directly, but we need to do a few transformations on that before hand to make it work the way we want. I made getter methods to make life easier:

- (CGPoint) getOffsetAsPoint
{
    CGPoint offset = [self contentOffset];
    offset = [[CCDirector sharedDirector] convertToGL: offset];
    offset.y *= -1;
    offset.x *= -1;

    return offset;
}

- (int) getOffset
{
    CGPoint offset = [self getOffsetAsPoint];
    return offset.y;
}

Making sure touches are registered by cocos2D

Right now we can have elements scrolling on the screen, but we can’t touch any of them. This is because CCScrollView is sitting on top of cocos2d, so the touches stop being processed before they hit cocos2D. To solve this we override touchBegan and touchEnd, and pass the touches down to cocos2D

-(void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event
{
    if (!self.dragging)
        [[[CCDirector sharedDirector] openGLView] touchesBegan:touches withEvent:event];
    [super touchesBegan: touches withEvent: event];
}

-(void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event
{
    if (!self.dragging)
        [[[CCDirector sharedDirector] openGLView] touchesEnded:touches withEvent:event];
    [super touchesEnded: touches withEvent: event];
}

Fixing the content offset bug

But it STILL won’t work. Cocos2D, for some weird reason, isn’t prepared to deal with the touches we get from UIScrollView. It offsets the touches by a small margin when you scroll down far enough. I found a great solution online, which requires a quick change to CCNode.m

http://stackoverflow.com/questions/2457380/uiscrollview-and-cocos2d

Basically replace these functions in CCNode.m:

- (CGPoint)convertTouchToNodeSpace:(UITouch *)touch {
    // cocos2d 1.0 rc bug when using with additional overlayed views (such as UIScrollView).
    // CGPoint point = [touch locationInView: [touch view]];
    CGPoint point = [touch locationInView: [[CCDirector sharedDirector] openGLView]];
    point = [[CCDirector sharedDirector] convertToGL: point];
    return [self convertToNodeSpace:point];
}

- (CGPoint)convertTouchToNodeSpaceAR:(UITouch *)touch {
    // cocos2d 1.0 rc bug when using with additional overlayed views (such as UIScrollView).
    // CGPoint point = [touch locationInView: [touch view]];
    CGPoint point = [touch locationInView: [[CCDirector sharedDirector] openGLView]];
    point = [[CCDirector sharedDirector] convertToGL: point];
    return [self convertToNodeSpaceAR:point];
}

and CCMenu.m

-(CCMenuItem *) itemForTouch: (UITouch *) touch {
    // cocos2d 1.0 rc bug when using with additional overlayed views (such as UIScrollView).
    // CGPoint touchLocation = [touch locationInView: [touch view]];
    CGPoint touchLocation = [touch locationInView: [[CCDirector sharedDirector] openGLView]];
    touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
    ...

And now it’s ready to go!! The code is here in full, so feel free to copy paste these classes.

Fixing it for iOS 5

After all this, it might still not work with iOS 5. Instead of explaining why, I’ll point you to a stack overflow answer that has the solution:

Animation in OpenGL ES view freezes when UIScrollView is dragged on the iPhone

Whats Next

I’ve done a ton of work since I made this video which I’ll post in a few days. Tonight, I’m travelling back to Australia! I’m hoping to get a bit of code written on the plane before my battery dies. Wish me luck!


Discussion

  1. [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  2. Agen Judi Bola linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  3. [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  4. Free how to guides linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  5. beylikdüzü escort linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  6. smartphone repair linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  7. [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  8. beylikdüzü escort linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  9. beylikdüzü escort linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  10. beylikdüzü escort linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  11. [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  12. [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  13. Piece Of Heaven linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  14. Google linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  15. fukuidatumou linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  16. fukuidatumou linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  17. 色情管 linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  18. Fun88 China linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  19. iptv linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  20. best coffee inc linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  21. [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  22. coffee-beans-inc linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  23. beylikdüzü escort linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  24. [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  25. [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  26. fish tanks linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  27. ücretsiz indir linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  28. senior care agencies linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  29. [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  30. Buy ig Likes linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  31. her explanation linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  32. escortsinorlando.com linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  33. Maria Johnsen linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  34. Program indir linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  35. Taz beats linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  36. got paid linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  37. عروض رمضان linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  38. quality beats linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  39. QWEQEWQE linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  40. best gourmet linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  41. whole coffee beans linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  42. outdoor camping linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  43. descargar programs linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  44. lawn & garden linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  45. live rock linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  46. windows programas linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  47. Fidelity exams linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  48. [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  49. app maker linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

  50. beylikdüzü escort linked here

    [... So as you know that I spent the weekend trying to get xcode, objective c and cocos2d to be my bitch. Most of my time I was working on a solution ...]

Leave a Comment