SKSpriteNode遵循bezier路径旋转

时间:2015-05-22 22:32:58

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

我正在尝试做什么:让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];
    }
}

Player.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 nodes parent是添加到GameScene的SKNode。 我用[node convertPoint:..]尝试了很多东西,但没有成功。会喜欢朝正确方向发展的一些指示。

谢谢!

2 个答案:

答案 0 :(得分:1)

我建议您使用绝对场景坐标而不是相对节点坐标来创建要遵循的路径。以下是如何执行此操作的示例:

<强> GameScene

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

CGPoint touchPoint = [touch locationInNode:self];

<强> Player.m

2)更改以下内容以在场景坐标中创建路径(请参阅注释)

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

答案 1 :(得分:0)

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

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

您还应该查看Converting Between View and Scene Coordinates