6

I have created my own solution for zooming in or out on a specific SKNode without having the zoom the entire scene, and it seems to work mostly how I would expect it to work, with 2 notable exceptions which I am hoping to get input on here. First the code (this control statement is within the touchesMoved method):

 if (touches.count == 2) {
        // this means there are two fingers on the screen
        NSArray *fingers = [touches allObjects];
        CGPoint fingOneCurr = [fingers[0] locationInNode:self];
        CGPoint fingOnePrev = [fingers[0] previousLocationInNode:self];
        CGPoint fingTwoCurr = [fingers[1] locationInNode:self];
        CGPoint fingTwoPrev = [fingers[1] previousLocationInNode:self];

        BOOL yPinch = fingOneCurr.y > fingOnePrev.y && fingTwoCurr.y < fingTwoPrev.y;
        BOOL yUnpinch = fingOneCurr.y < fingOnePrev.y && fingTwoCurr.y > fingTwoPrev.y;

        BOOL xPinch = fingOneCurr.x > fingOnePrev.x && fingTwoCurr.x < fingTwoPrev.x;
        BOOL xUnpinch = fingOneCurr.x < fingOnePrev.x && fingTwoCurr.x > fingTwoPrev.x;

        if (xUnpinch | yUnpinch) {
            if (YES) NSLog(@"This means an unpinch is happening");
            mapScale = mapScale +.02;
            [map setScale:mapScale];
        }

        if (xPinch | yPinch) {
            if (YES) NSLog(@"This means a pinch is happening");
            mapScale = mapScale - .02;
            [map setScale:mapScale];
        }
    }

Now the problems:

  1. The pinch and unpinch are not always right sometimes, and I cannot quite put my finger on when this is happening, the pinch will behave as an unpinch and vis a versa.

  2. When the pinching and unpinching is scaling the SKNode correctly, it is rarely as smooth as I would like. There is a bit of jerkiness to it which I find annoying.

Can anyone suggest improvements to this method? Thanks!

zeeple
  • 5,509
  • 12
  • 43
  • 71
  • try pinch gesture recognizer and use its scale property, no need to reinvent the wheel – CodeSmile Oct 19 '13 at 02:31
  • My understanding is that the pinch gesture recognizer could not be placed on SKNodes. – zeeple Oct 19 '13 at 02:32
  • you might need to sub class the nodes you wanna scale, then add the pinch gesture recognizer? – DogCoffee Oct 19 '13 at 04:48
  • you use the recognizers with a view, self.scene.view to be precise – CodeSmile Oct 19 '13 at 09:43
  • @LearnCocos2D I've tried (trying now actually) using a pinch recognizer in a subclass of SKNode, adding it to self.scene.view, but no luck. userInteractionEnabled is set to YES. Have you gotten recognizers to work in SKNodes? I feel like it should work but I'm having no luck. Doing it in a scene is easy, I was hoping doing it a node deeper would be simple, but no dice so far. – Ben Kane Nov 01 '13 at 19:15
  • The reason your original code sometimes unpinch when you expected a pinch (or vice versa) is because you were setting the "scaleTo" value, while Smick's answer uses the "scaleBy" version. Thus, in the original code, if you had a large pinch that set the scale to, say, 3.0 but in the subsequent pinch you slightly smaller value of 2.0, the "scaleTo" code would see that as a reduction from 3.0 to 2.0. Using scaleBy in Smick's answer, the first pinch would increase by 3.0, and the second pinch would increase by another 2.0. – Thunk Nov 27 '13 at 20:18

1 Answers1

8

This will solve your problem, thanks to Steffen for the hints.

- (void)didMoveToView:(SKView *)view
{
    UIPinchGestureRecognizer *precog = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)];
    [self.scene.view addGestureRecognizer:precog];
}

- (void)handlePinch:(UIPinchGestureRecognizer *) recognizer
{
    //NSLog(@"Pinch %f", recognizer.scale);
    //[_bg setScale:recognizer.scale];
    [_bg runAction:[SKAction scaleBy:recognizer.scale duration:0]];
    recognizer.scale = 1;
}
DogCoffee
  • 19,820
  • 10
  • 87
  • 120
  • 1
    this is far better than hat I came up with. Thanks! – zeeple Oct 20 '13 at 00:20
  • I like this solution but I am having one problem with it that I am hoping someone can help with. The pinch zoom works but the anchor of the pinching action seems to be always bottom left or upper right and the result is that the main character (hero node) ends up vanishing off the screen. Is there anyway to keep the hero node centered on the screen during the pinch/zoom? – zeeple Nov 12 '13 at 03:50
  • the scale should not change the position of the sprite. – DogCoffee Nov 12 '13 at 09:08
  • The scale does not change the position of the sprite _relative to the map_. So as the map grows increasingly larger, and naturally less of it can fit on screen, the hero grows with it and if it is on a part of the map that slides off screen, then when the zoom is finished the user needs to move the map around to find the hero again. What I would like is for the hero sprite to be the focal point of the zoom so that the hero is always on screen. Does this make sense? – zeeple Nov 12 '13 at 18:20
  • I wrestled with a similar problem of my sprites always moving up/right or down/left off screen. The problem is where I assigned subnodes in the map. The map *is* growing from its center. But, I started placing all my subnodes from 0,0 to 1024,1024 placing all children in the upper right quadrant relative to the map's center. Thus, when the map zoomed, all children slid up and right, off the screen. Once I placed the map tiles from -512,-512 to 512,512 *and* put the hero at 0,0, the hero stayed fixed and the other children moved away in equal directions during the zoom. – Thunk Nov 27 '13 at 20:30
  • If the anchor point of the map were not 0,0, but rather mid-screen, would this not be a similar if not equivalent solution? I have yet to try this but I am hoping to have time to get back to it soon. – zeeple Dec 02 '13 at 20:52