Search code examples
sprite-kitskactioncgpathref

How to followPath: in clockwise direction for rectangular shape path?


I saw this answer on how to use SKAction to follow Circle CGPathRef in clockwise direction.

What about rectangular path? The default one will be in counter-clockwise fashion:

CGPathRef square =     CGPathCreateWithRect(CGRectMake(pathOriginX,pathOriginY,pathWidthX,pathHeightY), NULL);
SKAction *followTrack = [SKAction followPath:square asOffset:NO orientToPath:YES duration:completeOnePathDuration];

Tried changing the end points but the result is the same.


Solution

  • Short Answer: run the action in reverse to follow the path in the opposite direction

        [sprite runAction:[followTrack reversedAction]];
    

    Long Answer: the followPath SKAction follows the direction in which the path was built. If you want your sprite to move along a rectangle path in a clockwise or counter-clockwise direction, then build the path accordingly. Alternatively, you can use the reverseAction method to follow a path in the opposite direction than it was built. Here are examples of both methods.

        BOOL clockwise = YES;
        BOOL reversedActionMethod = NO;
    
        CGRect rect = CGRectMake(CGRectGetWidth(self.frame)/2-50,CGRectGetHeight(self.frame)/2-50, 100, 100);
        SKAction *followTrackCW = [SKAction followPath:[self clockwiseRectanglePathWithRect:rect] asOffset:NO orientToPath:YES duration:5];
        SKAction *followTrackCCW = [SKAction followPath:[self counterClockwiseRectanglePathWithRect:rect] asOffset:NO orientToPath:YES duration:5];
    
        if (!reversedActionMethod) {
            if (clockwise) {
                [sprite runAction:followTrackCW];
            }
            else {
                [sprite runAction:followTrackCCW];
            }
        }
        else {
            if (clockwise) {
                [sprite runAction:[followTrackCCW reversedAction]];
            }
            else {
                [sprite runAction: followTrackCCW];
            }
        }
    

    Build a rectangular-shaped path in clockwise order in scene coordinates (CCW in view coordinates)

    - (CGPathRef) clockwiseRectanglePathWithRect:(CGRect)rect
    {
        CGFloat x = rect.origin.x;
        CGFloat y = rect.origin.y;
        CGFloat width = rect.size.width;
        CGFloat height = rect.size.width;
    
        UIBezierPath* bezierPath = UIBezierPath.bezierPath;
        [bezierPath moveToPoint: CGPointMake(x, y)];
        [bezierPath addLineToPoint: CGPointMake(x, y+height)];
        [bezierPath addLineToPoint: CGPointMake(x+width, y+height)];
        [bezierPath addLineToPoint: CGPointMake(x+width, y)];
        [bezierPath closePath];
        return bezierPath.CGPath;
    }
    

    Use built-in method to construct a rectangular-shaped path in counter-clockwise order in scene coordinates (and CW in view coordinates).

    - (CGPathRef) counterClockwiseRectanglePathWithRect:(CGRect)rect
    {
        UIBezierPath* bezierPath = [UIBezierPath bezierPathWithRect:rect];
        return bezierPath.CGPath;
    }