Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/44.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 在SpriteKit中缩放和滚动SKNode_Ios_Iphone_Uiscrollview_Scroll_Sprite Kit - Fatal编程技术网

Ios 在SpriteKit中缩放和滚动SKNode

Ios 在SpriteKit中缩放和滚动SKNode,ios,iphone,uiscrollview,scroll,sprite-kit,Ios,Iphone,Uiscrollview,Scroll,Sprite Kit,我正在SpriteKit上做一个类似拼字游戏的游戏,一直在缩放和滚动拼字板。 首先让我解释一下游戏背后的工作原理: 在我的游戏场景中,我有: 一个名为GameBoard Layer(名为GAME_BOARD_Layer)的SKNode子类,包含以下子类: A SKNode subclass for Scrabble Board named NAME_BOARD. A SKNode subclass for Letters Tile Rack named NAME_RACK. 字母瓦片从瓦片架

我正在SpriteKit上做一个类似拼字游戏的游戏,一直在缩放和滚动拼字板。 首先让我解释一下游戏背后的工作原理: 在我的游戏场景中,我有:

  • 一个名为GameBoard Layer(名为GAME_BOARD_Layer)的SKNode子类,包含以下子类:

    A SKNode subclass for Scrabble Board named NAME_BOARD.
    A SKNode subclass for Letters Tile Rack named NAME_RACK.
    
    字母瓦片从瓦片架上拣起,放在拼字板上

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

  • 放大用户双击的精确位置
  • 滚动(尝试了PanGestures,但在拖动和放置瓷砖时以某种方式产生了问题)
  • 将缩放后的SKNode保留在特定区域中(如UIScrollView将缩放后的内容保留在scrollView边界中)
以下是我使用UITapPictures进行缩放的代码:

在我的游戏场景中

- (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节点中:

- (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]];
}
}
是否有人能指导我如何实现此功能


谢谢大家。

我将这样做:

设置:

  • 创建游戏场景作为游戏的根节点。(场景之子)
  • 将BoardNode作为子节点添加到场景(SKNode的子节点)
  • 将CameraNode作为子节点添加到板(SKNode的子节点)
  • 将LetterNodes添加为电路板的子节点
使摄影机节点居中:

// 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来平移视图(记住要防止平移超出范围)


至于平移意外拖拽你的字母节点的问题,我通常实现一个TouchDispatcher(通常在GameSecene类中)来注册所有的触摸。然后,TouchDispatcher决定哪个节点应响应触摸(以及以何种顺序)。

UIView和UIGestureRecognitors可以完成类似的事情,方法是在手势开始时设置视图的定位点,并将视图向相反方向平移,以补偿定位点的变化。这样,变换的锚点就在手势下。在SKSpriteNode(它也有一个大小和锚点)上使用相同的技术几乎是可行的,但是转换后的sprite节点的子节点没有正确转换,所有事情都出错了。有没有办法解决这个问题?这个答案提供了一个有效的解决方案,只需计算一个变换来保持场景的位置。centerOnNode方法救了我!非常感谢你。
// 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.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;
    }
}