Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

Scrolling List using Sprite Kit

I am attempting to make a scrolling list using Sprite Kit. I have successfully implemented the scrolling thanks to the a current github project (https://github.com/bobmoff/ScrollKit), but am still unable to detect touches.

The ScrollViewDelegate, I am guessing, must be interfering with the basic "touchesBegan" and other recognizers that are built in Sprite Kit.

I have also attempted to add UIGestureRecognizers, but they don't seem to be calling their selector methods.

If anyone has any pointers or solutions, it would be greatly appreciated!

1 Answer

if you are using a UIScrollView, you may have to detect touches in the viewController, not in your SKScene. what are you currently doing?

using gesture recognizers is probably the way to go without subclassing UIScrollView. can you post some code of how you implemented your gesture recognizers

@interface MainScene ()
@property (nonatomic) SKNode *swipeLayer;
@end

@implementation MainScene
{
    CGFloat topSpotHeight;
    CGFloat tHeight;
    CGFloat tWidth;
    BOOL detailViewIsOpen;
}


- (instancetype) initWithSize:(CGSize)size
{
    if (self = [super initWithSize:size])
    {
        self.backgroundColor = [UIColor blackColor];

        tWidth          = self.size.width;
        tHeight         = self.size.height;
        topSpotHeight   = tHeight * 0.9;

        detailViewIsOpen        = NO;
        NSUInteger itemCount    = 10;
        self.swipeLayer         = [SKNode new];

        for (int i = 0; i < 10; i++)
        {
            SKSpriteNode *sprite = (SKSpriteNode *)[self listItemForRow:i + 1 andWidth:tWidth andHeight:tHeight / itemCount - 5];
            sprite.position = CGPointMake(tWidth / 2, tHeight - (tHeight / itemCount * (i + 1)));
            sprite.name = @"movable";
            [self.swipeLayer addChild:sprite];
        }
        [self addChild:self.swipeLayer];
    }
    return self;
}

- (void)didMoveToView:(SKView *)view
{
    swipeDownRecognizer             = [[UISwipeGestureRecognizer alloc] initWithTarget:self
                                                                                action:@selector(handleSwipes:)];
    swipeUpRecognizer               = [[UISwipeGestureRecognizer alloc] initWithTarget:self
                                                                                action:@selector(handleSwipes:)];
    tapGestureRecognzier            = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                              action:@selector(handleTapsFrom:)];
    swipeUpRecognizer.direction     = UISwipeGestureRecognizerDirectionUp;
    swipeDownRecognizer.direction   = UISwipeGestureRecognizerDirectionDown;

    [self.view addGestureRecognizer:swipeDownRecognizer];
    [self.view addGestureRecognizer:swipeUpRecognizer];
    [self.view addGestureRecognizer:tapGestureRecognzier];

    [tapGestureRecognzier requireGestureRecognizerToFail:swipeUpRecognizer];
    [tapGestureRecognzier requireGestureRecognizerToFail:swipeDownRecognizer];
}

- (void) handleSwipes: (UISwipeGestureRecognizer *)sender
{
    if (sender.direction == UISwipeGestureRecognizerDirectionDown && !detailViewIsOpen)    // && Not at Top
    {
        CGFloat moveUp = 100.0f;
        [self.swipeLayer runAction:[SKAction moveByX:0.0f y:moveUp duration:0.1]];
    }
    else if (sender.direction == UISwipeGestureRecognizerDirectionUp && !detailViewIsOpen) // && Not at Bottom
    {
        CGFloat moveDown = -100.0f;
        [self.swipeLayer runAction:[SKAction moveByX:0.0f y:moveDown duration:0.1]];
    }
}

- (void) handleTapsFrom: (UITapGestureRecognizer *)sender
{
    CGPoint touchPoint = [sender locationInView:self.view];
    SKSpriteNode *node = (SKSpriteNode *)[self.scene nodeAtPoint:touchPoint];
    if ([node.name isEqualToString:@"movable"] && !detailViewIsOpen)
    {
        detailViewIsOpen = YES;
        [node runAction:[SKAction moveTo:CGPointMake(tWidth / 2, topSpotHeight) duration:0.5] completion:^
        {
            SKSpriteNode *detailNode = [SKSpriteNode spriteNodeWithColor:[SKColor orangeColor] size:CGSizeMake(tWidth, tWidth)];
            detailNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
            detailNode.name = @"detail";
            [self.swipeLayer addChild:detailNode];
        }];
        NSLog(@"Open That List Item");
    }
    else if (detailViewIsOpen && [node.name isEqualToString:@"detail"])
    {
        NSLog(@"Detail Node Touched");
    }
}


# pragma mark - Helper Methods

- (SKSpriteNode *) listItemForRow:(NSInteger)row andWidth:(CGFloat)width andHeight:(CGFloat)height
{
    SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithColor:[SKColor blueColor] size:CGSizeMake(width, height)];
    SKLabelNode *label = [SKLabelNode labelNodeWithText:[NSString stringWithFormat:@"%ld", (long)row]];
    label.fontName = @"HelveticaNeue-Black";
    label.name = @"label";
    label.fontColor = [SKColor whiteColor];
    label.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter;

    [sprite addChild:label];

    return sprite;
}

@end 

Here is my Scene that I am creating the table like list in. I rebuilt it to show the basics on here, but I am having a hard time with the selection of a particular "cell" or "list item node."

yeah you might have to implement the UIKit (gesture recognizers etc) stuff in your viewController, not your scene. SpriteKit does not really play well with UIKit.

Is there anyway you could point me in the right direction towards implementing it into the View Controller?

The reason I chose to go with the Scene and not the VC, is because I will need a slight variation of this functionality in two of the 3 scenes that will be presented.

you might want to lean more on the sprite kit side of things then (using SKNode touch methods instead of gesture recognizers etc) depending on what you want to do.

Really thats probably the best idea since UIKit is probably better suited to creating game menus instead of being used for actual gameplay logic. But that might make implementing your scroll view problematic as well.

What exactly are you trying to accomplish

sorry for the delay, I have been trying to respond, but the site was down

That's exactly the scenario I am running into with the Scroll View and/or Table View implementation.

From what I am able to gather though, as long as I remove all UIKit references (including gesture recognizers) in the -willMoveFromView and declare them in the -didMoveToView, they should be working as expected.

I am waiting to hear back from the team who put this up (crossing my fingers) http://benjaminbojko.com/work/ken-burns/

Here's Exactly what I am trying to accomplish:

Login/Signup

Home Scene (two CGRects responding to touchesBegan)

  • SceneARect if(touched) present corresponding SceneA √
  • SceneBRect if(touched) present corresponding SceneB √

SceneA

  • List of items that have a corresponding Sprite that displays upon click √
  • Corresponding Sprite responds to Tap Gesture Recognizer (for PinSprite placement) √

I run into a problem when the list exceeds the screen frame and I try to implement a scrolling feature

SceneB

  • List of items associated with Corresponding SceneA item sprite √
  • Present SceneA with Corresponding Sprite Displayed ?

wow that app is cool. yeah merging UIKit and sprite kit can be a challenge, and Im afraid I dont really know enough sprite kit stuff to be of much help at this point

I see that you're in Texas? I actually just moved to Dallas and my team and I are looking to bring on another developer.

If you are at all interested, I would love to discuss the app and it's entirety with you to gauge your interest and fit for the team...

Shoot me an email:

chrishayes.dev@gmail.com

yeah I live in Lubbock and go to Texas Tech. cool ill shoot you an email

Hi Chris, I'm wondering if you ever figured out how to handle touches using the ScrollKit framework you mention in this question? Looking to do basically this same thing.

Ended up finding this, which totally worked: http://stackoverflow.com/a/30016071/2752214