Drawing dashed line in Sprite Kit using SKShapeNode and CGPath
Asked Answered
S

2

6

I want to draw a dashed line in my sprite kit game, I can use SKShapeNode node to draw a normal line like the following:

 UIBezierPath *_path=[UIBezierPath bezierPath];
 //1
 CGPoint point1 = CGPointMake(100,100);
 CGPoint point2 = CGPointMake(150,150);
 [_path moveToPoint:point1];
 [_path addLineToPoint:point2];
 //2
 SKShapeNode *line = [SKShapeNode node];
 line.path = _path.CGPath;

I tried to set a dashed pattern to UIBezierPath like this:

// adding this code at location 1 or 2 above but no effect
CGFloat dashes[] = {6, 2};
[_path setLineDash:dashes count:2 phase:0];

but the dashed pattern is not applied.

I also tried to create a dashed copy of CGPath directly from UIBezierpath.CGPath property as:

 CGFloat dashes[] = {6, 2};
 CGPathRef aCGPath= CGPathCreateCopyByDashingPath(_path.CGPath,NULL,0,dashes,2);
line.path = aCGPath;

but also the same.

I really appreciate if someone could explain what is the problem and how can I draw a dashed line between two points by applying dashed cgpath to skshapenode.

Edit: I know for this simple example I could divide the distance between these two points to small fixed distances and moving and drawing dashed line by bezeirpath but consider a free hand path with points came from touches, it is a very complex and inefficient to redraw the path with fixed length points then draw dashes. I wonder if there is a way to apply the dashed pattern to the path and making skshapenode to use it that is my question.

Solecism answered 26/12, 2013 at 3:16 Comment(0)
G
10

If anyone is still interested in a simple answer to this question:

Use CGPathCreateCopyByDashingPath to create a dashed copy of - [UIBezierCurve CGPath]

CGPathRef CGPathCreateCopyByDashingPath(
   CGPathRef path,
   const CGAffineTransform *transform,
   CGFloat phase,
   const CGFloat *lengths,
   size_t count
);

and add it to the SKShapeNode's path property.

Example:

    // creates a dashed pattern
    CGFloat pattern[2];
    pattern[0] = 10.0;
    pattern[1] = 10.0;
    CGPathRef dashed =
    CGPathCreateCopyByDashingPath([bezierPath CGPath],
                                  NULL,
                                  0,
                                  pattern,
                                  2);

    self.myShapeNode.path = dashed;

    CGPathRelease(dashed);

EDIT: For performance, you can add an SKShapeNode to an SKEffectNode and set the shouldRasterize property to YES.

Glycolysis answered 25/6, 2014 at 10:34 Comment(3)
your solution worked great! But I don't understand your performance comment. You're saying add the shapenode to an effectnode, then add the effectnode to the scene? As set the rasterize on the effect node? Could you clarify? Thanks!Bucky
If you use an SKShapeNode as-is it will draw the path every frame. If you use an SKEffectNode as described above it will cache a bitmap version of the path so will render it much more quickly (only useful for a path that you don't expect to change very often).Glycolysis
Hey, thanks for the answer, it was long time, I managed to solve that problem by not using SKShapeNode at all because of performance and weird memory leaks issues. I finally used SKSpriteNode to draw the dashed line (each single dash is an SKSpriteNode), to maintain performance I used single SKTexture of the "Dash Image", and the result was perfect. I will mark your answer as accepted so anyone interested in a solution by using SKShapeNode will find it here.Solecism
C
0

Change the code at location 1 to something like this:

UIBezierPath *_path=[UIBezierPath bezierPath];
CGPoint point1 = CGPointMake(100,100);
CGPoint point2 = CGPointMake(150,150);
CGFloat deltaX = 1;
CGFloat deltaY = 1;
CGPoint tmpPoint = point1;
[_path moveToPoint:point1];
while(tmpPoint.x<point2.x && tmpPoint.y<point2.y){
    tmpPoint.x+=deltaX;
    tmpPoint.y+=deltaY;
    if((tmpPoint.y-point1.y)%2==1){
       [_path addLineToPoint:tmpPoint];
    }else{
      [_path moveToPoint:tmpPoint];
    }
}
// If the line is not a 45 degree straight line
// Please modify the while loop accordingly
[_path addLineToPoint:point2];
Coronagraph answered 27/12, 2013 at 13:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.