在SpriteKit中缩放和滚动SKNode [英] Zoom and Scroll SKNode in SpriteKit

查看:152
本文介绍了在SpriteKit中缩放和滚动SKNode的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作像SpriteKit上的Scrabble这样的游戏,并且一直停留在Scoble和Scrolling Scrabble Board上。
首先让我解释游戏背后的工作:
在我的GameScene上我有:

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 GameScene I Have:


  • A名为GameBoard Layer(名为NAME_GAME_BOARD_LAYER)的SKNode子类包含以下子项:

  • A SKNode subclass called GameBoard Layer (named NAME_GAME_BOARD_LAYER) containing following Children:

A SKNode subclass for Scrabble Board named NAME_BOARD.
A SKNode subclass for Letters Tile Rack named NAME_RACK.

Letters Tiles从Tile Rack中挑选并放入Scrabble Board。

The Letters Tiles are picked from the Tile Rack and dropped at the Scrabble Board.

这里的问题是,我需要模仿UIScrollView可以实现的缩放和滚动,我认为不能添加到SKNode。我需要模仿的功能是:

The problem here is, I need to mimic the zooming and scrolling which can be achieved by UIScrollView, which I think cant be added on a SKNode. The Features I need to mimic are:


  • 放大用户双击的精确位置

  • 滚动(尝试PanGestures,以某种方式创建拖动窗格的问题)

  • 将Zoomed SKNode保留在特定区域(与UIScrollView一样,将缩放的内容保留在scrollView边界内)

以下是我用于缩放的代码,使用UITapGestures:

Here is the Code I have used for Zooming, using UITapGestures:

在我的GameScene.m

In my GameScene.m

- (void)didMoveToView:(SKView *)view {
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self
                                                                             action:@selector(handleTapGesture:)];
tapGesture.numberOfTapsRequired = 2;
tapGesture.numberOfTouchesRequired = 1;
[self.scene.view addGestureRecognizer:tapGesture];
}

- (void)handleTapGesture:(UITapGestureRecognizer*)recognizer {
if ([self childNodeWithName:NAME_GAME_BOARD_LAYER]) {
    GameBoardLayer *gameBoardLayer = (GameBoardLayer*)[self childNodeWithName:NAME_GAME_BOARD_LAYER];

    SKNode *node = [Utils nodeAt:[recognizer locationInView:self.view]
                        withName:NAME_BOARD
                   inCurrentNode:gameBoardLayer];

    if ([node.name isEqualToString:NAME_BOARD]) {
        [gameBoardLayer handleDoubleTap:recognizer];
    }

}
}

在我的GameBoardLayer节点:

In my GameBoardLayer Node:

- (void)handleDoubleTap:(UITapGestureRecognizer*)recognizer {
Board *board = (Board*)[self childNodeWithName:NAME_BOARD];
if (isBoardZoomed)
{
    [board runAction:[SKAction scaleTo:1.0f duration:0.25f]];
    isBoardZoomed = NO;
}
else
{
    isBoardZoomed = YES;
    [board runAction:[SKAction scaleTo:1.5f duration:0.25f]];
}
}

有人会指导我如何实现此功能?

Would someone kindly guide me how can i achieve this functionality?

谢谢大家。

推荐答案

这就是我要做的这个:

设置:


  • 创建一个GameScene作为游戏的rootNode 。 (SKScene的孩子)

  • 将BoardNode作为子项添加到场景中(SKNode的子项)

  • 将CameraNode作为子项添加到Board(SKNode的子项) )

  • 添加LetterNodes作为董事会的子女

  • 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

保持Camera节点居中:

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);
}

通过移动BoardNode来平移视图(记住防止平移越界)

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)));
}

通过设置GameScene的大小来缩放:

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;
    }
}

崩溃意外拖动LetterNodes的问题是什么,我通常会实现一个TouchDispatcher(通常在GameScene类中)来记录所有的触摸。然后,TouchDispatcher决定哪个节点应该响应触摸(以及以哪种顺序)。

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).

这篇关于在SpriteKit中缩放和滚动SKNode的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆