hello world
hello world

Reputation: 61

Why does UIBezierPath behave like this?

I make a little SpriteKit game where the enemies are following a UIBezierPath. (Is there btw any other way to do this? It seems pretty unproductive)

Anyway my enemy behaves very strange. Here's the code for a simple circle with a diameter of 300:

    enemy.position = CGPointMake(0, 0);

    UIBezierPath* circlePath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(0, 0, 300, 300)];

    CGPathRef pathRef = [cicrlePath CGPath];


    SKAction *followPath = [SKAction followPath:pathRef
                                       asOffset:NO
                                   orientToPath:NO
                                       duration: pathSpeed];




    SKAction *forever = [SKAction repeatActionForever:followPath];


    [enemy runAction:forever];

Now see how I specified the enemies position and the circlePath position at (0,0)?

Somehow it's giving me this result: http://www.gfycat.com/DistinctSnarlingAracari

It's not really making sense since it's way out of place, I think? Or am I missing something?

Oh, and like I mentioned before, how could I do enemy movements for my game the most efficient/productive way? I am currently using PaintCode with UIBeziers, but it's always giving me a strange result. I am really looking forward to your answers..

Upvotes: 0

Views: 502

Answers (2)

0x141E
0x141E

Reputation: 12773

The center of a UIBezier oval path is at (x + width/2, y + height/2). Starting from angle = 0 (right-most point on the oval i.e., (x+width,y+height/2)), ovals are drawn counter-clockwise in scene coordinates. A sprite will, therefore, follow an oval path in a counter-clockwise direction because it moves in the same direction in which the path was drawn.

Here's code that may be useful to you:

This method creates an oval path that is centered at the position (origin) of the specified CGRect.

- (CGPathRef) ovalInRect:(CGRect)rect
{
    CGFloat width = rect.size.width;
    CGFloat height = rect.size.height;
    CGFloat x = rect.origin.x-rect.size.width/2;
    CGFloat y = rect.origin.y-rect.size.height/2;

    return[UIBezierPath bezierPathWithOvalInRect: CGRectMake(x, y, width, height)].CGPath;
}

This method creates an SKAction that moves a node along a circular path. The parameters specifies the center, radius, and direction (YES = clockwise and NO = counter-clockwise) of the path.

- (SKAction *) createCircularPathActionAtLocation:(CGPoint)center
                                       withRadius:(CGFloat)radius
                                  andDirectionCW:(BOOL)directionCW

{
    CGRect rect = CGRectMake(center.x, center.y, radius*2, radius*2);
    CGPathRef ovalPath = [self ovalInRect:rect];
    SKAction *circlePathAction = [SKAction followPath:ovalPath asOffset:NO orientToPath:YES duration:5];
    SKAction *action;

    if (directionCW) {
        // Reverse the action to follow the path in the opposite direction
        action = [SKAction repeatActionForever:[circlePathAction reversedAction]];
    }
    else {
        action = [SKAction repeatActionForever:circlePathAction];
    }
    return action;
}

Side note: If you are using PaintCode 2, you can generalize the code it produces by using variables instead of absolute values.

Upvotes: 1

rob mayoff
rob mayoff

Reputation: 386018

I think you don't understand -[UIBezierPath bezierPathWithOvalInRect:] or maybe CGRectMake. Your 0, 0 is the upper-left corner of the bounding box of the oval, not the center, and 300, 300 is the width and height of that bounding box. If you want the oval to be centered at 0, 0, try this:

UIBezierPath* circlePath = [UIBezierPath bezierPathWithOvalInRect:
    CGRectMake(-150, -150, 300, 300)];

Upvotes: 1

Related Questions