Zoom and Scroll SKNode in SpriteKit

后端 未结 1 776
心在旅途
心在旅途 2020-12-25 08:10

I am working on a Game like Scrabble on SpriteKit and have been stuck on Zooming and Scrolling the Scrabble Board. First Let me Explain the working behind the game: On my Ga

相关标签:
1条回答
  • 2020-12-25 08:51

    This is how I would do this:

    Setup:

    • Create a GameScene as the rootNode of your game. (child of SKScene)
    • Add BoardNode as child to the scene (child of SKNode)
    • Add CameraNode as child to the Board (child of SKNode)
    • Add LetterNodes as children of the Board

    Keep Camera node centered:

    // GameScene.m
    - (void) didSimulatePhysics
    {
         [super didSimulatePhysics];
         [self centerOnNode:self.Board.Camera];
    }
    
    - (void) centerOnNode:(SKNode*)node
    {
        CGPoint posInScene = [node.scene convertPoint:node.position fromNode:node.parent];
        node.parent.position = CGPointMake(node.parent.position.x - posInScene.x, node.parent.position.y - posInScene.y);
    }
    

    Pan view by moving BoardNode around (Remember to prevent panning out of bounds)

    // GameScene.m
    - (void) handlePan:(UIPanGestureRecognizer *)pan
    {
        if (pan.state == UIGestureRecognizerStateChanged)
        {
            [self.Board.Camera moveCamera:CGVectorMake([pan translationInView:pan.view].x, [pan translationInView:pan.view].y)];
        }
    }
    
    // CameraNode.m
    - (void) moveCamera:(CGVector)direction
    {
        self.direction = direction;
    }
    
    - (void) update:(CFTimeInterval)dt
    {
        if (ABS(self.direction.dx) > 0 || ABS(self.direction.dy) > 0)
        {
            float dx = self.direction.dx - self.direction.dx/20;
            float dy = self.direction.dy - self.direction.dy/20;
            if (ABS(dx) < 1.0f && ABS(dy) < 1.0f)
            {
                dx = 0.0;
                dy = 0.0;
            }
            self.direction = CGVectorMake(dx, dy);
            self.Board.position = CGPointMake(self.position.x - self.direction.dx, self.position.y + self.direction.dy);
        }
    }
    
    // BoardNode.m
    - (void) setPosition:(CGPoint)position
    {
        CGRect bounds = CGRectMake(-boardSize.width/2, -boardSize.height/2, boardSize.width, boardSize.height);
    
        self.position = CGPointMake(
            MAX(bounds.origin.x, MIN(bounds.origin.x + bounds.size.width, position.x)),
            MAX(bounds.origin.y, MIN(bounds.origin.y + bounds.size.height, position.y)));
    }
    

    Pinch Zoom by setting the size of your GameScene:

    // GameScene.m
    - (void) didMoveToView:(SKView*)view
    {
        self.scaleMode = SKSceneScaleModeAspectFill;
    }
    
    - (void) handlePinch:(UIPinchGestureRecognizer *)pinch
    {
        switch (pinch.state)
        {
            case UIGestureRecognizerStateBegan:
            {
                self.origPoint = [self GetGesture:pinch LocationInNode:self.Board];
                self.lastScale = pinch.scale;
            } break;
    
            case UIGestureRecognizerStateChanged:
            {
                CGPoint pinchPoint = [self GetGesture:pinch LocationInNode:self.Board];
                float scale = 1 - (self.lastScale - pinch.scale);
    
                float newWidth = MAX(kMinSceneWidth, MIN(kMaxSceneWidth, self.size.width / scale));
                float newHeight = MAX(kMinSceneHeight, MIN(kMaxSceneHeight, self.size.height / scale));
    
                [self.gameScene setSize:CGSizeMake(newWidth, newHeight)];                
                self.lastScale = pinch.scale;
    
            } break;
    
            default: break;
        }
    }
    

    What comes to the problem of panning accidentally dragging your LetterNodes, I usually implement a single TouchDispatcher (usually in GameScene class) that registers all the touches. TouchDispatcher then decides which node(s) should respond to the touch (and in which order).

    0 讨论(0)
提交回复
热议问题