Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SKNode scale from the touched point

I have added UIPinchGestureRecognizer to my scene.view to scale my content. I actually scale the parent node where all my visible contents reside. But I have problem though with scaling point. The thing is node scale from the lower-left corner. It's definitely not what I want. Do I have to write lots of code to be able to scale from the point where pinching occurs? Could you please give some hints as to what way to follow.

like image 520
Mikayil Abdullayev Avatar asked Feb 20 '14 07:02

Mikayil Abdullayev


2 Answers

I have translated ninefifteen's solution for Swift and Pinch Gestures. I spent a couple days trying to get this to work on my own. Thank goodness for ninefifteen's Obj-C post! Here is the Swift version that appears to be working for me.

func scaleExperiment(_ sender: UIPinchGestureRecognizer) {


    var anchorPoint = sender.location(in: sender.view)

    anchorPoint = self.convertPoint(fromView: anchorPoint)

    let anchorPointInMySkNode = _mySkNode.convert(anchorPoint, from: self)

    _mySkNode.setScale(_mySkNode.xScale * sender.scale)

    let mySkNodeAnchorPointInScene = self.convert(anchorPointInMySkNode, from: _mySkNode)

    let translationOfAnchorInScene = (x: anchorPoint.x - mySkNodeAnchorPointInScene.x, y: anchorPoint.y - mySkNodeAnchorPointInScene.y)

    _mySkNode.position = CGPoint(x: _mySkNode.position.x + translationOfAnchorInScene.x, y: _mySkNode.position.y + translationOfAnchorInScene.y)

    sender.scale = 1.0


}
like image 184
Dave Levy Avatar answered Nov 14 '22 02:11

Dave Levy


I have been working on the same problem and my solution is shown below. Not sure if it is the best way to do it, but so far it seems to work. I'm using this code to zoom in and out of an SKNode that has several SKSpriteNode children. The children all move and scale with the SKNode as desired. The anchor point for the scaling is the location of the pinch gesture. The parent SKScene and other SKNodes in the scene are not affected. All of the work takes place during recognizer.state == UIGestureRecognizerStateChanged.

// instance variables of MyScene.
SKNode *_mySkNode;
UIPinchGestureRecognizer *_pinchGestureRecognizer;

- (void)didMoveToView:(SKView *)view
{
    _pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handleZoomFrom:)];
    [[self view] addGestureRecognizer:_pinchGestureRecognizer];
}

// Method that is called by my UIPinchGestureRecognizer.
- (void)handleZoomFrom:(UIPinchGestureRecognizer *)recognizer
{
     CGPoint anchorPoint = [recognizer locationInView:recognizer.view];
     anchorPoint = [self convertPointFromView:anchorPoint];

     if (recognizer.state == UIGestureRecognizerStateBegan) {

         // No code needed for zooming...

     } else if (recognizer.state == UIGestureRecognizerStateChanged) {

         CGPoint anchorPointInMySkNode = [_mySkNode convertPoint:anchorPoint fromNode:self];

         [_mySkNode setScale:(_mySkNode.xScale * recognizer.scale)];

         CGPoint mySkNodeAnchorPointInScene = [self convertPoint:anchorPointInMySkNode fromNode:_mySkNode];
         CGPoint translationOfAnchorInScene = CGPointSubtract(anchorPoint, mySkNodeAnchorPointInScene);

         _mySkNode.position = CGPointAdd(_mySkNode.position, translationOfAnchorInScene);

         recognizer.scale = 1.0;

     } else if (recognizer.state == UIGestureRecognizerStateEnded) {

         // No code needed here for zooming...

     }
}

The following are helper functions that were used above. They are from the Ray Wenderlich book on Sprite Kit.

SKT_INLINE CGPoint CGPointAdd(CGPoint point1, CGPoint point2) {
    return CGPointMake(point1.x + point2.x, point1.y + point2.y);
}

SKT_INLINE CGPoint CGPointSubtract(CGPoint point1, CGPoint point2) {
    return CGPointMake(point1.x - point2.x, point1.y - point2.y);
}

SKT_INLINE GLKVector2 GLKVector2FromCGPoint(CGPoint point) {
    return GLKVector2Make(point.x, point.y);
}

SKT_INLINE CGPoint CGPointFromGLKVector2(GLKVector2 vector) {
    return CGPointMake(vector.x, vector.y);
}

SKT_INLINE CGPoint CGPointMultiplyScalar(CGPoint point, CGFloat value) {
    return CGPointFromGLKVector2(GLKVector2MultiplyScalar(GLKVector2FromCGPoint(point), value));
}
like image 31
ninefifteen Avatar answered Nov 14 '22 04:11

ninefifteen