从触摸点开始缩放SKNode

11

我已将UIPinchGestureRecognizer添加到我的场景视图中以缩放内容。我实际上是在缩放包含所有可见内容的父节点。但是,我遇到了一个问题,就是缩放点的位置。事实上,节点从左下角开始缩放,这显然不是我想要的。我是否需要编写大量代码才能从捏合发生的点开始缩放?您能否请给出一些提示应该遵循什么方式。


你改变了节点的 anchorPoint 吗? - Andrey Gordeev
无法更改SKNode的锚点。 - Mikayil Abdullayev
4个回答

20

我一直在解决同一个问题,我的解决方案如下所示。不确定这是否是最好的方式,但到目前为止,它似乎可以工作。我使用此代码来放大和缩小具有多个SKSpriteNode子项的SKNode。子项随着SKNode按预期移动和缩放。缩放的锚点是捏合手势的位置。场景的父级SKScene和其他SKNode不受影响。所有工作都在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...

     }
}
以下是先前使用过的辅助函数。它们来自于 Ray Wenderlich 的 Sprite Kit 书籍。

以下是先前使用过的辅助函数。它们来自于 Ray Wenderlich 的 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));
}

谢谢,伙计。但是trackNodeShift是什么?你是不是指的是mySkNodeShift? - Mikayil Abdullayev
是的,应该是mySkNodeShift。当我在更改名称以使其更通用时,我错过了这个。我回去纠正了它。谢谢! - ninefifteen
我尝试了你的方法,确实有帮助。再次感谢。 - Mikayil Abdullayev
我尝试了一下,它确实起作用了,但是...并不完全符合我的预期。假设你在(200, 200)处放大了视图,然后抬起手指,在(50, 50)处缩小了视图...这一刻打破了一切。唉...有什么想法可以修复它吗? - AndrewShmig
AndrewShmig... 你能发一下你的代码吗?我没有那个问题。我可以放大或缩小,抬起手指,然后再放大或缩小,没有任何问题。 - ninefifteen
嗨,感谢您提供的代码!但是当我使用它时,它会从中心缩放而不是从触摸位置缩放。请帮忙:))) - Anton O.

3

我翻译了ninefifteen关于Swift和Pinch手势的解决方案,并花了几天时间尝试自己解决这个问题。感谢ninefifteen的Obj-C帖子!这是我使用的似乎有效的Swift版本。

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


}

这是 Ray Wenderlich 助手函数的 Swift 版本,位于 ninefifteen 的答案中:https://github.com/raywenderlich/SKTUtils/blob/master/SKTUtils/CGPoint%2BExtensions.swift - peacetype

0
在Swift 4中,我的SKSceneUIPinchGestureRecognizer添加到视图中,但将捏合手势的处理传递给其中一个在场景的init()中创建的SKNode子节点,由于这里不相关的某些原因。无论如何,这是ninefifteen从他所称的_mySkNode的角度给出的答案。它还包括一些代码来限制缩放,并且不使用他帖子底部列出的便利函数。声明中的@objc部分允许在#selector()中使用该函数。

这是我SKScene中的内容:

override func didMove(to view: SKView) {
    let pinchRecognizer: UIPinchGestureRecognizer = UIPinchGestureRecognizer(target: self.grid, action: #selector(self.grid.pinchZoomGrid))
    self.view!.addGestureRecognizer(pinchRecognizer)
}

这是我SKNode中相关的部分:

// Pinch Management
@objc func pinchZoomGrid(_ recognizer: UIPinchGestureRecognizer){
    var anchorPoint: CGPoint = recognizer.location(in: recognizer.view)
    anchorPoint = self.scene!.convertPoint(fromView: anchorPoint)

    if recognizer.state == .began {
        // No zoom code
    } else if recognizer.state == .changed {
        let anchorPointInGrid = self.convert(anchorPoint, from: self.scene!)

        // Start section that limits the zoom
        if recognizer.scale < 1.0 {
            if self.xScale * recognizer.scale < 0.6 {
                self.setScale(0.6)
            } else {
                self.setScale(self.xScale * recognizer.scale)
            }
        } else if recognizer.scale > 1.0 {
            if self.xScale * recognizer.scale > 1.5 {
                self.setScale(1.5)
            } else {
                self.setScale(self.xScale * recognizer.scale)
            }
        }
        // End section that limits the zoom

        let gridAnchorPointInScene = self.scene!.convert(anchorPointInGrid, from: self)
        let translationOfAnchorPointInScene = CGPoint(x:anchorPoint.x - gridAnchorPointInScene.x,
                                                      y:anchorPoint.y - gridAnchorPointInScene.y)

        self.position = CGPoint(x:self.position.x + translationOfAnchorPointInScene.x,
                                y:self.position.y + translationOfAnchorPointInScene.y)
        recognizer.scale = 1.0

    } else if recognizer.state == .ended {
        // No zoom code
    }
}

0

无法缩放,我不知道为什么,但主要问题是那些SKT_INLINE。我已经谷歌过它们,没有找到任何关于它们的信息...问题是当我将它们复制/粘贴到我的项目中时,编译器告诉我必须在它们后面添加一个“;”。我想知道这是否是我无法缩放的原因。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接