使用贝塞尔曲线方程来找到SKNode在spritekit中移动时的路径点

时间:2015-01-22 07:10:19

标签: objective-c performance uibezierpath

最近我在Spritekit中编码 我需要的是在SKNode移动时找到贝塞尔曲线的一个点跟随UIBezierPath.BTW贝塞尔曲线只有一个控制点。 我使用贝塞尔曲线方程来找到' t'并使用这个' t'为了得到这一点,我发现我的代码恰好符合"直线" bezier曲线。如果有一条大曲线,我就错了,我认为SKNode的速度不恒定。我很高兴知道哪里不对或得到其他解决方案。 这是我的代码,它用于测试。

-(void)setupTestCurve
{
    float ts =0.56f;
    float timeofmove = 5.0f;
    SKSpriteNode* arrow = [SKSpriteNode spriteNodeWithImageNamed:@"blue_b_01"];

    arrow.scale = 0.8;
    arrow.anchorPoint = CGPointMake(0.5, 0.5);

    [background addChild:arrow];

    CGPoint point1 = CGPointMake(400, 400);
    CGPoint point2 = CGPointMake(800, 100);
    CGPoint controlP = CGPointMake(100, 100);
    [ToolObjective setupTestCurve:(SKSpriteNode *)background startp:point1 endp:point2 anchorPoint:controlP];

    CGPoint ps = [ToolObjective get3dPointbezierInterpolation:ts startp:point1 controlp:controlP endp:point2];
    float twill = [ToolObjective get3dTofbezierInterpolation:point1 nowPoint:ps endp:point2 anchorPoint:controlP];

    SKAction *w = [SKAction waitForDuration:twill * timeofmove];
    SKAction *paction = [SKAction runBlock:^{
        [ToolObjective setupTestpoint:background startp:ps color:[UIColor redColor]];
    }];

    SKAction *m = [SKAction sequence:@[w,paction]];

    CGPathRef patharrow = [ToolObjective Get3dBezierPath:point1 endPoint:point2 anchorPoint:controlP];

    SKAction *moveBow = [SKAction followPath:patharrow asOffset:NO orientToPath:YES duration:timeofmove];

    [arrow runAction:[SKAction group:@[m,moveBow]]];
}

这是工具功能

/*
add a bezier curve to the background
*/
+(void)setupTestCurve:(SKSpriteNode *)background startp:(CGPoint)startPoint endp:(CGPoint)endpoint anchorPoint:(CGPoint)anchorPoint
{
    UIBezierPath *path=[UIBezierPath bezierPath];
    [path moveToPoint:startPoint];
    [path addQuadCurveToPoint:endpoint controlPoint:anchorPoint];
    SKShapeNode *circle = [SKShapeNode node];
    circle.path = path.CGPath;
    [background addChild:circle];
}
/*
get point on a bezier curve with 't'
*/
+(CGPoint) get3dPointbezierInterpolation:(CGFloat)t startp:(CGPoint)startp controlp:(CGPoint)controlp endp:(CGPoint)endp
{
    CGFloat q0x = (1 - t) * startp.x + t * controlp.x;
    CGFloat q1x = (1 - t) * controlp.x + t * endp.x;
    CGFloat x = (1 - t) * q0x + t * q1x;

    CGFloat q0y = (1 - t) * startp.y + t * controlp.y;
    CGFloat q1y = (1 - t) * controlp.y + t * endp.y;
    CGFloat y = (1 - t) * q0y + t * q1y;

    return CGPointMake(x, y);
}
/*
get 't' of a bezier curve with a point on this bezier curve
*/
+(CGFloat) get3dTofbezierInterpolation:(CGPoint)startp nowPoint:(CGPoint)nowp endp:(CGPoint)endp anchorPoint:(CGPoint)controlp
{
    CGFloat ax = (startp.x - 2 * controlp.x + endp.x);
    CGFloat bx = (2 * (controlp.x - startp.x));
    CGFloat cx = (startp.x - nowp.x);

    CGFloat tx1,tx2;

    CGFloat px = bx * bx - 4 * ax * cx;

    if (px >= 0) {
        tx1 = (-bx + sqrt(px)) / (2 * ax);
        tx2 = (-bx - sqrt(px)) / (2 * ax);
    }

    if (tx1 == tx2) {
        return tx1;
    }

    CGFloat ay = (startp.y - 2 * controlp.y + endp.y);
    CGFloat by = (2 * (controlp.y - startp.y));
    CGFloat cy = (startp.y - nowp.y);

    CGFloat ty1,ty2;

    CGFloat py = by * by - 4 * ay * cy;

    if (py >= 0) {
        ty1 = (-by + sqrt(py)) / (2 * ay);
        ty2 = (-by - sqrt(py)) / (2 * ay);
    }

    if (ty1 == ty2) {
        return ty1;
    }

    if (fabsf(tx1 - ty1) < 0.0001)
        return tx1;
    else if (fabsf(tx1 - ty2) < 0.0001) {
        return tx1;
    }
    else if (fabsf(tx2 - ty1) < 0.0001) {
        return tx2;
    }
    else if (fabsf(tx2 - ty2) < 0.0001) {
        return tx2;
    }
    return 0;
}
/*
get bezier curve path with just one anchorPoint
*/
+(CGPathRef)Get3dBezierPath:(CGPoint)startPoint endPoint:(CGPoint)endPoint anchorPoint:(CGPoint)anchorPoint
{
    UIBezierPath *path=[UIBezierPath bezierPath];

    [path moveToPoint:startPoint];

    [path addQuadCurveToPoint:endPoint controlPoint:anchorPoint];
    return path.CGPath;
}
/*
add a point on bezier curve
*/
+(void)setupTestpoint:(SKSpriteNode *)background startp:(CGPoint)point color:(UIColor *)color
{
    SKShapeNode *cpoint = [SKShapeNode node];
    UIBezierPath *ppath = [UIBezierPath bezierPathWithRect:CGRectMake(point.x,point.y,10,10)];
    cpoint.fillColor = color;
    cpoint.path = ppath.CGPath;

    [background addChild:cpoint];
}

您可以在项目中使用这些代码进行测试。 非常感谢你!

一天后,我发现sknode不是沿着bezier路径移动的恒定速度。使用此方法。

for (float i = 0; i < 1.0001f; i+=0.10f) {
    CGPoint ps = [ToolObjective get3dPointbezierInterpolation: i startp:point1 controlp:controlP endp:point2];
    [ToolObjective setupTestpoint:background startp:ps color:[UIColor yellowColor]];

}

因此,关键问题是找到一种方法使sknode具有恒定的速度。 我会在这里发布我的解决方案。或者你已经知道了,请告诉我!

0 个答案:

没有答案