Рисование пунктирной линии в Sprite Kit с использованием SKShapeNode и CGPath

Я хочу нарисовать пунктирную линию в своей игре с набором спрайтов, я могу использовать узел SKShapeNode, чтобы нарисовать обычную линию, как показано ниже:

 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;

Я попытался установить штриховой шаблон для UIBezierPath следующим образом:

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

но пунктирный узор не применяется.

Я также попытался создать пунктирную копию CGPath непосредственно из свойства UIBezierpath.CGPath как:

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

но тоже самое.

Я очень ценю, если кто-то может объяснить, в чем проблема и как я могу нарисовать пунктирную линию между двумя точками, применив пунктирную cgpath к skshapenode.

Редактировать: я знаю, что для этого простого примера я мог бы разделить расстояние между этими двумя точками на небольшие фиксированные расстояния и перемещать и рисовать пунктирную линию с помощью безейрпати, но рассмотрим путь свободной руки с точками, полученными в результате касаний, это очень сложно и неэффективно перерисовывать путь с точками фиксированной длины, затем нарисуйте штрихи. Интересно, есть ли способ применить пунктирный шаблон к пути и заставить skshapenode использовать его, это мой вопрос.


person Androyal    schedule 26.12.2013    source источник


Ответы (2)


Если кому еще интересен простой ответ на этот вопрос:

Используйте CGPathCreateCopyByDashingPath, чтобы создать пунктирную копию - [UIBezierCurve CGPath].

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

и добавьте его в свойство path SKShapeNode.

Пример:

    // 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);

РЕДАКТИРОВАТЬ: для повышения производительности вы можете добавить SKShapeNode к SKEffectNode и установить для свойства shouldRasterize значение YES.

person Pulsar    schedule 25.06.2014
comment
ваше решение сработало отлично! Но я не понимаю вашего комментария к производительности. Вы говорите добавить узел формы к узлу эффекта, а затем добавить узел эффекта к сцене? Как настроить растеризацию на узле эффекта? Не могли бы вы уточнить? Спасибо! - person Thunk; 19.07.2014
comment
Если вы используете SKShapeNode как есть, он будет рисовать путь каждый кадр. Если вы используете SKEffectNode, как описано выше, он будет кэшировать растровую версию пути, поэтому он будет отображаться намного быстрее (полезно только для пути, который вы не ожидаете менять очень часто). - person Pulsar; 19.07.2014
comment
Эй, спасибо за ответ, это было давно, мне удалось решить эту проблему, вообще не используя SKShapeNode из-за проблем с производительностью и странными утечками памяти. Наконец, я использовал SKSpriteNode для рисования пунктирной линии (каждая отдельная черточка является SKSpriteNode), для поддержания производительности я использовал одну SKTexture изображения штриха, и результат был идеальным. Я отмечу ваш ответ как принятый, чтобы любой, кто интересуется решением с помощью SKShapeNode, нашел его здесь. - person Androyal; 09.09.2014

Измените код в ячейке 1 примерно так:

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];
person Mr. Sun Lin    schedule 27.12.2013