【问题标题】:SKSpriteNode follow bezier path rotationSKSpriteNode 遵循贝塞尔路径旋转
【发布时间】:2015-05-22 22:32:57
【问题描述】:

我正在尝试做的事情:使 SKSpriteNode 遵循 UIBezierPath,其中端点是用户触摸的位置。

问题:当用户触摸时,我将位置发送到处理自身移动的播放器节点。然而,这仅在玩家节点“指向”上方时才有效,例如在第一次触摸时。其他触摸会使玩家移动到错误的点。

描述问题的图片:http://i.stack.imgur.com/nleXj.png
我在 Photoshop 中添加了一些解释性的东西,所以这里是一个解释:
- 厚 > 是我要移动的 SKSpriteNode。
- 紫色方块是触摸的确切位置,按顺序编号(实际上添加了 SKSpriteNodes 用于调试目的)
- 细箭头是触摸发生时玩家的位置。

我认为问题出在玩家节点坐标系和场景坐标系之间的转换中。
例如:第一次触摸(当玩家 zRotation 没有改变时)将玩家移动到正确的位置。然而,第二次触摸是在玩家节点坐标系中的左侧,但随后它在场景坐标系中基本上是向左移动,就好像如果将触摸旋转到向上,则触摸会随着节点一起旋转。

代码:
GameScene.m:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    /* Called when a touch begins */
    for (UITouch *touch in touches) {
        [self playRiddle];

        CGPoint touchPoint = [touch locationInNode:_player];
        [_player moveTo:touchPoint];

        SKSpriteNode *n = [SKSpriteNode spriteNodeWithColor:[UIColor purpleColor] size:CGSizeMake(10, 10)];
        n.position = [self convertPoint:touchPoint fromNode:_player];
        [_worldNode addChild:n];
    }
}

玩家.m:

- (void)moveTo:(CGPoint)point {
    _moving = YES;
    [self removeActionForKey:@"move"];

    CGVector vector = [self convertAngleToVector:[self shipOrientation]];
    CGPoint controlPoint = CGPointMake(vector.dx, vector.dy);

    UIBezierPath *path = [self createPathWindEndPoint:point controlPoint:controlPoint];
    SKAction *move = [SKAction followPath:[path CGPath] asOffset:YES orientToPath:YES speed:15];
    SKAction *done = [SKAction runBlock:^{
        _moving = NO;
    }];
    [self runAction:[SKAction sequence:@[move, done]] withKey:@"move"];
}

- (UIBezierPath *)createPathWindEndPoint:(CGPoint)endpoint controlPoint:(CGPoint)cp {    
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointZero];

    [path addQuadCurveToPoint:endpoint controlPoint:cp];

    //Draw path
    SKShapeNode *line = [SKShapeNode node];
    line.path = [path CGPath];
    [line setStrokeColor:[UIColor darkGrayColor]];
    line.position = self.position;
    [self.parent addChild:line];

    return path;
}

- (CGVector)convertAngleToVector:(CGFloat)radians {
    CGVector vector;
    vector.dx = cos(radians) * 25;
    vector.dy = sin(radians) * 25;
    return vector;
}

- (CGFloat)shipOrientation {
    return self.zRotation + M_PI_2;
}

_player 节点的父节点是添加到 GameScene 的 SKNode。 我用 [node convertPoint: ..] 尝试了很多东西,但没有成功。希望有一些正确方向的指示。

谢谢!

【问题讨论】:

    标签: ios objective-c sprite-kit trigonometry uibezierpath


    【解决方案1】:

    我建议您使用绝对场景坐标而不是相对节点坐标来创建要遵循的路径。以下是如何做到这一点的示例:

    游戏场景

    1) 在touchesBegan中,进行如下修改,将触摸位置转换为场景坐标

    CGPoint touchPoint = [touch locationInNode:self];
    

    Player.m

    2) 更改以下内容以在场景坐标中创建路径(参见 cmets)

    - (void)moveTo:(CGPoint)point {
        _moving = YES;
        [self removeActionForKey:@"move"];
    
        CGVector vector = [self convertAngleToVector:[self shipOrientation]];
        // Offset the control point by the node's position
        CGPoint controlPoint = CGPointMake(vector.dx+self.position.x, vector.dy+self.position.y);
    
        UIBezierPath *path = [self createPathWindEndPoint:point controlPoint:controlPoint];
        // Use absolute path
        SKAction *move = [SKAction followPath:[path CGPath] asOffset:NO orientToPath:YES speed:15];
    
        SKAction *done = [SKAction runBlock:^{
            _moving = NO;
        }];
        [self runAction:[SKAction sequence:@[move, done]] withKey:@"move"];
    }
    
    - (UIBezierPath *)createPathWindEndPoint:(CGPoint)endpoint controlPoint:(CGPoint)cp {
        UIBezierPath *path = [UIBezierPath bezierPath];
        // Use scene coordinates
        [path moveToPoint:self.position];
    
        [path addQuadCurveToPoint:endpoint controlPoint:cp];
    
        //Draw path
        SKShapeNode *line = [SKShapeNode node];
        line.path = [path CGPath];
        [line setStrokeColor:[UIColor darkGrayColor]];
        // Line relative to the origin
        line.position = CGPointZero;
        [self.parent addChild:line];
    
        return path;
    }
    

    【讨论】:

      【解决方案2】:

      如果您希望在节点与其父节点之间转换点,请尝试以下代码:

      CGPoint myPoint = [self convertPoint:myNode.position fromNode:myNode.parent];
      

      你也应该看看Converting Between View and Scene Coordinates

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-09-10
        • 2023-03-27
        • 2019-07-27
        • 2021-10-30
        • 2011-03-30
        • 2011-02-26
        • 2017-05-18
        相关资源
        最近更新 更多