Swift: Comment append des points à un CGPath fermé?

J'aimerais faire en sorte que SKSpriteNodes se déplace le long des contours des lettres. J'ai beaucoup de lettres mais voici un exemple:

entrez la description de l'image ici

Je voudrais que le sprite suive la ligne rouge. J'ai trouvé cette réponse qui couvre principalement mon problème: Obtenir le path pour tracer un personnage dans un iOS UIFont

La réponse vient avec ce bon exemple de code de travail:

let font = UIFont(name: "HelveticaNeue", size: 64)! var unichars = [UniChar]("P".utf16) var glyphs = [CGGlyph](count: unichars.count, repeatedValue: 0) let gotGlyphs = CTFontGetGlyphsForCharacters(font, &unichars, &glyphs, unichars.count) if gotGlyphs { let cgpath = CTFontCreatePathForGlyph(font, glyphs[0], nil)! let path = UIBezierPath(CGPath: cgpath) print(path) XCPlaygroundPage.currentPage.captureValue(path, withIdentifier: "glyph \(glyphs[0])") } 

Cependant, je rencontre toujours un problème car mon sprite ne complète pas le path complet autour de la lettre pour toutes les lettres, mais à la place, par exemple, avec "P" s'arrête ici (et a commencé par le bas):

entrez la description de l'image ici

J'ai essayé d'append quelques points au path comme ceci:

 CGPathAddLineToPoint(path, nil, 0, 0) 

mais le résultat ne fonctionne probablement pas parce que le point ajouté est après l'instruction <Close> :

 <UIBezierPath: 0x7889ff70; <MoveTo {25.950001, 55.800003}>, <LineTo {25.950001, 95.100006}>, <LineTo {53.850002, 95.100006}>, <QuadCurveTo {71.625, 90.075005} - {66, 95.100006}>, <QuadCurveTo {77.25, 75.450005} - {77.25, 85.050003}>, <QuadCurveTo {71.625, 60.750004} - {77.25, 65.850006}>, <QuadCurveTo {53.850002, 55.800003} - {66, 55.650002}>, <Close>, <MoveTo {11.700001, 107.10001}>, <LineTo {11.700001, 0}>, <LineTo {25.950001, 0}>, <LineTo {25.950001, 43.800003}>, <LineTo {58.650002, 43.800003}>, <QuadCurveTo {83.175003, 52.050003} - {74.850006, 43.650002}>, <QuadCurveTo {91.5, 75.450005} - {91.5, 60.450001}>, <QuadCurveTo {83.175003, 98.775002} - {91.5, 90.450005}>, <QuadCurveTo {58.650002, 107.10001} - {74.850006, 107.10001}>, <Close>, <LineTo {0, 0}> 

Tout d'abord, vous avez besoin d'une méthode pour récupérer tous les éléments de CGPath .

J'ai traduit cette méthode à Swift (vous findez également un exemple pour l'utiliser).

Comme je peux le voir ici dans votre code, vous devez aussi savoir quels types d'éléments composent votre path, mais CGPathElement fonctionne avec UnsafeMutablePointer<CGPoint> (il peut être difficile), donc vous pouvez modifier ma traduction en créant une fonction avec deux arrays de sortie comme ceci:

 //MARK: - CGPath extensions extension CGPath { func getPathElementsPointsAndTypes() -> ([CGPoint],[CGPathElementType]) { var arrayPoints : [CGPoint]! = [CGPoint]() var arrayTypes : [CGPathElementType]! = [CGPathElementType]() self.forEach { element in switch (element.type) { case CGPathElementType.MoveToPoint: arrayPoints.append(element.points[0]) arrayTypes.append(element.type) case .AddLineToPoint: arrayPoints.append(element.points[0]) arrayTypes.append(element.type) case .AddQuadCurveToPoint: arrayPoints.append(element.points[0]) arrayPoints.append(element.points[1]) arrayTypes.append(element.type) arrayTypes.append(element.type) case .AddCurveToPoint: arrayPoints.append(element.points[0]) arrayPoints.append(element.points[1]) arrayPoints.append(element.points[2]) arrayTypes.append(element.type) arrayTypes.append(element.type) arrayTypes.append(element.type) default: break } } return (arrayPoints,arrayTypes) } } 

Après cela, vous avez un tableau de points et un tableau spéculaire de type qui explique quel type est chaque point dans notre list. Cette fois tous les closePath sont supprimés.

Il est maintenant time de recréer le path ad HOC pour votre situation:

 func createNewPath(path:CGPath) -> UIBezierPath { let (points,types) = path.getPathElementsPointsAndTypes() if points.count <= 1 { return UIBezierPath() // exit } let pathRef = UIBezierPath() var i = 0 while i < points.count { switch (types[i]) { case CGPathElementType.MoveToPoint: pathRef.moveToPoint(CGPointMake(points[i].x,points[i].y)) case .AddLineToPoint: pathRef.addLineToPoint(CGPointMake(points[i].x,points[i].y)) case .AddQuadCurveToPoint: pathRef.addQuadCurveToPoint(CGPointMake(points[i].x,points[i].y), controlPoint: CGPointMake(points[i+1].x,points[i+1].y)) i += 1 case .AddCurveToPoint: pathRef.addCurveToPoint(CGPointMake(points[i].x,points[i].y), controlPoint1: CGPointMake(points[i+1].x,points[i+1].y), controlPoint2: CGPointMake(points[i+2].x,points[i+2].y)) i += 2 default: break } i += 1 } //pathRef.closePath() if you want to add new elements dont uncomment this return pathRef } 

Après avoir lancé cette méthode, votre path sera nettoyé par tout closePath et prêt à append de nouvelles lignes comme vous le souhaitez.